use cratestack_core::CratestackError;
use sqlx_core::acquire::Acquire as _;
use crate::error::cratestack_error_from_sqlx;
use crate::sqlx;
use crate::transaction::Tx;
pub(crate) async fn begin_savepoint(
tx: &mut Tx,
) -> Result<sqlx::Transaction<'_, sqlx::Postgres>, CratestackError> {
let outer: &mut sqlx::Transaction<'static, sqlx::Postgres> = tx;
outer.begin().await.map_err(cratestack_error_from_sqlx)
}
pub(crate) async fn finish_savepoint<T>(
savepoint: sqlx::Transaction<'_, sqlx::Postgres>,
result: Result<T, CratestackError>,
) -> Result<T, CratestackError> {
match result {
Ok(value) => {
savepoint
.commit()
.await
.map_err(cratestack_error_from_sqlx)?;
Ok(value)
}
Err(error) => {
let _ = savepoint.rollback().await;
Err(error)
}
}
}
macro_rules! in_bound_savepoint {
($bound:expr, |$sp:ident| $body:expr) => {{
let bound: &$crate::bound::BoundTx = $bound;
let result = match bound.lock() {
Err(error) => Err(error),
Ok(mut guard) => match guard.tx() {
Err(error) => Err(error),
Ok(tx) => match $crate::bound::begin_savepoint(tx).await {
Err(error) => Err(error),
Ok(mut savepoint) => {
let result = {
let $sp = &mut savepoint;
$body.await
};
$crate::bound::finish_savepoint(savepoint, result).await
}
},
},
};
bound.observe(&result);
result
}};
}
macro_rules! in_write_tx {
($runtime:expr, |$tx:ident| $body:expr) => {{
let runtime: &$crate::SqlxRuntime = $runtime;
match runtime.bound() {
Some(bound) => $crate::bound::in_bound_savepoint!(bound, |$tx| $body),
None => {
let mut owned = runtime
.pool()
.begin()
.await
.map_err($crate::cratestack_error_from_sqlx)?;
let result = {
let $tx = &mut owned;
$body.await
};
match result {
Ok(value) => owned
.commit()
.await
.map(|()| value)
.map_err($crate::cratestack_error_from_sqlx),
Err(error) => Err(error),
}
}
}
}};
}
pub(crate) use {in_bound_savepoint, in_write_tx};