use std::sync::Arc;
use sqlx::any::AnyPoolOptions;
pub type DbPool = sqlx::Pool<sqlx::Any>;
pub type DbTransaction<'a> = sqlx::Transaction<'a, sqlx::Any>;
pub type DbResult<T> = Result<T, sqlx::Error>;
fn prepare_db_url(url: Option<&str>) -> String {
let url = url.unwrap_or("sqlite://./agentic_api.db");
if url.starts_with("sqlite") && !url.contains('?') {
format!("{url}?mode=rwc")
} else {
url.to_string()
}
}
pub async fn create_pool(db_url: Option<&str>) -> DbResult<Arc<DbPool>> {
sqlx::any::install_default_drivers();
let url = prepare_db_url(db_url);
let max_connections = if url.starts_with("sqlite") { 1 } else { 10 };
let pool = AnyPoolOptions::new()
.max_connections(max_connections)
.connect(&url)
.await?;
Ok(Arc::new(pool))
}
pub async fn create_pool_with_schema(db_url: Option<&str>) -> DbResult<Arc<DbPool>> {
use crate::storage::PoolWithSchema;
let pool = create_pool(db_url).await?;
let pool_with_schema = PoolWithSchema::new(pool);
pool_with_schema.ensure_schema_ready().await?;
Ok(pool_with_schema.pool().clone())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_prepare_sqlite_url_without_params() {
let url = "sqlite://test.db";
let prepared = prepare_db_url(Some(url));
assert_eq!(prepared, "sqlite://test.db?mode=rwc");
}
#[test]
fn test_prepare_sqlite_url_with_params() {
let url = "sqlite://test.db?cache=shared";
let prepared = prepare_db_url(Some(url));
assert_eq!(prepared, "sqlite://test.db?cache=shared");
}
#[test]
fn test_prepare_postgres_url() {
let url = "postgresql://user:pass@localhost/db";
let prepared = prepare_db_url(Some(url));
assert_eq!(prepared, "postgresql://user:pass@localhost/db");
}
#[test]
fn test_prepare_mysql_url() {
let url = "mysql://user:pass@localhost/db";
let prepared = prepare_db_url(Some(url));
assert_eq!(prepared, "mysql://user:pass@localhost/db");
}
#[test]
fn test_prepare_default_sqlite_url() {
let prepared = prepare_db_url(None);
assert_eq!(prepared, "sqlite://./agentic_api.db?mode=rwc");
}
}