use crate::{AsyncConnection, TransactionManager};
use diesel::QueryResult;
use futures_core::future::BoxFuture;
use futures_util::FutureExt;
use std::borrow::Cow;
use std::fmt;
use std::future::Future;
#[cfg(feature = "bb8")]
pub mod bb8;
#[cfg(feature = "deadpool")]
pub mod deadpool;
#[cfg(feature = "mobc")]
pub mod mobc;
#[derive(Debug)]
pub enum PoolError {
ConnectionError(diesel::result::ConnectionError),
QueryError(diesel::result::Error),
}
impl fmt::Display for PoolError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
PoolError::ConnectionError(ref e) => e.fmt(f),
PoolError::QueryError(ref e) => e.fmt(f),
}
}
}
impl std::error::Error for PoolError {}
pub type SetupCallback<C> =
Box<dyn Fn(&str) -> BoxFuture<diesel::ConnectionResult<C>> + Send + Sync>;
pub type RecycleCheckCallback<C> = dyn Fn(&mut C) -> BoxFuture<QueryResult<()>> + Send + Sync;
#[derive(Default)]
pub enum RecyclingMethod<C> {
Fast,
#[default]
Verified,
CustomQuery(Cow<'static, str>),
CustomFunction(Box<RecycleCheckCallback<C>>),
}
impl<C: fmt::Debug> fmt::Debug for RecyclingMethod<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Fast => write!(f, "Fast"),
Self::Verified => write!(f, "Verified"),
Self::CustomQuery(arg0) => f.debug_tuple("CustomQuery").field(arg0).finish(),
Self::CustomFunction(_) => f.debug_tuple("CustomFunction").finish(),
}
}
}
#[non_exhaustive]
pub struct ManagerConfig<C> {
pub recycling_method: RecyclingMethod<C>,
pub custom_setup: SetupCallback<C>,
}
impl<C> Default for ManagerConfig<C>
where
C: AsyncConnection + 'static,
{
fn default() -> Self {
Self {
recycling_method: Default::default(),
custom_setup: Box::new(|url| C::establish(url).boxed()),
}
}
}
#[allow(dead_code)]
pub struct AsyncDieselConnectionManager<C> {
connection_url: String,
manager_config: ManagerConfig<C>,
}
impl<C> fmt::Debug for AsyncDieselConnectionManager<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"AsyncDieselConnectionManager<{}>",
std::any::type_name::<C>()
)
}
}
impl<C> AsyncDieselConnectionManager<C>
where
C: AsyncConnection + 'static,
{
#[must_use]
pub fn new(connection_url: impl Into<String>) -> Self
where
C: AsyncConnection + 'static,
{
Self::new_with_config(connection_url, Default::default())
}
#[must_use]
pub fn new_with_config(
connection_url: impl Into<String>,
manager_config: ManagerConfig<C>,
) -> Self {
Self {
connection_url: connection_url.into(),
manager_config,
}
}
}
#[doc(hidden)]
pub trait PoolableConnection: AsyncConnection {
fn ping(
&mut self,
config: &RecyclingMethod<Self>,
) -> impl Future<Output = diesel::QueryResult<()>> + Send
where
for<'a> Self: 'a,
diesel::dsl::select<diesel::dsl::AsExprOf<i32, diesel::sql_types::Integer>>:
crate::methods::ExecuteDsl<Self>,
diesel::query_builder::SqlQuery: crate::methods::ExecuteDsl<Self>,
{
use crate::run_query_dsl::RunQueryDsl;
use diesel::IntoSql;
async move {
match config {
RecyclingMethod::Fast => Ok(()),
RecyclingMethod::Verified => {
diesel::select(1_i32.into_sql::<diesel::sql_types::Integer>())
.execute(self)
.await
.map(|_| ())
}
RecyclingMethod::CustomQuery(query) => diesel::sql_query(query.as_ref())
.execute(self)
.await
.map(|_| ()),
RecyclingMethod::CustomFunction(c) => c(self).await,
}
}
}
fn is_broken(&mut self) -> bool {
Self::TransactionManager::is_broken_transaction_manager(self)
}
}