use axum::extract::FromRequestParts;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use sqlx::{Any, Transaction};
use rusty_gasket::db::transaction::RequestTransaction;
pub struct DbTx(pub Transaction<'static, Any>);
impl std::fmt::Debug for DbTx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DbTx").finish_non_exhaustive()
}
}
impl std::ops::Deref for DbTx {
type Target = Transaction<'static, Any>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for DbTx {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl DbTx {
pub async fn commit(self) -> Result<(), sqlx::Error> {
self.0.commit().await
}
}
#[derive(Debug)]
pub struct DbTxNotAvailable;
impl IntoResponse for DbTxNotAvailable {
fn into_response(self) -> Response {
rusty_gasket::error::quick_error_response(
StatusCode::INTERNAL_SERVER_ERROR,
"DATABASE_TRANSACTION_NOT_AVAILABLE",
"Database transaction not available for this request",
)
}
}
impl<S> FromRequestParts<S> for DbTx
where
S: Send + Sync,
{
type Rejection = DbTxNotAvailable;
async fn from_request_parts(
parts: &mut http::request::Parts,
_state: &S,
) -> Result<Self, Self::Rejection> {
let req_tx = parts
.extensions
.get::<RequestTransaction>()
.ok_or(DbTxNotAvailable)?;
let tx = req_tx.take().ok_or(DbTxNotAvailable)?;
Ok(Self(tx))
}
}