Files
zhenyi 821537186e refactor(tests): reformat code and update dependency management
- 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
2026-06-11 12:11:05 +08:00

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");
}
}