use sqlx::{postgres::PgPoolOptions, Executor, Pool, Postgres};
use crate::{Error, Result};
pub type Db = Pool<Postgres>;
pub async fn new_db_pool(db_connect_url: &str, max_connections: u32) -> Result<Db> {
PgPoolOptions::new()
.max_connections(max_connections)
.connect(db_connect_url)
.await
.map_err(|e| Error::FailedToCreateDBPool(e.to_string()))
}
#[derive(Debug, Clone)]
pub struct DbModelManager {
db: Db,
}
impl DbModelManager {
pub async fn new(db_connect_url: &str, max_connections: u32) -> Result<Self> {
let db = new_db_pool(db_connect_url, max_connections).await?;
Ok(DbModelManager { db })
}
pub fn new_from_pool(pool: Db) -> Self {
pool.into()
}
pub async fn check_db_connectivity(&self) -> Result<()> {
sqlx::query("SELECT 1").execute(self.db()).await?;
Ok(())
}
pub async fn begin(&self) -> Result<Transaction<'_>> {
let mut raw = self.db().begin().await?;
raw.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;")
.await?;
Ok(Transaction(raw))
}
pub fn db(&self) -> &Db {
&self.db
}
}
impl From<Db> for DbModelManager {
fn from(db: Db) -> Self {
Self { db }
}
}
pub struct Transaction<'a>(sqlx::Transaction<'a, Postgres>);
impl Transaction<'_> {
pub(crate) fn executor(&mut self) -> impl Executor<'_, Database = Postgres> {
&mut *self.0
}
pub async fn commit(self) -> Result<()> {
Ok(self.0.commit().await?)
}
pub async fn rollback(self) -> Result<()> {
Ok(self.0.rollback().await?)
}
}
pub trait AsExecutor: private::ActualExecutor {
fn is_transaction(&self) -> bool {
false
}
}
pub(crate) mod private {
use sqlx::{Executor, Postgres};
pub trait ActualExecutor {
fn as_executor(&mut self) -> impl Executor<'_, Database = Postgres>;
}
}
impl private::ActualExecutor for Transaction<'_> {
fn as_executor(&mut self) -> impl Executor<'_, Database = Postgres> {
self.executor()
}
}
impl AsExecutor for Transaction<'_> {
fn is_transaction(&self) -> bool {
true
}
}
impl private::ActualExecutor for DbModelManager {
fn as_executor(&mut self) -> impl Executor<'_, Database = Postgres> {
self.db()
}
}
impl AsExecutor for DbModelManager {}