#[cfg(feature = "mongodb")]
pub mod mongo;
#[cfg(feature = "sql")]
use std::time::Duration;
#[cfg(feature = "sql")]
use klauthed_core::config::{DatabaseConfig, PoolConfig};
#[cfg(feature = "sql")]
use sqlx::AnyPool;
#[cfg(feature = "sql")]
use sqlx::any::AnyPoolOptions;
#[cfg(feature = "sql")]
use crate::error::DataError;
#[cfg(feature = "sql")]
pub async fn connect(config: &DatabaseConfig) -> Result<AnyPool, DataError> {
if !config.system.is_relational() {
return Err(DataError::UnsupportedSystem(config.system));
}
sqlx::any::install_default_drivers();
let url = config.connection_url();
tracing::debug!(system = ?config.system, "connecting to relational database");
let pool = pool_options(&config.pool).connect(&url).await?;
Ok(pool)
}
#[cfg(feature = "sql")]
pub async fn connect_verified(config: &DatabaseConfig) -> Result<AnyPool, DataError> {
let pool = connect(config).await?;
ping(&pool).await?;
Ok(pool)
}
#[cfg(feature = "sql")]
pub async fn ping(pool: &AnyPool) -> Result<(), DataError> {
sqlx::query("SELECT 1").execute(pool).await?;
Ok(())
}
#[cfg(feature = "sql")]
pub async fn close(pool: &AnyPool) {
pool.close().await;
}
#[cfg(feature = "sql")]
fn pool_options(pool: &PoolConfig) -> AnyPoolOptions {
let mut options = AnyPoolOptions::new()
.max_connections(pool.max_connections)
.min_connections(pool.min_connections)
.acquire_timeout(Duration::from_secs(pool.acquire_timeout_secs));
if let Some(idle) = pool.idle_timeout_secs {
options = options.idle_timeout(Duration::from_secs(idle));
}
if let Some(lifetime) = pool.max_lifetime_secs {
options = options.max_lifetime(Duration::from_secs(lifetime));
}
options
}
#[cfg(all(test, feature = "sql"))]
mod tests {
use super::*;
use klauthed_core::config::DbSystem;
#[tokio::test]
async fn rejects_non_relational_system() {
let config = DatabaseConfig { system: DbSystem::MongoDb, ..Default::default() };
let err = connect(&config).await.unwrap_err();
assert!(matches!(err, DataError::UnsupportedSystem(DbSystem::MongoDb)));
}
#[cfg(feature = "sqlite")]
#[tokio::test]
async fn connect_verify_ping_close_against_sqlite_memory() {
let config = DatabaseConfig {
system: DbSystem::Sqlite,
url: Some("sqlite::memory:".into()),
..Default::default()
};
let pool = connect_verified(&config).await.expect("connect + ping");
ping(&pool).await.expect("ping again");
close(&pool).await;
}
}