Skip to main content

diesel/connection/
mod.rs

1//! Types related to database connections
2
3pub(crate) mod instrumentation;
4#[cfg(all(
5    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
6    any(feature = "__sqlite-shared", feature = "postgres", feature = "mysql")
7))]
8pub(crate) mod statement_cache;
9#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
10pub mod statement_cache;
11mod transaction_manager;
12
13use crate::backend::Backend;
14use crate::expression::QueryMetadata;
15use crate::query_builder::{Query, QueryFragment, QueryId};
16use crate::result::*;
17use crate::sql_types::TypeMetadata;
18use core::fmt::Debug;
19
20#[cfg(feature = "std")]
21#[doc(inline)]
22pub use self::instrumentation::set_default_instrumentation;
23#[doc(inline)]
24pub use self::instrumentation::{
25    DebugQuery, Instrumentation, InstrumentationEvent, get_default_instrumentation,
26};
27#[doc(inline)]
28pub use self::transaction_manager::{
29    AnsiTransactionManager, InTransactionStatus, TransactionDepthChange, TransactionManager,
30    TransactionManagerStatus, ValidTransactionManagerStatus,
31};
32
33pub use self::private::ConnectionSealed;#[diesel_derives::__diesel_public_if(
34    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
35)]
36pub(crate) use self::private::ConnectionSealed;
37
38#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
39pub use self::private::MultiConnectionHelper;
40
41#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
42pub use self::instrumentation::{DynInstrumentation, StrQueryHelper};
43
44#[cfg(all(
45    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
46    any(feature = "__sqlite-shared", feature = "postgres", feature = "mysql")
47))]
48pub(crate) use self::private::MultiConnectionHelper;
49
50/// Set cache size for a connection
51#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CacheSize {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                CacheSize::Unbounded => "Unbounded",
                CacheSize::Disabled => "Disabled",
            })
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CacheSize {
    #[inline]
    fn clone(&self) -> CacheSize { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CacheSize { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for CacheSize {
    #[inline]
    fn eq(&self, other: &CacheSize) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CacheSize {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {}
}Eq)]
52#[non_exhaustive]
53pub enum CacheSize {
54    /// Caches all queries if possible
55    Unbounded,
56    /// Disable statement cache
57    Disabled,
58}
59
60/// Perform simple operations on a backend.
61///
62/// You should likely use [`Connection`] instead.
63pub trait SimpleConnection {
64    /// Execute multiple SQL statements within the same string.
65    ///
66    /// This function is used to execute migrations,
67    /// which may contain more than one SQL statement.
68    fn batch_execute(&mut self, query: &str) -> QueryResult<()>;
69}
70
71#[doc(hidden)]
72#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
73#[deprecated(note = "Directly use `LoadConnection::Cursor` instead")]
74pub type LoadRowIter<'conn, 'query, C, DB, B = DefaultLoadingMode> =
75    <C as self::private::ConnectionHelperType<DB, B>>::Cursor<'conn, 'query>;
76
77/// A connection to a database
78///
79/// This trait represents a database connection. It can be used to query the database through
80/// the query dsl provided by diesel, custom extensions or raw sql queries.
81///
82/// # Implementing a custom connection
83///
84/// There are several reasons why you would want to implement a custom connection implementation:
85///
86/// * To wrap an existing connection for instrumentation purposes
87/// * To use a different underlying library to provide a connection implementation
88/// for already existing backends.
89/// * To add support for an unsupported database system
90///
91/// Implementing a `Connection` in a third party crate requires
92/// enabling the
93/// `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
94/// crate feature which grants access to some of diesel's implementation details.
95///
96///
97/// ## Wrapping an existing connection impl
98///
99/// Wrapping an existing connection allows you to customize the implementation to
100/// add additional functionality, like for example instrumentation. For this use case
101/// you only need to implement `Connection`, [`LoadConnection`] and all super traits.
102/// You should forward any method call to the wrapped connection type.
103/// It is **important** to also forward any method where diesel provides a
104/// default implementation, as the wrapped connection implementation may
105/// contain a customized implementation.
106///
107/// To allow the integration of your new connection type with other diesel features
108#[cfg_attr(
109    feature = "r2d2",
110    doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
111)]
112#[cfg_attr(
113    not(feature = "r2d2"),
114    doc = "it may be useful to also implement `R2D2Connection`"
115)]
116/// and [`MigrationConnection`](crate::migration::MigrationConnection).
117///
118/// ## Provide a new connection implementation for an existing backend
119///
120/// Implementing a new connection based on an existing backend can enable the usage of
121/// other methods to connect to the database. One example here would be to replace
122/// the official diesel provided connection implementations with an implementation
123/// based on a pure rust connection crate.
124///
125/// **It's important to use prepared statements to implement the following methods:**
126/// * [`LoadConnection::load`]
127/// * [`Connection::execute_returning_count`]
128///
129/// For performance reasons it may also be meaningful to cache already prepared statements.
130#[cfg_attr(
131    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
132    doc = "See [`StatementCache`](self::statement_cache::StatementCache)"
133)]
134#[cfg_attr(
135    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
136    doc = "See `StatementCache`"
137)]
138/// for a helper type to implement prepared statement caching.
139#[cfg_attr(
140    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
141    doc = "The [statement_cache](self::statement_cache)"
142)]
143#[cfg_attr(
144    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
145    doc = "The statement_cache"
146)]
147/// module documentation contains details about efficient prepared statement caching
148/// based on diesels query builder.
149///
150/// It is required to implement at least the following parts:
151///
152/// * A row type that describes how to receive values form a database row.
153///   This type needs to implement [`Row`](crate::row::Row)
154/// * A field type that describes a database field value.
155///   This type needs to implement [`Field`](crate::row::Field)
156/// * A connection type that wraps the connection +
157///   the necessary state management.
158/// * Maybe a [`TransactionManager`] implementation matching
159///  the interface provided by the database connection crate.
160///  Otherwise the implementation used by the corresponding
161///  `Connection` in diesel can be reused.
162///
163/// To allow the integration of your new connection type with other diesel features
164#[cfg_attr(
165    feature = "r2d2",
166    doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
167)]
168#[cfg_attr(
169    not(feature = "r2d2"),
170    doc = "it may be useful to also implement `R2D2Connection`"
171)]
172/// and [`MigrationConnection`](crate::migration::MigrationConnection).
173///
174/// The exact implementation of the `Connection` trait depends on the interface provided
175/// by the connection crate/library. A struct implementing `Connection` should
176#[cfg_attr(
177    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
178    doc = "likely contain a [`StatementCache`](self::statement_cache::StatementCache)"
179)]
180#[cfg_attr(
181    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
182    doc = "likely contain a `StatementCache`"
183)]
184/// to cache prepared statements efficiently.
185///
186/// As implementations differ significantly between the supported backends
187/// we cannot give a one for all description here. Generally it's likely a
188/// good idea to follow the implementation of the corresponding connection
189/// in diesel at a high level to gain some idea how to implement your
190/// custom implementation.
191///
192/// ## Implement support for an unsupported database system
193///
194/// Additionally to anything mentioned in the previous section the following steps are required:
195///
196/// * Implement a custom backend type. See the documentation of [`Backend`] for details
197/// * Implement appropriate [`FromSql`](crate::deserialize::FromSql)/
198/// [`ToSql`](crate::serialize::ToSql) conversions.
199/// At least the following impls should be considered:
200///     * `i16`: `FromSql<SmallInt, YourBackend>`
201///     * `i32`: `FromSql<Integer, YourBackend>`
202///     * `i64`: `FromSql<BigInt, YourBackend>`
203///     * `f32`: `FromSql<Float, YourBackend>`
204///     * `f64`: `FromSql<Double, YourBackend>`
205///     * `bool`: `FromSql<Bool, YourBackend>`
206///     * `String`: `FromSql<Text, YourBackend>`
207///     * `Vec<u8>`: `FromSql<Binary, YourBackend>`
208///     * `i16`: `ToSql<SmallInt, YourBackend>`
209///     * `i32`: `ToSql<Integer, YourBackend>`
210///     * `i64`: `ToSql<BigInt, YourBackend>`
211///     * `f32`: `ToSql<Float, YourBackend>`
212///     * `f64`: `ToSql<Double, YourBackend>`
213///     * `bool`: `ToSql<Bool, YourBackend>`
214///     * `String`: `ToSql<Text, YourBackend>`
215///     * `Vec<u8>`: `ToSql<Binary, YourBackend>`
216/// * Maybe a [`TransactionManager`] implementation matching
217///  the interface provided by the database connection crate.
218///  Otherwise the implementation used by the corresponding
219///  `Connection` in diesel can be reused.
220///
221/// As these implementations will vary depending on the backend being used,
222/// we cannot give concrete examples here. We recommend looking at our existing
223/// implementations to see how you can implement your own connection.
224pub trait Connection: SimpleConnection + Sized + Send
225where
226    // This trait bound is there so that implementing a new connection is
227    // gated behind the `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
228    // feature flag
229    Self: ConnectionSealed,
230{
231    /// The backend this type connects to
232    type Backend: Backend;
233
234    /// The transaction manager implementation used by this connection
235    #[diesel_derives::__diesel_public_if(
236        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
237    )]
238    type TransactionManager: TransactionManager<Self>;
239
240    /// Establishes a new connection to the database
241    ///
242    /// The argument to this method and the method's behavior varies by backend.
243    /// See the documentation for that backend's connection class
244    /// for details about what it accepts and how it behaves.
245    fn establish(database_url: &str) -> ConnectionResult<Self>;
246
247    /// Executes the given function inside of a database transaction
248    ///
249    /// This function executes the provided closure `f` inside a database
250    /// transaction. If there is already an open transaction for the current
251    /// connection savepoints will be used instead. The connection is committed if
252    /// the closure returns `Ok(_)`, it will be rolled back if it returns `Err(_)`.
253    /// For both cases the original result value will be returned from this function.
254    ///
255    /// If the transaction fails to commit due to a `SerializationFailure` or a
256    /// `ReadOnlyTransaction` a rollback will be attempted.
257    /// If the rollback fails, the error will be returned in a
258    /// [`Error::RollbackErrorOnCommit`],
259    /// from which you will be able to extract both the original commit error and
260    /// the rollback error.
261    /// In addition, the connection will be considered broken
262    /// as it contains a uncommitted unabortable open transaction. Any further
263    /// interaction with the transaction system will result in an returned error
264    /// in this case.
265    ///
266    /// If the closure returns an `Err(_)` and the rollback fails the function
267    /// will return that rollback error directly, and the transaction manager will
268    /// be marked as broken as it contains a uncommitted unabortable open transaction.
269    ///
270    /// If a nested transaction fails to release the corresponding savepoint
271    /// the error will be returned directly.
272    ///
273    /// # Example
274    ///
275    /// ```rust
276    /// # include!("../doctest_setup.rs");
277    /// use diesel::result::Error;
278    ///
279    /// # fn main() {
280    /// #     run_test().unwrap();
281    /// # }
282    /// #
283    /// # fn run_test() -> QueryResult<()> {
284    /// #     use schema::users::dsl::*;
285    /// #     let conn = &mut establish_connection();
286    /// conn.transaction::<_, Error, _>(|conn| {
287    ///     diesel::insert_into(users)
288    ///         .values(name.eq("Ruby"))
289    ///         .execute(conn)?;
290    ///
291    ///     let all_names = users.select(name).load::<String>(conn)?;
292    ///     assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
293    ///
294    ///     Ok(())
295    /// })?;
296    ///
297    /// conn.transaction::<(), _, _>(|conn| {
298    ///     diesel::insert_into(users)
299    ///         .values(name.eq("Pascal"))
300    ///         .execute(conn)?;
301    ///
302    ///     let all_names = users.select(name).load::<String>(conn)?;
303    ///     assert_eq!(vec!["Sean", "Tess", "Ruby", "Pascal"], all_names);
304    ///
305    ///     // If we want to roll back the transaction, but don't have an
306    ///     // actual error to return, we can return `RollbackTransaction`.
307    ///     Err(Error::RollbackTransaction)
308    /// });
309    ///
310    /// let all_names = users.select(name).load::<String>(conn)?;
311    /// assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
312    /// #     Ok(())
313    /// # }
314    /// ```
315    fn transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
316    where
317        F: FnOnce(&mut Self) -> Result<T, E>,
318        E: From<Error>,
319    {
320        Self::TransactionManager::transaction(self, f)
321    }
322
323    /// Creates a transaction that will never be committed. This is useful for
324    /// tests. Panics if called while inside of a transaction or
325    /// if called with a connection containing a broken transaction
326    fn begin_test_transaction(&mut self) -> QueryResult<()> {
327        match Self::TransactionManager::transaction_manager_status_mut(self) {
328            TransactionManagerStatus::Valid(valid_status) => {
329                match (&None, &valid_status.transaction_depth()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
}assert_eq!(None, valid_status.transaction_depth())
330            }
331            TransactionManagerStatus::InError => {
    ::core::panicking::panic_fmt(format_args!("Transaction manager in error"));
}panic!("Transaction manager in error"),
332        };
333        Self::TransactionManager::begin_transaction(self)?;
334        // set the test transaction flag
335        // to prevent that this connection gets dropped in connection pools
336        // Tests commonly set the poolsize to 1 and use `begin_test_transaction`
337        // to prevent modifications to the schema
338        Self::TransactionManager::transaction_manager_status_mut(self).set_test_transaction_flag();
339        Ok(())
340    }
341
342    /// Executes the given function inside a transaction, but does not commit
343    /// it. Panics if the given function returns an error.
344    ///
345    /// # Example
346    ///
347    /// ```rust
348    /// # include!("../doctest_setup.rs");
349    /// use diesel::result::Error;
350    ///
351    /// # fn main() {
352    /// #     run_test().unwrap();
353    /// # }
354    /// #
355    /// # fn run_test() -> QueryResult<()> {
356    /// #     use schema::users::dsl::*;
357    /// #     let conn = &mut establish_connection();
358    /// conn.test_transaction::<_, Error, _>(|conn| {
359    ///     diesel::insert_into(users)
360    ///         .values(name.eq("Ruby"))
361    ///         .execute(conn)?;
362    ///
363    ///     let all_names = users.select(name).load::<String>(conn)?;
364    ///     assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
365    ///
366    ///     Ok(())
367    /// });
368    ///
369    /// // Even though we returned `Ok`, the transaction wasn't committed.
370    /// let all_names = users.select(name).load::<String>(conn)?;
371    /// assert_eq!(vec!["Sean", "Tess"], all_names);
372    /// #     Ok(())
373    /// # }
374    /// ```
375    fn test_transaction<T, E, F>(&mut self, f: F) -> T
376    where
377        F: FnOnce(&mut Self) -> Result<T, E>,
378        E: Debug,
379    {
380        let mut user_result = None;
381        let _ = self.transaction::<(), _, _>(|conn| {
382            user_result = Some(f(conn));
383            Err(Error::RollbackTransaction)
384        });
385        user_result
386            .expect("Transaction never executed")
387            .unwrap_or_else(|e| {
    ::core::panicking::panic_fmt(format_args!("Transaction did not succeed: {0:?}",
            e));
}panic!("Transaction did not succeed: {:?}", e))
388    }
389
390    /// Execute a single SQL statements given by a query and return
391    /// number of affected rows
392    #[diesel_derives::__diesel_public_if(
393        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
394    )]
395    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
396    where
397        T: QueryFragment<Self::Backend> + QueryId;
398
399    /// Get access to the current transaction state of this connection
400    ///
401    /// This function should be used from [`TransactionManager`] to access
402    /// internally required state.
403    #[diesel_derives::__diesel_public_if(
404        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
405    )]
406    fn transaction_state(
407        &mut self,
408    ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData;
409
410    /// Get the instrumentation instance stored in this connection
411    #[diesel_derives::__diesel_public_if(
412        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
413    )]
414    fn instrumentation(&mut self) -> &mut dyn Instrumentation;
415
416    /// Set a specific [`Instrumentation`] implementation for this connection
417    fn set_instrumentation(&mut self, instrumentation: impl Instrumentation);
418
419    /// Set the prepared statement cache size to [`CacheSize`] for this connection
420    fn set_prepared_statement_cache_size(&mut self, size: CacheSize);
421}
422
423/// The specific part of a [`Connection`] which actually loads data from the database
424///
425/// This is a separate trait to allow connection implementations to specify
426/// different loading modes via the generic parameter.
427pub trait LoadConnection<B = DefaultLoadingMode>: Connection {
428    /// The cursor type returned by [`LoadConnection::load`]
429    ///
430    /// Users should handle this as opaque type that implements [`Iterator`]
431    type Cursor<'conn, 'query>: Iterator<
432        Item = QueryResult<<Self as LoadConnection<B>>::Row<'conn, 'query>>,
433    >
434    where
435        Self: 'conn;
436
437    /// The row type used as [`Iterator::Item`] for the iterator implementation
438    /// of [`LoadConnection::Cursor`]
439    type Row<'conn, 'query>: crate::row::Row<'conn, Self::Backend>
440    where
441        Self: 'conn;
442
443    /// Executes a given query and returns any requested values
444    ///
445    /// This function executes a given query and returns the
446    /// query result as given by the database. **Normal users
447    /// should not use this function**. Use
448    /// [`QueryDsl::load`](crate::QueryDsl) instead.
449    ///
450    /// This function is useful for people trying to build an alternative
451    /// dsl on top of diesel. It returns an [`impl Iterator<Item = QueryResult<&impl Row<Self::Backend>>`](Iterator).
452    /// This type can be used to iterate over all rows returned by the database.
453    #[diesel_derives::__diesel_public_if(
454        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
455    )]
456    fn load<'conn, 'query, T>(
457        &'conn mut self,
458        source: T,
459    ) -> QueryResult<Self::Cursor<'conn, 'query>>
460    where
461        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
462        Self::Backend: QueryMetadata<T::SqlType>;
463}
464
465/// Describes a connection with an underlying [`crate::sql_types::TypeMetadata::MetadataLookup`]
466#[doc =
" Describes a connection with an underlying [`crate::sql_types::TypeMetadata::MetadataLookup`]"]
pub trait WithMetadataLookup: Connection {
    /// Retrieves the underlying metadata lookup
    fn metadata_lookup(&mut self)
    -> &mut <Self::Backend as TypeMetadata>::MetadataLookup;
}#[diesel_derives::__diesel_public_if(
467    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
468)]
469pub trait WithMetadataLookup: Connection {
470    /// Retrieves the underlying metadata lookup
471    fn metadata_lookup(&mut self) -> &mut <Self::Backend as TypeMetadata>::MetadataLookup;
472}
473
474/// A variant of the [`Connection`](trait.Connection.html) trait that is
475/// usable with dynamic dispatch
476///
477/// If you are looking for a way to use pass database connections
478/// for different database backends around in your application
479/// this trait won't help you much. Normally you should only
480/// need to use this trait if you are interacting with a connection
481/// passed to a [`Migration`](../migration/trait.Migration.html)
482pub trait BoxableConnection<DB: Backend>: SimpleConnection + core::any::Any {
483    /// Maps the current connection to `std::any::Any`
484    #[diesel_derives::__diesel_public_if(
485        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
486    )]
487    fn as_any(&self) -> &dyn core::any::Any;
488
489    #[doc(hidden)]
490    fn as_any_mut(&mut self) -> &mut dyn core::any::Any;
491}
492
493impl<C> BoxableConnection<C::Backend> for C
494where
495    C: Connection + core::any::Any,
496{
497    fn as_any(&self) -> &dyn core::any::Any {
498        self
499    }
500
501    fn as_any_mut(&mut self) -> &mut dyn core::any::Any {
502        self
503    }
504}
505
506/// The default loading mode provided by a [`Connection`].
507///
508/// Checkout the documentation of concrete connection types for details about
509/// supported loading modes.
510///
511/// All types implementing [`Connection`] should provide at least
512/// a single [`LoadConnection<DefaultLoadingMode>`](self::LoadConnection)
513/// implementation.
514#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DefaultLoadingMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "DefaultLoadingMode")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for DefaultLoadingMode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DefaultLoadingMode {
    #[inline]
    fn clone(&self) -> DefaultLoadingMode { *self }
}Clone)]
515pub struct DefaultLoadingMode;
516
517impl<DB: Backend + 'static> dyn BoxableConnection<DB> {
518    /// Downcast the current connection to a specific connection
519    /// type.
520    ///
521    /// This will return `None` if the underlying
522    /// connection does not match the corresponding
523    /// type, otherwise a reference to the underlying connection is returned
524    pub fn downcast_ref<T>(&self) -> Option<&T>
525    where
526        T: Connection<Backend = DB> + 'static,
527    {
528        self.as_any().downcast_ref::<T>()
529    }
530
531    /// Downcast the current connection to a specific mutable connection
532    /// type.
533    ///
534    /// This will return `None` if the underlying
535    /// connection does not match the corresponding
536    /// type, otherwise a mutable reference to the underlying connection is returned
537    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
538    where
539        T: Connection<Backend = DB> + 'static,
540    {
541        self.as_any_mut().downcast_mut::<T>()
542    }
543
544    /// Check if the current connection is
545    /// a specific connection type
546    pub fn is<T>(&self) -> bool
547    where
548        T: Connection<Backend = DB> + 'static,
549    {
550        self.as_any().is::<T>()
551    }
552}
553
554// These traits are considered private for different reasons:
555//
556// `ConnectionSealed` to control who can implement `Connection`,
557// so that we can later change the `Connection` trait
558//
559// `MultiConnectionHelper` is a workaround needed for the
560// `MultiConnection` derive. We might stabilize this trait with
561// the corresponding derive
562//
563// `ConnectionHelperType` as a workaround for the `LoadRowIter`
564// type def. That trait should not be used by any user outside of diesel,
565// it purely exists for backward compatibility reasons.
566pub(crate) mod private {
567
568    /// This trait restricts who can implement `Connection`
569    #[cfg_attr(
570        diesel_docsrs,
571        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
572    )]
573    pub trait ConnectionSealed {}
574
575    /// This trait provides helper methods to convert a database lookup type
576    /// to/from an `std::any::Any` reference. This is used internally by the `#[derive(MultiConnection)]`
577    /// implementation
578    #[cfg_attr(
579        diesel_docsrs,
580        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
581    )]
582    pub trait MultiConnectionHelper: super::Connection {
583        /// Convert the lookup type to any
584        fn to_any<'a>(
585            lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
586        ) -> &mut (dyn core::any::Any + 'a);
587
588        /// Get the lookup type from any
589        fn from_any(
590            lookup: &mut dyn core::any::Any,
591        ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup>;
592    }
593
594    // These impls are only there for backward compatibility reasons
595    // Remove them on the next breaking release
596    #[allow(unreachable_pub)] // must be pub for the type def using this trait
597    #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
598    pub trait ConnectionHelperType<DB, B>: super::LoadConnection<B, Backend = DB> {
599        type Cursor<'conn, 'query>
600        where
601            Self: 'conn;
602    }
603    #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
604    impl<T, B> ConnectionHelperType<T::Backend, B> for T
605    where
606        T: super::LoadConnection<B>,
607    {
608        type Cursor<'conn, 'query>
609            = <T as super::LoadConnection<B>>::Cursor<'conn, 'query>
610        where
611            T: 'conn;
612    }
613}