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