#![deny(missing_docs, clippy::unwrap_used)]
#![warn(clippy::impl_trait_in_params)]
use axum_core::response::{IntoResponse, Response};
use http::StatusCode;
use thiserror::Error;
#[cfg(feature = "bb8")]
use bb8_postgres::{
PostgresConnectionManager,
bb8::{PooledConnection, RunError},
tokio_postgres::{self, NoTls, Transaction},
};
#[cfg(feature = "deadpool")]
use deadpool_postgres::tokio_postgres::{self, Transaction};
mod extension;
pub mod layer;
pub mod pool;
pub mod tx;
#[cfg(feature = "bb8")]
type Pool = bb8_postgres::bb8::Pool<PostgresConnectionManager<NoTls>>;
#[cfg(feature = "deadpool")]
type Pool = deadpool_postgres::Pool;
#[derive(Debug, Error)]
pub enum Error {
#[cfg(feature = "bb8")]
#[error(transparent)]
Pool(#[from] RunError<tokio_postgres::Error>),
#[cfg(feature = "deadpool")]
#[error(transparent)]
Pool(#[from] deadpool::managed::PoolError<deadpool_postgres::tokio_postgres::Error>),
#[error(transparent)]
Db(#[from] tokio_postgres::Error),
#[error("required extension not registered")]
MissingExtension,
#[error("Tx extractor used multiple times in the same handler/middleware")]
OverlappingExtractors,
}
impl IntoResponse for Error {
fn into_response(self) -> Response {
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
}
}
struct OwnedTx {
tx: Transaction<'static>,
#[cfg(feature = "bb8")]
_conn: Box<PooledConnection<'static, PostgresConnectionManager<NoTls>>>,
#[cfg(feature = "deadpool")]
_conn: Box<deadpool_postgres::Object>,
}
impl OwnedTx {
#[cfg(feature = "bb8")]
async fn new(
conn: PooledConnection<'static, PostgresConnectionManager<NoTls>>,
read_only: bool,
) -> Result<OwnedTx, tokio_postgres::Error> {
let mut conn = Box::new(conn);
let tx = conn
.build_transaction()
.read_only(read_only)
.start()
.await?;
let tx = unsafe {
std::mem::transmute::<
tokio_postgres::Transaction<'_>,
tokio_postgres::Transaction<'static>,
>(tx)
};
Ok(OwnedTx { tx, _conn: conn })
}
#[cfg(feature = "deadpool")]
async fn new(
conn: deadpool_postgres::Object,
read_only: bool,
) -> Result<OwnedTx, tokio_postgres::Error> {
use std::ops::DerefMut;
let mut conn = Box::new(conn);
let client: &mut tokio_postgres::Client = conn.deref_mut().deref_mut().deref_mut();
let tx = client
.build_transaction()
.read_only(read_only)
.start()
.await?;
let tx = unsafe {
std::mem::transmute::<
tokio_postgres::Transaction<'_>,
tokio_postgres::Transaction<'static>,
>(tx)
};
Ok(OwnedTx { tx, _conn: conn })
}
}