use sqlx::{PgPool, postgres::PgTransaction};
pub struct Transaction {
inner: Option<PgTransaction<'static>>,
}
impl Transaction {
pub async fn commit(mut self) -> Result<(), sqlx::Error> {
if let Some(tx) = self.inner.take() {
tx.commit().await?;
}
Ok(())
}
pub async fn rollback(mut self) -> Result<(), sqlx::Error> {
if let Some(tx) = self.inner.take() {
tx.rollback().await?;
}
Ok(())
}
pub fn inner_mut(&mut self) -> Option<&mut PgTransaction<'static>> {
self.inner.as_mut()
}
}
impl Drop for Transaction {
fn drop(&mut self) {
if self.inner.is_some() {
tracing::warn!("Transaction dropped without explicit commit/rollback");
}
}
}
pub async fn with_transaction<F, T>(pool: &PgPool, f: F) -> Result<T, sqlx::Error>
where
F: FnOnce(&mut PgTransaction<'_>) -> Result<T, sqlx::Error>,
{
let mut tx = pool.begin().await?;
match f(&mut tx) {
Ok(result) => {
tx.commit().await?;
Ok(result)
}
Err(e) => {
tx.rollback().await?;
Err(e)
}
}
}