use sqlx::{Acquire, Transaction};
use crate::{clock::ClockHandle, db};
use super::{AtomicOperation, hooks};
pub struct SavepointOp<'t> {
tx: Transaction<'t, db::Db>,
clock: ClockHandle,
now: Option<chrono::DateTime<chrono::Utc>>,
staged: hooks::CommitHooks,
parent_hooks: &'t mut Option<hooks::CommitHooks>,
}
impl<'t> SavepointOp<'t> {
pub(super) async fn begin(
tx: &'t mut Transaction<'_, db::Db>,
clock: ClockHandle,
now: Option<chrono::DateTime<chrono::Utc>>,
parent_hooks: &'t mut Option<hooks::CommitHooks>,
) -> Result<Self, sqlx::Error> {
Ok(Self {
tx: tx.begin().await?,
clock,
now,
staged: hooks::CommitHooks::new(),
parent_hooks,
})
}
pub async fn release(self) -> Result<(), sqlx::Error> {
let Self {
tx,
staged,
parent_hooks,
..
} = self;
tx.commit().await?;
parent_hooks
.as_mut()
.expect("no hooks")
.absorb_staged(staged);
Ok(())
}
pub async fn rollback(self) -> Result<(), sqlx::Error> {
self.tx.rollback().await
}
}
impl AtomicOperation for SavepointOp<'_> {
fn maybe_now(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.now
}
fn clock(&self) -> &ClockHandle {
&self.clock
}
fn connection(&mut self) -> &mut db::Connection {
self.tx.connection()
}
fn add_commit_hook<H: hooks::CommitHook>(&mut self, hook: H) -> Result<(), H> {
self.staged.add(hook);
Ok(())
}
fn commit_hook<H: hooks::CommitHook>(&self) -> Option<&H> {
self.staged
.get_last::<H>()
.or_else(|| self.parent_hooks.as_ref()?.get_last::<H>())
}
fn supports_hooks(&self) -> bool {
true
}
}