use std::fmt;
use std::ops::{Deref, DerefMut};
use sqlx::pool::PoolConnection;
use sqlx::{Database, Error, Pool, SqlStr};
use sqlx_core::transaction::TransactionManager;
pub(crate) struct PoolTx<DB: Database> {
conn: PoolConnection<DB>,
open: bool,
}
impl<DB: Database> PoolTx<DB> {
pub(crate) async fn begin(
pool: &Pool<DB>,
statement: Option<&'static str>,
) -> Result<Self, Error> {
Self::open(pool.acquire().await?, statement).await
}
pub(crate) async fn open(
conn: PoolConnection<DB>,
statement: Option<&'static str>,
) -> Result<Self, Error> {
let mut tx = Self { conn, open: true };
DB::TransactionManager::begin(&mut tx.conn, statement.map(SqlStr::from_static)).await?;
Ok(tx)
}
pub(crate) async fn commit(mut self) -> Result<(), Error> {
DB::TransactionManager::commit(&mut self.conn).await?;
self.open = false;
Ok(())
}
pub(crate) async fn rollback(mut self) -> Result<(), Error> {
DB::TransactionManager::rollback(&mut self.conn).await?;
self.open = false;
Ok(())
}
}
impl<DB: Database> Deref for PoolTx<DB> {
type Target = DB::Connection;
fn deref(&self) -> &Self::Target {
&self.conn
}
}
impl<DB: Database> DerefMut for PoolTx<DB> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.conn
}
}
impl<DB: Database> Drop for PoolTx<DB> {
fn drop(&mut self) {
if self.open {
self.conn.close_on_drop();
}
}
}
impl<DB: Database> fmt::Debug for PoolTx<DB> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PoolTx")
.field("open", &self.open)
.finish_non_exhaustive()
}
}