821537186e
- Reorganized import statements in adapter tests for better readability - Replaced or_insert_with(Vec::new) with or_default() in test closures - Updated Cargo.lock with new dependency versions and checksums - Added TLS features to tonic dependency configuration - Included sqlx, chrono, and uuid dependencies with specific features - Added jsonwebtoken and arc-swap as project dependencies - Reformatted assertion statements to comply with line length limits - Adjusted base64 import order in engine codec module - Updated protobuf include statement formatting
76 lines
2.2 KiB
Rust
76 lines
2.2 KiB
Rust
//! PostgreSQL connection pool wrapper.
|
|
//!
|
|
//! Provides [`Database`] — a thin, cloneable wrapper around `sqlx::PgPool`
|
|
//! with health-check and graceful shutdown.
|
|
|
|
use std::time::Duration;
|
|
|
|
use sqlx::Row;
|
|
use sqlx::postgres::{PgPool, PgPoolOptions};
|
|
|
|
use crate::ImksResult;
|
|
|
|
use super::config::DatabaseConfig;
|
|
|
|
/// Cloneable handle to the PostgreSQL connection pool.
|
|
///
|
|
/// All query execution goes through `pool()` which returns a `&PgPool`.
|
|
#[derive(Clone)]
|
|
pub struct Database {
|
|
pool: PgPool,
|
|
}
|
|
|
|
impl Database {
|
|
/// Create a new pool from config and verify connectivity with a ping.
|
|
pub async fn connect(config: &DatabaseConfig) -> ImksResult<Self> {
|
|
let pool = PgPoolOptions::new()
|
|
.max_connections(config.max_connections)
|
|
.min_connections(config.min_connections)
|
|
.acquire_timeout(Duration::from_secs(config.connect_timeout_secs))
|
|
.idle_timeout(Duration::from_secs(config.idle_timeout_secs))
|
|
.connect(&config.url)
|
|
.await?;
|
|
|
|
tracing::info!(
|
|
max_connections = config.max_connections,
|
|
min_connections = config.min_connections,
|
|
"PostgreSQL pool created"
|
|
);
|
|
|
|
let db = Self { pool };
|
|
db.health_check().await?;
|
|
Ok(db)
|
|
}
|
|
|
|
/// Wrap an existing `PgPool` (useful for tests with shared pools).
|
|
pub fn from_pool(pool: PgPool) -> Self {
|
|
Self { pool }
|
|
}
|
|
|
|
/// Access the inner `PgPool` for query execution.
|
|
pub fn pool(&self) -> &PgPool {
|
|
&self.pool
|
|
}
|
|
|
|
/// Verify the database is reachable by executing `SELECT 1`.
|
|
pub async fn health_check(&self) -> ImksResult<()> {
|
|
let row = sqlx::query("SELECT 1 AS alive")
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
let alive: i32 = row.get("alive");
|
|
if alive != 1 {
|
|
return Err(crate::ImksError::Internal(
|
|
"Database health check returned unexpected value".into(),
|
|
));
|
|
}
|
|
tracing::debug!("Database health check passed");
|
|
Ok(())
|
|
}
|
|
|
|
/// Gracefully close all connections in the pool.
|
|
pub async fn close(&self) {
|
|
self.pool.close().await;
|
|
tracing::info!("Database pool closed");
|
|
}
|
|
}
|