oxedyne/fe2o3/fe2o3_text/tests/annealer_corpus/diesel_connection.rs
24.1 KiB, 1 run
created by r1870400018:11724, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Types related to database connections |
| 2 | |
| 3 | pub(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 | ))] |
| 8 | pub(crate) mod statement_cache; |
| 9 | #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")] |
| 10 | pub mod statement_cache; |
| 11 | mod transaction_manager; |
| 12 | |
| 13 | use crate::backend::Backend; |
| 14 | use crate::expression::QueryMetadata; |
| 15 | use crate::query_builder::{Query, QueryFragment, QueryId}; |
| 16 | use crate::result::*; |
| 17 | use crate::sql_types::TypeMetadata; |
| 18 | use core::fmt::Debug; |
| 19 | |
| 20 | #[cfg(feature = "std")] |
| 21 | #[doc(inline)] |
| 22 | pub use self::instrumentation::set_default_instrumentation; |
| 23 | #[doc(inline)] |
| 24 | pub use self::instrumentation::{ |
| 25 | DebugQuery, Instrumentation, InstrumentationEvent, get_default_instrumentation, |
| 26 | }; |
| 27 | #[doc(inline)] |
| 28 | pub use self::transaction_manager::{ |
| 29 | AnsiTransactionManager, InTransactionStatus, TransactionDepthChange, TransactionManager, |
| 30 | TransactionManagerStatus, ValidTransactionManagerStatus, |
| 31 | }; |
| 32 | |
| 33 | #[diesel_derives::__diesel_public_if( |
| 34 | feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" |
| 35 | )] |
| 36 | pub(crate) use self::private::ConnectionSealed; |
| 37 | |
| 38 | #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")] |
| 39 | pub use self::private::MultiConnectionHelper; |
| 40 | |
| 41 | #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")] |
| 42 | pub 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 | ))] |
| 48 | pub(crate) use self::private::MultiConnectionHelper; |
| 49 | |
| 50 | /// Set cache size for a connection |
| 51 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 52 | #[non_exhaustive] |
| 53 | pub 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. |
| 63 | pub 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")] |
| 74 | pub 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. |
| 224 | pub trait Connection: SimpleConnection + Sized + Send |
| 225 | where |
| 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 | assert_eq!(None, valid_status.transaction_depth()) |
| 330 | } |
| 331 | TransactionManagerStatus::InError => 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| 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. |
| 427 | pub 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 | #[diesel_derives::__diesel_public_if( |
| 467 | feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" |
| 468 | )] |
| 469 | pub 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) |
| 482 | pub 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 | |
| 493 | impl<C> BoxableConnection<C::Backend> for C |
| 494 | where |
| 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(Debug, Copy, Clone)] |
| 515 | pub struct DefaultLoadingMode; |
| 516 | |
| 517 | impl<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. |
| 566 | pub(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 | } |