Skip to main content

diesel/connection/
mod.rs

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