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
41#[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(Debug, Clone, Copy, PartialEq, 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 assert_eq!(None, valid_status.transaction_depth())
348 }
349 TransactionManagerStatus::InError => 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| 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#[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(Debug, Copy, 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}