pub(crate) mod instrumentation;
#[cfg(all(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
any(feature = "sqlite", feature = "postgres", feature = "mysql")
))]
pub(crate) mod statement_cache;
#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
pub mod statement_cache;
mod transaction_manager;
use crate::backend::Backend;
use crate::expression::QueryMetadata;
use crate::query_builder::{Query, QueryFragment, QueryId};
use crate::result::*;
use crate::sql_types::TypeMetadata;
use std::fmt::Debug;
#[doc(inline)]
pub use self::instrumentation::{
get_default_instrumentation, set_default_instrumentation, DebugQuery, Instrumentation,
InstrumentationEvent,
};
#[doc(inline)]
pub use self::transaction_manager::{
AnsiTransactionManager, InTransactionStatus, TransactionDepthChange, TransactionManager,
TransactionManagerStatus, ValidTransactionManagerStatus,
};
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub(crate) use self::private::ConnectionSealed;
#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
pub use self::private::MultiConnectionHelper;
#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
pub use self::instrumentation::{DynInstrumentation, StrQueryHelper};
#[cfg(all(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
any(feature = "sqlite", feature = "postgres", feature = "mysql")
))]
pub(crate) use self::private::MultiConnectionHelper;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum CacheSize {
Unbounded,
Disabled,
}
pub trait SimpleConnection {
fn batch_execute(&mut self, query: &str) -> QueryResult<()>;
}
#[doc(hidden)]
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
#[deprecated(note = "Directly use `LoadConnection::Cursor` instead")]
pub type LoadRowIter<'conn, 'query, C, DB, B = DefaultLoadingMode> =
<C as self::private::ConnectionHelperType<DB, B>>::Cursor<'conn, 'query>;
#[cfg_attr(
feature = "r2d2",
doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
)]
#[cfg_attr(
not(feature = "r2d2"),
doc = "it may be useful to also implement `R2D2Connection`"
)]
#[cfg_attr(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
doc = "See [`StatementCache`](self::statement_cache::StatementCache)"
)]
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
doc = "See `StatementCache`"
)]
#[cfg_attr(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
doc = "The [statement_cache](self::statement_cache)"
)]
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
doc = "The statement_cache"
)]
#[cfg_attr(
feature = "r2d2",
doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
)]
#[cfg_attr(
not(feature = "r2d2"),
doc = "it may be useful to also implement `R2D2Connection`"
)]
#[cfg_attr(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
doc = "likely contain a [`StatementCache`](self::statement_cache::StatementCache)"
)]
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
doc = "likely contain a `StatementCache`"
)]
pub trait Connection: SimpleConnection + Sized + Send
where
Self: ConnectionSealed,
{
type Backend: Backend;
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
type TransactionManager: TransactionManager<Self>;
fn establish(database_url: &str) -> ConnectionResult<Self>;
fn transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
where
F: FnOnce(&mut Self) -> Result<T, E>,
E: From<Error>,
{
Self::TransactionManager::transaction(self, f)
}
fn begin_test_transaction(&mut self) -> QueryResult<()> {
match Self::TransactionManager::transaction_manager_status_mut(self) {
TransactionManagerStatus::Valid(valid_status) => {
assert_eq!(None, valid_status.transaction_depth())
}
TransactionManagerStatus::InError => panic!("Transaction manager in error"),
};
Self::TransactionManager::begin_transaction(self)?;
Self::TransactionManager::transaction_manager_status_mut(self).set_test_transaction_flag();
Ok(())
}
fn test_transaction<T, E, F>(&mut self, f: F) -> T
where
F: FnOnce(&mut Self) -> Result<T, E>,
E: Debug,
{
let mut user_result = None;
let _ = self.transaction::<(), _, _>(|conn| {
user_result = Some(f(conn));
Err(Error::RollbackTransaction)
});
user_result
.expect("Transaction never executed")
.unwrap_or_else(|e| panic!("Transaction did not succeed: {:?}", e))
}
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
where
T: QueryFragment<Self::Backend> + QueryId;
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn transaction_state(
&mut self,
) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData;
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn instrumentation(&mut self) -> &mut dyn Instrumentation;
fn set_instrumentation(&mut self, instrumentation: impl Instrumentation);
fn set_prepared_statement_cache_size(&mut self, size: CacheSize);
}
pub trait LoadConnection<B = DefaultLoadingMode>: Connection {
type Cursor<'conn, 'query>: Iterator<
Item = QueryResult<<Self as LoadConnection<B>>::Row<'conn, 'query>>,
>
where
Self: 'conn;
type Row<'conn, 'query>: crate::row::Row<'conn, Self::Backend>
where
Self: 'conn;
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn load<'conn, 'query, T>(
&'conn mut self,
source: T,
) -> QueryResult<Self::Cursor<'conn, 'query>>
where
T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
Self::Backend: QueryMetadata<T::SqlType>;
}
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub trait WithMetadataLookup: Connection {
fn metadata_lookup(&mut self) -> &mut <Self::Backend as TypeMetadata>::MetadataLookup;
}
pub trait BoxableConnection<DB: Backend>: SimpleConnection + std::any::Any {
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn as_any(&self) -> &dyn std::any::Any;
#[doc(hidden)]
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
}
impl<C> BoxableConnection<C::Backend> for C
where
C: Connection + std::any::Any,
{
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
#[derive(Debug, Copy, Clone)]
pub struct DefaultLoadingMode;
impl<DB: Backend + 'static> dyn BoxableConnection<DB> {
pub fn downcast_ref<T>(&self) -> Option<&T>
where
T: Connection<Backend = DB> + 'static,
{
self.as_any().downcast_ref::<T>()
}
pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
where
T: Connection<Backend = DB> + 'static,
{
self.as_any_mut().downcast_mut::<T>()
}
pub fn is<T>(&self) -> bool
where
T: Connection<Backend = DB> + 'static,
{
self.as_any().is::<T>()
}
}
pub(crate) mod private {
#[cfg_attr(
docsrs,
doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
)]
pub trait ConnectionSealed {}
#[cfg_attr(
docsrs,
doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
)]
pub trait MultiConnectionHelper: super::Connection {
fn to_any<'a>(
lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
) -> &mut (dyn std::any::Any + 'a);
fn from_any(
lookup: &mut dyn std::any::Any,
) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup>;
}
#[allow(unreachable_pub)] #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
pub trait ConnectionHelperType<DB, B>: super::LoadConnection<B, Backend = DB> {
type Cursor<'conn, 'query>
where
Self: 'conn;
}
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
impl<T, B> ConnectionHelperType<T::Backend, B> for T
where
T: super::LoadConnection<B>,
{
type Cursor<'conn, 'query>
= <T as super::LoadConnection<B>>::Cursor<'conn, 'query>
where
T: 'conn;
}
}