use crate::db::Tx;
use crate::result::{AppError, Result};
use log::debug;
use server_env_config::db::DbConfig;
use server_env_config::Config;
use sqlx::postgres::{PgConnection, PgPoolOptions};
use sqlx::{Connection, PgPool};
#[derive(Debug, Clone)]
pub struct AppState {
pub pool: Option<PgPool>,
pub config: Config,
}
impl AppState {
pub async fn init(config: Config) -> core::result::Result<AppState, String> {
match Self::create_pool(&config.db) {
Ok(pool) => {
debug!("Connection configuration to the database looks good");
Ok(AppState { pool: Some(pool), config })
}
Err(err) => {
Err(format!("Failed to connect to the database: {:?}", err))
}
}
}
pub fn new(config: Config) -> AppState {
AppState {
config,
pool: None,
}
}
pub async fn get_tx(&self) -> Result<Tx<'_>> {
self.pool
.as_ref()
.ok_or_else(|| AppError::StaticValidation("Pool not initialized"))?
.begin()
.await
.map_err(AppError::DB)
}
pub async fn get_conn(&self) -> Result<PgConnection> {
let conn = PgConnection::connect(self.config.db.database_url.as_ref())
.await
.map_err(AppError::DB);
conn
}
pub async fn commit_tx(&self, tx: Tx<'_>) -> Result<()> {
tx.commit().await.map_err(AppError::DB)?;
Ok(())
}
#[allow(dead_code)]
pub async fn rollback_tx(&self, tx: Tx<'_>) -> Result<()> {
tx.rollback().await.map_err(AppError::DB)?;
Ok(())
}
pub fn create_pool(config: &DbConfig) -> Result<PgPool> {
PgPoolOptions::new()
.max_connections(config.max_connections)
.min_connections(config.min_connections)
.acquire_timeout(config.acquire_timeout)
.idle_timeout(config.idle_timeout)
.test_before_acquire(config.test_before_acquire)
.connect_lazy(&config.database_url)
.map_err(AppError::DB)
}
}