use crate::config::AkitaConfig;
use crate::database_err;
use crate::driver::blocking::mssql::SyncMssqlClient;
use crate::driver::DriverType;
use crate::errors::AkitaError;
pub type MssqlConnection = r2d2::PooledConnection<MssqlConnectionManager>;
pub type MssqlPool = r2d2::Pool<MssqlConnectionManager>;
pub struct MssqlConnectionManager {
config: tiberius::Config,
}
impl MssqlConnectionManager {
pub fn new(cfg: &AkitaConfig) -> Result<Self, AkitaError> {
if cfg.get_platform()? != DriverType::Mssql {
return Err(database_err!(
"Database type mismatch: expected SQL Server".to_string()
));
}
let connection_string = cfg.get_connection_string()?;
let config = tiberius::Config::from_ado_string(&connection_string)
.map_err(|e| database_err!(format!("Invalid SQL Server connection string: {}", e)))?;
Ok(Self { config })
}
}
impl r2d2::ManageConnection for MssqlConnectionManager {
type Connection = SyncMssqlClient;
type Error = AkitaError;
fn connect(&self) -> std::result::Result<Self::Connection, Self::Error> {
SyncMssqlClient::connect(self.config.clone())
}
fn is_valid(&self, conn: &mut Self::Connection) -> std::result::Result<(), Self::Error> {
let _result = conn.execute("SELECT 1", &[])?;
Ok(())
}
fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
false
}
}
pub fn init_mssql_pool(cfg: AkitaConfig) -> Result<MssqlPool, AkitaError> {
let manager = MssqlConnectionManager::new(&cfg)?;
let pool = r2d2::Pool::builder()
.connection_timeout(cfg.get_connection_timeout())
.min_idle(cfg.get_min_idle().into())
.max_size(cfg.get_max_size())
.idle_timeout(Some(cfg.get_idle_timeout()))
.max_lifetime(Some(cfg.get_max_lifetime()))
.test_on_check_out(cfg.get_test_on_check_out())
.build(manager)
.map_err(|e| {
database_err!(format!(
"Failed to create SQL Server connection pool: {}",
e
))
})?;
let conn = pool
.get()
.map_err(|e| database_err!(format!("Failed to get connection from pool: {}", e)))?;
conn.query("SELECT 1", &[])
.map_err(|e| database_err!(format!("SQL Server connection test failed: {}", e)))?;
Ok(pool)
}