use crate::{config::DatabaseConfig, error::Result};
use sqlx::{MySql, Pool};
use std::sync::Arc;
use tokio::sync::OnceCell;
pub static DB_POOL: OnceCell<Arc<DbPool>> = OnceCell::const_new();
#[derive(Clone)]
pub struct DbPool {
pool: Pool<MySql>,
}
impl DbPool {
pub async fn new(config: &DatabaseConfig) -> Result<Self> {
let pool = config
.into_pool_options()
.connect(&config.url)
.await
.map_err(|e| crate::error::Error::Pool(e.to_string()))?;
Ok(Self { pool })
}
pub fn pool(&self) -> &Pool<MySql> {
&self.pool
}
pub async fn begin(&self) -> Result<sqlx::Transaction<'_, MySql>> {
self.pool
.begin()
.await
.map_err(|e| crate::error::Error::Transaction(e.to_string()))
}
pub async fn execute(&self, query: &str) -> Result<sqlx::mysql::MySqlQueryResult> {
sqlx::query(query)
.execute(&self.pool)
.await
.map_err(|e| crate::error::Error::Query(e.to_string()))
}
pub fn metrics(&self) -> DbMetrics {
DbMetrics {
connections: 0, idle_connections: 0,
active_connections: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct DbMetrics {
pub connections: u32,
pub idle_connections: u32,
pub active_connections: u32,
}
pub async fn get_pool() -> Arc<DbPool> {
DB_POOL
.get()
.expect("Database pool not initialized")
.clone()
}
pub async fn init(config: DatabaseConfig) -> Result<Arc<DbPool>> {
let pool = DbPool::new(&config).await?;
let pool = Arc::new(pool);
if DB_POOL.set(pool.clone()).is_err() {
return Err(crate::error::Error::Pool(
"Database pool already initialized".to_string(),
));
}
Ok(pool)
}