From cfb95067153ba55dff556c0b580cbc0e47f3fd28 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 6 May 2021 09:47:41 +0200 Subject: [PATCH] Interacting with the database requires a mutable connection This commit changes all connection implementations to take `&mut self` on all methods that interact with the database. This unblocks the following features: * Returnig a cursor/iterator from a `RunQueryDsl` method * Removing some unsafe code and interior mutability inside the current connection implementations * Possibly the first step of a async `Connection` variant to workaround the `Future` not `Send` issues there. --- CHANGELOG.md | 2 + bin/test | 6 +- diesel/Cargo.toml | 2 +- diesel/src/associations/belongs_to.rs | 6 +- diesel/src/associations/mod.rs | 36 +-- diesel/src/connection/mod.rs | 90 +++---- diesel/src/connection/statement_cache.rs | 53 ++-- diesel/src/connection/transaction_manager.rs | 146 ++++++----- diesel/src/deserialize.rs | 20 +- diesel/src/doctest_setup.rs | 10 +- diesel/src/expression/count.rs | 8 +- diesel/src/expression/exists.rs | 6 +- .../expression/functions/aggregate_folding.rs | 10 +- .../functions/aggregate_ordering.rs | 8 +- diesel/src/expression/mod.rs | 36 +-- diesel/src/expression/not.rs | 6 +- diesel/src/expression/operators.rs | 4 +- diesel/src/expression/select_by.rs | 2 +- diesel/src/expression/sql_literal.rs | 34 +-- .../bool_expression_methods.rs | 12 +- .../escape_expression_methods.rs | 8 +- .../global_expression_methods.rs | 64 ++--- .../text_expression_methods.rs | 16 +- diesel/src/insertable.rs | 8 +- diesel/src/lib.rs | 2 +- diesel/src/migration/mod.rs | 20 +- diesel/src/mysql/connection/bind.rs | 77 +++--- diesel/src/mysql/connection/mod.rs | 43 ++-- diesel/src/mysql/types/date_and_time.rs | 59 ++--- diesel/src/mysql/types/mod.rs | 8 +- diesel/src/pg/connection/mod.rs | 128 +++++----- diesel/src/pg/connection/stmt/mod.rs | 10 +- diesel/src/pg/expression/array.rs | 6 +- diesel/src/pg/expression/array_comparison.rs | 8 +- .../src/pg/expression/expression_methods.rs | 200 +++++++++------ .../pg/expression/extensions/interval_dsl.rs | 46 ++-- diesel/src/pg/metadata_lookup.rs | 49 ++-- diesel/src/pg/query_builder/on_constraint.rs | 8 +- diesel/src/pg/transaction.rs | 113 +++++---- diesel/src/pg/types/array.rs | 17 +- diesel/src/pg/types/date_and_time/chrono.rs | 91 ++++--- diesel/src/pg/types/date_and_time/std_time.rs | 25 +- diesel/src/pg/types/mod.rs | 28 +- diesel/src/pg/types/ranges.rs | 31 ++- diesel/src/pg/types/record.rs | 35 +-- diesel/src/query_builder/ast_pass.rs | 10 +- diesel/src/query_builder/bind_collector.rs | 4 +- .../src/query_builder/delete_statement/mod.rs | 16 +- diesel/src/query_builder/functions.rs | 101 ++++---- .../src/query_builder/insert_statement/mod.rs | 18 +- diesel/src/query_builder/mod.rs | 2 +- diesel/src/query_builder/sql_query.rs | 12 +- .../src/query_builder/update_statement/mod.rs | 16 +- diesel/src/query_dsl/belonging_to_dsl.rs | 10 +- diesel/src/query_dsl/combine_dsl.rs | 4 +- diesel/src/query_dsl/join_dsl.rs | 4 +- diesel/src/query_dsl/load_dsl.rs | 8 +- diesel/src/query_dsl/mod.rs | 193 +++++++------- diesel/src/query_dsl/save_changes_dsl.rs | 14 +- diesel/src/r2d2.rs | 76 +++--- diesel/src/serialize.rs | 19 +- diesel/src/sql_types/mod.rs | 2 +- diesel/src/sqlite/connection/functions.rs | 5 +- diesel/src/sqlite/connection/mod.rs | 150 +++++------ .../sqlite/expression/expression_methods.rs | 8 +- .../src/sqlite/types/date_and_time/chrono.rs | 73 +++--- diesel/src/test_helpers.rs | 4 +- diesel/src/type_impls/option.rs | 2 +- diesel/src/type_impls/tuples.rs | 6 +- diesel/src/upsert/on_conflict_extension.rs | 50 ++-- diesel_bench/benches/diesel_benches.rs | 66 ++--- diesel_cli/src/database.rs | 42 +-- .../infer_schema_internals/foreign_keys.rs | 4 +- .../src/infer_schema_internals/inference.rs | 50 ++-- .../information_schema.rs | 54 ++-- .../src/infer_schema_internals/mysql.rs | 2 +- .../src/infer_schema_internals/sqlite.rs | 43 ++-- diesel_cli/src/main.rs | 24 +- diesel_cli/tests/migration_run.rs | 6 +- diesel_cli/tests/support/postgres_database.rs | 6 +- diesel_cli/tests/support/sqlite_database.rs | 2 +- diesel_derives/src/lib.rs | 48 ++-- diesel_derives/src/sql_function.rs | 8 +- diesel_derives/src/sql_type.rs | 10 +- diesel_derives/tests/as_changeset.rs | 106 ++++---- diesel_derives/tests/helpers.rs | 20 +- diesel_derives/tests/insertable.rs | 72 +++--- diesel_derives/tests/queryable.rs | 12 +- diesel_derives/tests/queryable_by_name.rs | 26 +- diesel_derives/tests/selectable.rs | 20 +- .../examples/columns_used_in_where_clause.rs | 8 +- .../examples/querying_basic_schemas.rs | 8 +- .../examples/querying_multiple_types.rs | 8 +- diesel_dynamic_schema/src/dynamic_value.rs | 16 +- diesel_dynamic_schema/src/lib.rs | 8 +- .../tests/connection_setup.rs | 10 +- diesel_dynamic_schema/tests/dynamic_values.rs | 28 +- diesel_dynamic_schema/tests/lib.rs | 24 +- .../migrations_macros/src/lib.rs | 12 +- diesel_migrations/src/embedded_migrations.rs | 4 +- .../src/file_based_migrations.rs | 6 +- diesel_migrations/src/migration_harness.rs | 81 +++--- diesel_tests/Cargo.toml | 2 +- diesel_tests/tests/annotations.rs | 44 ++-- diesel_tests/tests/associations.rs | 76 +++--- diesel_tests/tests/boxed_queries.rs | 82 +++--- diesel_tests/tests/combination.rs | 32 +-- diesel_tests/tests/connection.rs | 25 +- diesel_tests/tests/custom_types.rs | 8 +- diesel_tests/tests/delete.rs | 20 +- diesel_tests/tests/deserialization.rs | 8 +- diesel_tests/tests/distinct.rs | 12 +- diesel_tests/tests/errors.rs | 70 ++--- .../tests/expressions/date_and_time.rs | 118 ++++----- diesel_tests/tests/expressions/mod.rs | 141 +++++----- diesel_tests/tests/expressions/ops.rs | 102 ++++---- diesel_tests/tests/filter.rs | 240 ++++++++++-------- diesel_tests/tests/filter_operators.rs | 78 +++--- diesel_tests/tests/find.rs | 48 ++-- diesel_tests/tests/group_by.rs | 28 +- diesel_tests/tests/having.rs | 20 +- diesel_tests/tests/insert.rs | 172 ++++++------- diesel_tests/tests/insert_from_select.rs | 102 ++++---- diesel_tests/tests/internal_details.rs | 10 +- diesel_tests/tests/joins.rs | 139 +++++----- diesel_tests/tests/limit_offset.rs | 34 +-- diesel_tests/tests/macros.rs | 12 +- diesel_tests/tests/order.rs | 28 +- diesel_tests/tests/raw_sql.rs | 35 +-- diesel_tests/tests/schema/custom_schemas.rs | 6 +- diesel_tests/tests/schema/mod.rs | 49 ++-- diesel_tests/tests/schema_inference.rs | 51 ++-- diesel_tests/tests/select.rs | 122 ++++----- diesel_tests/tests/select_by.rs | 56 ++-- diesel_tests/tests/serialize_as.rs | 6 +- diesel_tests/tests/transactions.rs | 116 +++++---- diesel_tests/tests/types.rs | 57 +++-- diesel_tests/tests/types_roundtrip.rs | 37 ++- diesel_tests/tests/update.rs | 103 ++++---- examples/mysql/all_about_inserts/src/lib.rs | 24 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../mysql/getting_started_step_2/src/lib.rs | 2 +- .../src/bin/delete_post.rs | 4 +- .../src/bin/publish_post.rs | 6 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../mysql/getting_started_step_3/src/lib.rs | 2 +- .../postgres/advanced-blog-cli/src/auth.rs | 32 +-- .../postgres/advanced-blog-cli/src/main.rs | 36 +-- .../advanced-blog-cli/src/pagination.rs | 2 +- .../advanced-blog-cli/src/test_helpers.rs | 2 +- .../postgres/all_about_inserts/src/lib.rs | 38 +-- .../postgres/all_about_updates/src/lib.rs | 14 +- examples/postgres/custom_types/src/main.rs | 6 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../getting_started_step_2/src/lib.rs | 2 +- .../src/bin/delete_post.rs | 4 +- .../src/bin/publish_post.rs | 4 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../getting_started_step_3/src/lib.rs | 2 +- examples/sqlite/all_about_inserts/src/lib.rs | 24 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../sqlite/getting_started_step_2/src/lib.rs | 2 +- .../src/bin/delete_post.rs | 4 +- .../src/bin/publish_post.rs | 6 +- .../src/bin/show_posts.rs | 4 +- .../src/bin/write_post.rs | 4 +- .../sqlite/getting_started_step_3/src/lib.rs | 2 +- 175 files changed, 2999 insertions(+), 2806 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d4b7b70b6f7..f131e917d8af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -169,6 +169,8 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/ * The `#[table_name]` attribute for derive macros can now refer to any path and is no longer limited to identifiers from the current scope. +* Interacting with a database requires a mutable connection. + ### Fixed * Many types were incorrectly considered non-aggregate when they should not diff --git a/bin/test b/bin/test index e1d4099e19e4..47cd826eaaab 100755 --- a/bin/test +++ b/bin/test @@ -27,7 +27,7 @@ else (cd diesel_derives && cargo test --features "diesel/sqlite" $*) (cd diesel_tests && cargo test --features "sqlite" --no-default-features $*) (cd diesel_dynamic_schema && cargo test --features "sqlite" $*) - (cd diesel_bench && cargo test --features "sqlite" $*) + (cd diesel_bench && cargo bench --features "sqlite" --list $*) (cd diesel_migrations && cargo test --features "postgres diesel/postgres" $*) (cd diesel_migrations/migrations_macros && cargo test --features "diesel/postgres postgres" $*) @@ -35,7 +35,7 @@ else (cd diesel_cli && cargo test --features "postgres" --no-default-features $*) (cd diesel_tests && cargo test --features "postgres" --no-default-features $*) (cd diesel_dynamic_schema && cargo test --features "postgres" $*) - (cd diesel_bench && cargo test --features "postgres" $*) + (cd diesel_bench && cargo bench --features "postgres" --list $*) (cd diesel_migrations && cargo test --features "mysql diesel/mysql" $* -- --test-threads 1) (cd diesel_migrations/migrations_macros && cargo test --features "diesel/mysql mysql" $* -- --test-threads 1) @@ -43,7 +43,7 @@ else (cd diesel_cli && cargo test --features "mysql" --no-default-features $* -- --test-threads 1) (cd diesel_tests && cargo test --features "mysql" --no-default-features $* -- --test-threads 1) (cd diesel_dynamic_schema && cargo test --features "mysql" $* -- --test-threads 1) - (cd diesel_bench && cargo test --features "mysql" $* -- --test-threads 1) + (cd diesel_bench && cargo bench --features "mysql" --list $* -- --test-threads 1) (cd diesel_compile_tests && cargo test $*) (cd diesel_migrations/migrations_internals && cargo test $*) diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index a784b6b80300..c62e052fc6a3 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -44,7 +44,7 @@ ipnetwork = ">=0.12.2, <0.19.0" quickcheck = "0.9" [features] -default = ["with-deprecated", "32-column-tables"] +default = ["with-deprecated", "32-column-tables", "r2d2"] extras = ["chrono", "serde_json", "uuid", "network-address", "numeric", "r2d2"] unstable = ["diesel_derives/nightly"] large-tables = ["32-column-tables"] diff --git a/diesel/src/associations/belongs_to.rs b/diesel/src/associations/belongs_to.rs index d3d5a7cc281a..429cfe7c826f 100644 --- a/diesel/src/associations/belongs_to.rs +++ b/diesel/src/associations/belongs_to.rs @@ -70,10 +70,10 @@ pub trait BelongsTo { /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let connection = establish_connection(); -/// let users = users::table.load::(&connection)?; +/// # let mut connection = establish_connection(); +/// let users = users::table.load::(&mut connection)?; /// let posts = Post::belonging_to(&users) -/// .load::(&connection)? +/// .load::(&mut connection)? /// .grouped_by(&users); /// let data = users.into_iter().zip(posts).collect::>(); /// diff --git a/diesel/src/associations/mod.rs b/diesel/src/associations/mod.rs index f70b16b9b62d..91ca2ee48348 100644 --- a/diesel/src/associations/mod.rs +++ b/diesel/src/associations/mod.rs @@ -29,11 +29,11 @@ //! # } //! # //! # fn run_test() -> QueryResult<()> { -//! # let connection = establish_connection(); +//! # let mut connection = establish_connection(); //! # use self::users::dsl::*; -//! let user = users.find(2).get_result::(&connection)?; +//! let user = users.find(2).get_result::(&mut connection)?; //! let users_post = Post::belonging_to(&user) -//! .first(&connection)?; +//! .first(&mut connection)?; //! let expected = Post { id: 3, user_id: 2, title: "My first post too".into() }; //! assert_eq!(expected, users_post); //! # Ok(()) @@ -115,11 +115,11 @@ //! # //! # fn main() { //! # use self::users::dsl::*; -//! # let connection = establish_connection(); +//! # let mut connection = establish_connection(); //! # -//! let user = users.find(1).first::(&connection).expect("Error loading user"); +//! let user = users.find(1).first::(&mut connection).expect("Error loading user"); //! let post_list = Post::belonging_to(&user) -//! .load::(&connection) +//! .load::(&mut connection) //! .expect("Error loading posts"); //! let expected = vec![ //! Post { id: 1, user_id: 1, title: "My first post".to_string() }, @@ -172,21 +172,21 @@ //! # } //! # //! # fn run_test() -> QueryResult<()> { -//! # let connection = establish_connection(); +//! # let mut connection = establish_connection(); //! # use self::users::dsl::*; //! # use self::posts::dsl::{posts, title}; -//! let sean = users.filter(name.eq("Sean")).first::(&connection)?; -//! let tess = users.filter(name.eq("Tess")).first::(&connection)?; +//! let sean = users.filter(name.eq("Sean")).first::(&mut connection)?; +//! let tess = users.filter(name.eq("Tess")).first::(&mut connection)?; //! //! let seans_posts = Post::belonging_to(&sean) //! .select(title) -//! .load::(&connection)?; +//! .load::(&mut connection)?; //! assert_eq!(vec!["My first post", "About Rust"], seans_posts); //! //! // A vec or slice can be passed as well //! let more_posts = Post::belonging_to(&vec![sean, tess]) //! .select(title) -//! .load::(&connection)?; +//! .load::(&mut connection)?; //! assert_eq!(vec!["My first post", "About Rust", "My first post too"], more_posts); //! # Ok(()) //! # } @@ -226,10 +226,10 @@ //! # } //! # //! # fn run_test() -> QueryResult<()> { -//! # let connection = establish_connection(); -//! let users = users::table.load::(&connection)?; +//! # let mut connection = establish_connection(); +//! let users = users::table.load::(&mut connection)?; //! let posts = Post::belonging_to(&users) -//! .load::(&connection)? +//! .load::(&mut connection)? //! .grouped_by(&users); //! let data = users.into_iter().zip(posts).collect::>(); //! @@ -290,15 +290,15 @@ //! # } //! # //! # fn main() { -//! # let connection = establish_connection(); +//! # let mut connection = establish_connection(); //! # -//! let users: Vec = users::table.load::(&connection) +//! let users: Vec = users::table.load::(&mut connection) //! .expect("error loading users"); //! let posts: Vec = Post::belonging_to(&users) -//! .load::(&connection) +//! .load::(&mut connection) //! .expect("error loading posts"); //! let comments: Vec = Comment::belonging_to(&posts) -//! .load::(&connection) +//! .load::(&mut connection) //! .expect("Error loading comments"); //! let grouped_comments: Vec> = comments.grouped_by(&posts); //! let posts_and_comments: Vec)>> = posts diff --git a/diesel/src/connection/mod.rs b/diesel/src/connection/mod.rs index 9e15a1b60589..b103fe9444bc 100644 --- a/diesel/src/connection/mod.rs +++ b/diesel/src/connection/mod.rs @@ -14,7 +14,9 @@ use crate::result::*; #[doc(hidden)] pub use self::statement_cache::{MaybeCached, StatementCache, StatementCacheKey}; -pub use self::transaction_manager::{AnsiTransactionManager, TransactionManager}; +pub use self::transaction_manager::{ + AnsiTransactionManager, AnsiTransactionManagerData, TransactionManager, +}; /// Perform simple operations on a backend. /// @@ -24,22 +26,25 @@ pub trait SimpleConnection { /// /// This function is used to execute migrations, /// which may contain more than one SQL statement. - fn batch_execute(&self, query: &str) -> QueryResult<()>; + fn batch_execute(&mut self, query: &str) -> QueryResult<()>; } /// A connection to a database -pub trait Connection: SimpleConnection + Send { +pub trait Connection: SimpleConnection + Sized + Send { /// The backend this type connects to type Backend: Backend; + #[doc(hidden)] + type TransactionManager: TransactionManager; + #[doc(hidden)] + type TransactionData; + /// Establishes a new connection to the database /// /// The argument to this method and the method's behavior varies by backend. /// See the documentation for that backend's connection class /// for details about what it accepts and how it behaves. - fn establish(database_url: &str) -> ConnectionResult - where - Self: Sized; + fn establish(database_url: &str) -> ConnectionResult; /// Executes the given function inside of a database transaction /// @@ -69,24 +74,24 @@ pub trait Connection: SimpleConnection + Send { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let conn = establish_connection(); - /// conn.transaction::<_, Error, _>(|| { + /// # let mut conn = establish_connection(); + /// conn.transaction::<_, Error, _>(|conn| { /// diesel::insert_into(users) /// .values(name.eq("Ruby")) - /// .execute(&conn)?; + /// .execute(conn)?; /// - /// let all_names = users.select(name).load::(&conn)?; + /// let all_names = users.select(name).load::(conn)?; /// assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names); /// /// Ok(()) /// })?; /// - /// conn.transaction::<(), _, _>(|| { + /// conn.transaction::<(), _, _>(|conn| { /// diesel::insert_into(users) /// .values(name.eq("Pascal")) - /// .execute(&conn)?; + /// .execute(conn)?; /// - /// let all_names = users.select(name).load::(&conn)?; + /// let all_names = users.select(name).load::(conn)?; /// assert_eq!(vec!["Sean", "Tess", "Ruby", "Pascal"], all_names); /// /// // If we want to roll back the transaction, but don't have an @@ -94,26 +99,24 @@ pub trait Connection: SimpleConnection + Send { /// Err(Error::RollbackTransaction) /// }); /// - /// let all_names = users.select(name).load::(&conn)?; + /// let all_names = users.select(name).load::(&mut conn)?; /// assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names); /// # Ok(()) /// # } /// ``` - fn transaction(&self, f: F) -> Result + fn transaction(&mut self, f: F) -> Result where - Self: Sized, - F: FnOnce() -> Result, + F: FnOnce(&mut Self) -> Result, E: From, { - let transaction_manager = self.transaction_manager(); - transaction_manager.begin_transaction(self)?; - match f() { + Self::TransactionManager::begin_transaction(self)?; + match f(&mut *self) { Ok(value) => { - transaction_manager.commit_transaction(self)?; + Self::TransactionManager::commit_transaction(self)?; Ok(value) } Err(e) => { - transaction_manager.rollback_transaction(self)?; + Self::TransactionManager::rollback_transaction(self)?; Err(e) } } @@ -121,13 +124,9 @@ pub trait Connection: SimpleConnection + Send { /// Creates a transaction that will never be committed. This is useful for /// tests. Panics if called while inside of a transaction. - fn begin_test_transaction(&self) -> QueryResult<()> - where - Self: Sized, - { - let transaction_manager = self.transaction_manager(); - assert_eq!(transaction_manager.get_transaction_depth(), 0); - transaction_manager.begin_transaction(self) + fn begin_test_transaction(&mut self) -> QueryResult<()> { + assert_eq!(Self::TransactionManager::get_transaction_depth(self), 0); + Self::TransactionManager::begin_transaction(self) } /// Executes the given function inside a transaction, but does not commit @@ -145,45 +144,43 @@ pub trait Connection: SimpleConnection + Send { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let conn = establish_connection(); - /// conn.test_transaction::<_, Error, _>(|| { + /// # let mut conn = establish_connection(); + /// conn.test_transaction::<_, Error, _>(|conn| { /// diesel::insert_into(users) /// .values(name.eq("Ruby")) - /// .execute(&conn)?; + /// .execute(conn)?; /// - /// let all_names = users.select(name).load::(&conn)?; + /// let all_names = users.select(name).load::(conn)?; /// assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names); /// /// Ok(()) /// }); /// /// // Even though we returned `Ok`, the transaction wasn't committed. - /// let all_names = users.select(name).load::(&conn)?; + /// let all_names = users.select(name).load::(&mut conn)?; /// assert_eq!(vec!["Sean", "Tess"], all_names); /// # Ok(()) /// # } /// ``` - fn test_transaction(&self, f: F) -> T + fn test_transaction(&mut self, f: F) -> T where - F: FnOnce() -> Result, + F: FnOnce(&mut Self) -> Result, E: Debug, - Self: Sized, { let mut user_result = None; - let _ = self.transaction::<(), _, _>(|| { - user_result = f().ok(); + let _ = self.transaction::<(), _, _>(|conn| { + user_result = f(conn).ok(); Err(Error::RollbackTransaction) }); user_result.expect("Transaction did not succeed") } #[doc(hidden)] - fn execute(&self, query: &str) -> QueryResult; + fn execute(&mut self, query: &str) -> QueryResult; #[doc(hidden)] - fn load(&self, source: T) -> QueryResult> + fn load(&mut self, source: T) -> QueryResult> where - Self: Sized, T: AsQuery, T::Query: QueryFragment + QueryId, T::SqlType: CompatibleType, @@ -191,15 +188,12 @@ pub trait Connection: SimpleConnection + Send { Self::Backend: QueryMetadata; #[doc(hidden)] - fn execute_returning_count(&self, source: &T) -> QueryResult + fn execute_returning_count(&mut self, source: &T) -> QueryResult where - Self: Sized, T: QueryFragment + QueryId; #[doc(hidden)] - fn transaction_manager(&self) -> &dyn TransactionManager - where - Self: Sized; + fn transaction_state(&mut self) -> &mut Self::TransactionData; } /// A variant of the [`Connection`](trait.Connection.html) trait that is @@ -210,7 +204,7 @@ pub trait Connection: SimpleConnection + Send { /// this trait won't help you much. Normally you should only /// need to use this trait if you are interacting with a connection /// passed to a [`Migration`](../migration/trait.Migration.html) -pub trait BoxableConnection: Connection + std::any::Any { +pub trait BoxableConnection: SimpleConnection + std::any::Any { #[doc(hidden)] fn as_any(&self) -> &dyn std::any::Any; } diff --git a/diesel/src/connection/statement_cache.rs b/diesel/src/connection/statement_cache.rs index 218d960e7af4..06323589efe0 100644 --- a/diesel/src/connection/statement_cache.rs +++ b/diesel/src/connection/statement_cache.rs @@ -93,7 +93,6 @@ use std::any::TypeId; use std::borrow::Cow; -use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::hash::Hash; use std::ops::{Deref, DerefMut}; @@ -105,7 +104,7 @@ use crate::result::QueryResult; #[doc(hidden)] #[allow(missing_debug_implementations)] pub struct StatementCache { - pub cache: RefCell, Statement>>, + pub cache: HashMap, Statement>, } #[allow(clippy::len_without_is_empty, clippy::new_without_default)] @@ -118,16 +117,16 @@ where { pub fn new() -> Self { StatementCache { - cache: RefCell::new(HashMap::new()), + cache: HashMap::new(), } } pub fn len(&self) -> usize { - self.cache.borrow().len() + self.cache.len() } pub fn cached_statement( - &self, + &mut self, source: &T, bind_types: &[DB::TypeMetadata], prepare_fn: F, @@ -145,20 +144,19 @@ where return prepare_fn(&sql).map(MaybeCached::CannotCache); } - refmut_map_result(self.cache.borrow_mut(), |cache| { - match cache.entry(cache_key) { - Occupied(entry) => Ok(entry.into_mut()), - Vacant(entry) => { - let statement = { - let sql = entry.key().sql(source)?; - prepare_fn(&sql) - }; + let cached_result = match self.cache.entry(cache_key) { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let statement = { + let sql = entry.key().sql(source)?; + prepare_fn(&sql) + }; - Ok(entry.insert(statement?)) - } + entry.insert(statement?) } - }) - .map(MaybeCached::Cached) + }; + + Ok(MaybeCached::Cached(cached_result)) } } @@ -166,7 +164,7 @@ where #[allow(missing_debug_implementations)] pub enum MaybeCached<'a, T: 'a> { CannotCache(T), - Cached(RefMut<'a, T>), + Cached(&'a mut T), } impl<'a, T> Deref for MaybeCached<'a, T> { @@ -235,22 +233,3 @@ where Ok(query_builder.finish()) } } - -/// Similar to `RefMut::map`, but for functions which return `Result` -/// -/// If we were in Haskell (and if `RefMut` were `Traversable`), this would just be -/// `traverse`. -fn refmut_map_result(mut refmut: RefMut, mapper: F) -> QueryResult> -where - F: FnOnce(&mut T) -> QueryResult<&mut U>, -{ - // We can't just use `RefMut::map` here, since to lift the error out of that - // closure we'd need to return *something*. - // - // Instead we will very briefly convert to a raw pointer to eliminate - // lifetimes from the equation. Ultimately the cast is safe since the input - // and output lifetimes are identical. However, without the raw pointer - // we would have two live mutable references at the same time. - let ptr = mapper(&mut *refmut).map(|x| x as *mut _)?; - Ok(RefMut::map(refmut, |_| unsafe { &mut *ptr })) -} diff --git a/diesel/src/connection/transaction_manager.rs b/diesel/src/connection/transaction_manager.rs index d9d2db2fbef6..bfd4c58543ba 100644 --- a/diesel/src/connection/transaction_manager.rs +++ b/diesel/src/connection/transaction_manager.rs @@ -1,5 +1,5 @@ use crate::backend::UsesAnsiSavepointSyntax; -use crate::connection::{Connection, SimpleConnection}; +use crate::connection::Connection; use crate::result::{DatabaseErrorKind, Error, QueryResult}; /// Manages the internal transaction state for a connection. @@ -12,66 +12,65 @@ pub trait TransactionManager { /// If the transaction depth is greater than 0, /// this should create a savepoint instead. /// This function is expected to increment the transaction depth by 1. - fn begin_transaction(&self, conn: &Conn) -> QueryResult<()>; + fn begin_transaction(conn: &mut Conn) -> QueryResult<()>; /// Rollback the inner-most transaction or savepoint /// /// If the transaction depth is greater than 1, /// this should rollback to the most recent savepoint. /// This function is expected to decrement the transaction depth by 1. - fn rollback_transaction(&self, conn: &Conn) -> QueryResult<()>; + fn rollback_transaction(conn: &mut Conn) -> QueryResult<()>; /// Commit the inner-most transaction or savepoint /// /// If the transaction depth is greater than 1, /// this should release the most recent savepoint. /// This function is expected to decrement the transaction depth by 1. - fn commit_transaction(&self, conn: &Conn) -> QueryResult<()>; + fn commit_transaction(conn: &mut Conn) -> QueryResult<()>; /// Fetch the current transaction depth /// /// Used to ensure that `begin_test_transaction` is not called when already /// inside of a transaction. - fn get_transaction_depth(&self) -> u32; + fn get_transaction_depth(conn: &mut Conn) -> u32; } -use std::cell::Cell; - -/// An implementation of `TransactionManager` which can be used for backends -/// which use ANSI standard syntax for savepoints such as SQLite and PostgreSQL. -#[allow(missing_debug_implementations)] +/// The internal state used by `AnsiTransactionManager` +#[allow(missing_debug_implementations, missing_copy_implementations)] #[derive(Default)] -pub struct AnsiTransactionManager { - transaction_depth: Cell, +pub struct AnsiTransactionManagerData { + transaction_depth: i32, } -impl AnsiTransactionManager { - /// Create a new transaction manager - pub fn new() -> Self { - AnsiTransactionManager::default() - } - - fn change_transaction_depth(&self, by: i32, query: QueryResult<()>) -> QueryResult<()> { +impl AnsiTransactionManagerData { + fn change_transaction_depth(&mut self, by: i32, query: QueryResult<()>) -> QueryResult<()> { if query.is_ok() { - self.transaction_depth - .set(self.transaction_depth.get() + by) + self.transaction_depth += by; } query } +} +/// An implementation of `TransactionManager` which can be used for backends +/// which use ANSI standard syntax for savepoints such as SQLite and PostgreSQL. +#[derive(Debug, Clone, Copy)] +pub struct AnsiTransactionManager; + +impl AnsiTransactionManager { /// Begin a transaction with custom SQL /// /// This is used by connections to implement more complex transaction APIs /// to set things such as isolation levels. /// Returns an error if already inside of a transaction. - pub fn begin_transaction_sql(&self, conn: &Conn, sql: &str) -> QueryResult<()> + pub fn begin_transaction_sql(conn: &mut Conn, sql: &str) -> QueryResult<()> where - Conn: SimpleConnection, + Conn: Connection, { use crate::result::Error::AlreadyInTransaction; - if self.transaction_depth.get() == 0 { - self.change_transaction_depth(1, conn.batch_execute(sql)) + if conn.transaction_state().transaction_depth == 0 { + let r = conn.batch_execute(sql); + conn.transaction_state().change_transaction_depth(1, r) } else { Err(AlreadyInTransaction) } @@ -80,34 +79,30 @@ impl AnsiTransactionManager { impl TransactionManager for AnsiTransactionManager where - Conn: Connection, + Conn: Connection, Conn::Backend: UsesAnsiSavepointSyntax, { - fn begin_transaction(&self, conn: &Conn) -> QueryResult<()> { - let transaction_depth = self.transaction_depth.get(); - self.change_transaction_depth( - 1, - if transaction_depth == 0 { - conn.batch_execute("BEGIN") - } else { - conn.batch_execute(&format!("SAVEPOINT diesel_savepoint_{}", transaction_depth)) - }, - ) + fn begin_transaction(conn: &mut Conn) -> QueryResult<()> { + let transaction_depth = conn.transaction_state().transaction_depth; + let r = if transaction_depth == 0 { + conn.batch_execute("BEGIN") + } else { + conn.batch_execute(&format!("SAVEPOINT diesel_savepoint_{}", transaction_depth)) + }; + conn.transaction_state().change_transaction_depth(1, r) } - fn rollback_transaction(&self, conn: &Conn) -> QueryResult<()> { - let transaction_depth = self.transaction_depth.get(); - self.change_transaction_depth( - -1, - if transaction_depth == 1 { - conn.batch_execute("ROLLBACK") - } else { - conn.batch_execute(&format!( - "ROLLBACK TO SAVEPOINT diesel_savepoint_{}", - transaction_depth - 1 - )) - }, - ) + fn rollback_transaction(conn: &mut Conn) -> QueryResult<()> { + let transaction_depth = conn.transaction_state().transaction_depth; + let r = if transaction_depth == 1 { + conn.batch_execute("ROLLBACK") + } else { + conn.batch_execute(&format!( + "ROLLBACK TO SAVEPOINT diesel_savepoint_{}", + transaction_depth - 1 + )) + }; + conn.transaction_state().change_transaction_depth(-1, r) } /// If the transaction fails to commit due to a `SerializationFailure` or a @@ -115,8 +110,8 @@ where /// the original error will be returned, otherwise the error generated by the rollback /// will be returned. In the second case the connection should be considered broken /// as it contains a uncommitted unabortable open transaction. - fn commit_transaction(&self, conn: &Conn) -> QueryResult<()> { - let transaction_depth = self.transaction_depth.get(); + fn commit_transaction(conn: &mut Conn) -> QueryResult<()> { + let transaction_depth = conn.transaction_state().transaction_depth; if transaction_depth <= 1 { match conn.batch_execute("COMMIT") { // When any of these kinds of error happen on `COMMIT`, it is expected @@ -124,17 +119,22 @@ where // If there are other such errors, it is fine to add them here. e @ Err(Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)) | e @ Err(Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)) => { - self.change_transaction_depth(-1, conn.batch_execute("ROLLBACK"))?; + let r = conn.batch_execute("ROLLBACK"); + conn.transaction_state().change_transaction_depth(-1, r)?; e } - result => self.change_transaction_depth(-1, result), + result => conn + .transaction_state() + .change_transaction_depth(-1, result), } } else { match conn.batch_execute(&format!( "RELEASE SAVEPOINT diesel_savepoint_{}", transaction_depth - 1, )) { - Ok(_) => self.change_transaction_depth(-1, Ok(())), + Ok(_) => conn + .transaction_state() + .change_transaction_depth(-1, Ok(())), // Postgres treats error (like syntax errors, missing tables, …) // as fatal errors and does not accept any new commands till the // transaction is aborted or we've done a rollback @@ -143,13 +143,11 @@ where Err(Error::DatabaseError(DatabaseErrorKind::Unknown, msg)) if msg.message().starts_with("current transaction is aborted") => { - self.change_transaction_depth( - -1, - conn.batch_execute(&format!( - "ROLLBACK TO SAVEPOINT diesel_savepoint_{}", - transaction_depth - 1 - )), - )?; + let r = conn.batch_execute(&format!( + "ROLLBACK TO SAVEPOINT diesel_savepoint_{}", + transaction_depth - 1 + )); + conn.transaction_state().change_transaction_depth(-1, r)?; Err(Error::DatabaseError(DatabaseErrorKind::Unknown, msg)) } Err(e) => panic!("{}", e), @@ -157,8 +155,8 @@ where } } - fn get_transaction_depth(&self) -> u32 { - self.transaction_depth.get() as u32 + fn get_transaction_depth(conn: &mut Conn) -> u32 { + conn.transaction_state().transaction_depth as u32 } } @@ -191,10 +189,10 @@ mod test { } } - let conn = crate::test_helpers::pg_connection_no_transaction(); + let mut conn = crate::test_helpers::pg_connection_no_transaction(); sql_query("DROP TABLE IF EXISTS transaction_depth_is_tracked_properly_on_commit_failure;") - .execute(&conn) + .execute(&mut conn) .unwrap(); sql_query( r#" @@ -204,7 +202,7 @@ mod test { ) "#, ) - .execute(&conn) + .execute(&mut conn) .unwrap(); insert_into(serialization_example::table) @@ -212,7 +210,7 @@ mod test { serialization_example::class.eq(1), serialization_example::class.eq(2), ]) - .execute(&conn) + .execute(&mut conn) .unwrap(); let barrier = Arc::new(Barrier::new(2)); @@ -222,27 +220,27 @@ mod test { thread::spawn(move || { use crate::connection::transaction_manager::AnsiTransactionManager; use crate::connection::transaction_manager::TransactionManager; - let conn = crate::test_helpers::pg_connection_no_transaction(); - assert_eq!(0, >::get_transaction_depth(&conn.transaction_manager)); + let mut conn = crate::test_helpers::pg_connection_no_transaction(); + assert_eq!(0, >::get_transaction_depth(&mut conn)); let result = - conn.build_transaction().serializable().run(|| { - assert_eq!(1, >::get_transaction_depth(&conn.transaction_manager)); + conn.build_transaction().serializable().run(|conn| { + assert_eq!(1, >::get_transaction_depth(conn)); let _ = serialization_example::table .filter(serialization_example::class.eq(i)) .count() - .execute(&conn)?; + .execute(conn)?; barrier.wait(); let other_i = if i == 1 { 2 } else { 1 }; insert_into(serialization_example::table) .values(serialization_example::class.eq(other_i)) - .execute(&conn) + .execute(conn) }); - assert_eq!(0, >::get_transaction_depth(&conn.transaction_manager)); + assert_eq!(0, >::get_transaction_depth(&mut conn)); result }) }) diff --git a/diesel/src/deserialize.rs b/diesel/src/deserialize.rs index 6f3f4965c797..67ec8bf8a511 100644 --- a/diesel/src/deserialize.rs +++ b/diesel/src/deserialize.rs @@ -43,8 +43,8 @@ pub type Result = result::Result>; /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// let first_user = users.first(&connection)?; +/// # let mut connection = establish_connection(); +/// let first_user = users.first(&mut connection)?; /// let expected = User { id: 1, name: "Sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -95,8 +95,8 @@ pub type Result = result::Result>; /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// let first_user = users.first(&connection)?; +/// # let mut connection = establish_connection(); +/// let first_user = users.first(&mut connection)?; /// let expected = User { id: 1, name: "sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -138,8 +138,8 @@ pub type Result = result::Result>; /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// let first_user = users.first(&connection)?; +/// # let mut connection = establish_connection(); +/// let first_user = users.first(&mut connection)?; /// let expected = User { id: 1, name: "sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -188,9 +188,9 @@ pub use diesel_derives::Queryable; /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// let first_user = sql_query("SELECT * FROM users ORDER BY id LIMIT 1") -/// .get_result(&connection)?; +/// .get_result(&mut connection)?; /// let expected = User { id: 1, name: "Sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -239,9 +239,9 @@ pub use diesel_derives::Queryable; /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// let first_user = sql_query("SELECT * FROM users ORDER BY id LIMIT 1") -/// .get_result(&connection)?; +/// .get_result(&mut connection)?; /// let expected = User { id: 1, name: "sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) diff --git a/diesel/src/doctest_setup.rs b/diesel/src/doctest_setup.rs index 9bb04378d184..b8f660c45ebb 100644 --- a/diesel/src/doctest_setup.rs +++ b/diesel/src/doctest_setup.rs @@ -12,7 +12,7 @@ cfg_if::cfg_if! { } fn connection_no_data() -> PgConnection { - let connection = connection_no_transaction(); + let mut connection = connection_no_transaction(); connection.begin_test_transaction().unwrap(); connection.execute("DROP TABLE IF EXISTS users CASCADE").unwrap(); connection.execute("DROP TABLE IF EXISTS animals CASCADE").unwrap(); @@ -25,7 +25,7 @@ cfg_if::cfg_if! { #[allow(dead_code)] fn establish_connection() -> PgConnection { - let connection = connection_no_data(); + let mut connection = connection_no_data(); connection.execute("CREATE TABLE users ( id SERIAL PRIMARY KEY, @@ -81,7 +81,7 @@ cfg_if::cfg_if! { #[allow(dead_code)] fn establish_connection() -> SqliteConnection { - let connection = connection_no_data(); + let mut connection = connection_no_data(); connection.execute("CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -127,7 +127,7 @@ cfg_if::cfg_if! { fn connection_no_data() -> MysqlConnection { let connection_url = database_url_from_env("MYSQL_UNIT_TEST_DATABASE_URL"); - let connection = MysqlConnection::establish(&connection_url).unwrap(); + let mut connection = MysqlConnection::establish(&connection_url).unwrap(); connection.execute("SET FOREIGN_KEY_CHECKS=0;").unwrap(); connection.execute("DROP TABLE IF EXISTS users CASCADE").unwrap(); connection.execute("DROP TABLE IF EXISTS animals CASCADE").unwrap(); @@ -141,7 +141,7 @@ cfg_if::cfg_if! { #[allow(dead_code)] fn establish_connection() -> MysqlConnection { - let connection = connection_no_data(); + let mut connection = connection_no_data(); connection.execute("CREATE TABLE users ( id INTEGER PRIMARY KEY AUTO_INCREMENT, diff --git a/diesel/src/expression/count.rs b/diesel/src/expression/count.rs index f9fd0e078085..b179026a86a8 100644 --- a/diesel/src/expression/count.rs +++ b/diesel/src/expression/count.rs @@ -20,8 +20,8 @@ sql_function! { /// # /// # fn main() { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); - /// assert_eq!(Ok(1), animals.select(count(name)).first(&connection)); + /// # let mut connection = establish_connection(); + /// assert_eq!(Ok(1), animals.select(count(name)).first(&mut connection)); /// # } /// ``` #[aggregate] @@ -46,8 +46,8 @@ sql_function! { /// # /// # fn main() { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// assert_eq!(Ok(2), users.select(count_star()).first(&connection)); +/// # let mut connection = establish_connection(); +/// assert_eq!(Ok(2), users.select(count_star()).first(&mut connection)); /// # } /// ``` pub fn count_star() -> CountStar { diff --git a/diesel/src/expression/exists.rs b/diesel/src/expression/exists.rs index c9c7d12bb5ea..e0a77f0def6a 100644 --- a/diesel/src/expression/exists.rs +++ b/diesel/src/expression/exists.rs @@ -20,11 +20,11 @@ use crate::sql_types::Bool; /// # use schema::users::dsl::*; /// # use diesel::select; /// # use diesel::dsl::exists; -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// let sean_exists = select(exists(users.filter(name.eq("Sean")))) -/// .get_result(&connection); +/// .get_result(&mut connection); /// let jim_exists = select(exists(users.filter(name.eq("Jim")))) -/// .get_result(&connection); +/// .get_result(&mut connection); /// assert_eq!(Ok(true), sean_exists); /// assert_eq!(Ok(false), jim_exists); /// # } diff --git a/diesel/src/expression/functions/aggregate_folding.rs b/diesel/src/expression/functions/aggregate_folding.rs index b544c39f1dd7..bac8e20c7909 100644 --- a/diesel/src/expression/functions/aggregate_folding.rs +++ b/diesel/src/expression/functions/aggregate_folding.rs @@ -13,8 +13,8 @@ sql_function! { /// # /// # fn main() { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); - /// assert_eq!(Ok(Some(12i64)), animals.select(sum(legs)).first(&connection)); + /// # let mut connection = establish_connection(); + /// assert_eq!(Ok(Some(12i64)), animals.select(sum(legs)).first(&mut connection)); /// # } /// ``` #[aggregate] @@ -47,13 +47,13 @@ sql_function! { /// # fn run_test() -> QueryResult<()> { /// # use bigdecimal::BigDecimal; /// # use self::numbers::dsl::*; - /// # let conn = establish_connection(); + /// # let mut conn = establish_connection(); /// # conn.execute("DROP TABLE IF EXISTS numbers")?; /// # conn.execute("CREATE TABLE numbers (number INTEGER)")?; /// diesel::insert_into(numbers) /// .values(&vec![number.eq(1), number.eq(2)]) - /// .execute(&conn)?; - /// let average = numbers.select(avg(number)).get_result(&conn)?; + /// .execute(&mut conn)?; + /// let average = numbers.select(avg(number)).get_result(&mut conn)?; /// let expected = "1.5".parse::().unwrap(); /// assert_eq!(Some(expected), average); /// # Ok(()) diff --git a/diesel/src/expression/functions/aggregate_ordering.rs b/diesel/src/expression/functions/aggregate_ordering.rs index bb2889590a94..b5a91b1d7850 100644 --- a/diesel/src/expression/functions/aggregate_ordering.rs +++ b/diesel/src/expression/functions/aggregate_ordering.rs @@ -25,8 +25,8 @@ sql_function! { /// # /// # fn main() { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); - /// assert_eq!(Ok(Some(8)), animals.select(max(legs)).first(&connection)); + /// # let mut connection = establish_connection(); + /// assert_eq!(Ok(Some(8)), animals.select(max(legs)).first(&mut connection)); /// # } #[aggregate] fn max(expr: ST) -> ST::Ret; @@ -44,8 +44,8 @@ sql_function! { /// # /// # fn main() { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); - /// assert_eq!(Ok(Some(4)), animals.select(min(legs)).first(&connection)); + /// # let mut connection = establish_connection(); + /// assert_eq!(Ok(Some(4)), animals.select(min(legs)).first(&mut connection)); /// # } #[aggregate] fn min(expr: ST) -> ST::Ret; diff --git a/diesel/src/expression/mod.rs b/diesel/src/expression/mod.rs index a10a737a2e5e..050bb0e76511 100644 --- a/diesel/src/expression/mod.rs +++ b/diesel/src/expression/mod.rs @@ -135,7 +135,7 @@ pub mod expression_types { impl TypedExpressionType for ST where ST: SingleValue {} impl QueryMetadata for DB { - fn row_metadata(_: &DB::MetadataLookup, row: &mut Vec>) { + fn row_metadata(_: &mut DB::MetadataLookup, row: &mut Vec>) { row.push(None) } } @@ -158,7 +158,7 @@ pub trait QueryMetadata: Backend { /// The exact return value of this function is considerded to be a /// backend specific implementation detail. You should not rely on those /// values if you not own the corresponding backend - fn row_metadata(lookup: &Self::MetadataLookup, out: &mut Vec>); + fn row_metadata(lookup: &mut Self::MetadataLookup, out: &mut Vec>); } impl QueryMetadata for DB @@ -166,7 +166,7 @@ where DB: Backend + HasSqlType, T: SingleValue, { - fn row_metadata(lookup: &Self::MetadataLookup, out: &mut Vec>) { + fn row_metadata(lookup: &mut Self::MetadataLookup, out: &mut Vec>) { out.push(Some(>::metadata(lookup))) } } @@ -233,10 +233,10 @@ where /// # /// # fn main() { /// use diesel::sql_types::Text; -/// # let conn = establish_connection(); +/// # let mut conn = establish_connection(); /// let names = users::table /// .select("The Amazing ".into_sql::().concat(users::name)) -/// .load(&conn); +/// .load(&mut conn); /// let expected_names = vec![ /// "The Amazing Sean".to_string(), /// "The Amazing Tess".to_string(), @@ -354,8 +354,8 @@ where /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// let first_user = users.select(User::as_select()).first(&connection)?; +/// # let mut connection = establish_connection(); +/// let first_user = users.select(User::as_select()).first(&mut connection)?; /// let expected = User { id: 1, name: "Sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -394,8 +394,8 @@ where /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); -/// let first_user = users.select(User::as_select()).first(&connection)?; +/// # let mut connection = establish_connection(); +/// let first_user = users.select(User::as_select()).first(&mut connection)?; /// let expected = User { id: 1, name: "Sean".into() }; /// assert_eq!(expected, first_user); /// # Ok(()) @@ -644,7 +644,7 @@ use crate::query_builder::{QueryFragment, QueryId}; /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let conn = establish_connection(); +/// # let mut conn = establish_connection(); /// enum Search { /// Id(i32), /// Name(String), @@ -663,12 +663,12 @@ use crate::query_builder::{QueryFragment, QueryId}; /// /// let user_one = users::table /// .filter(find_user(Search::Id(1))) -/// .first(&conn)?; +/// .first(&mut conn)?; /// assert_eq!((1, String::from("Sean")), user_one); /// /// let tess = users::table /// .filter(find_user(Search::Name("Tess".into()))) -/// .first(&conn)?; +/// .first(&mut conn)?; /// assert_eq!((2, String::from("Tess")), tess); /// # Ok(()) /// # } @@ -689,7 +689,7 @@ use crate::query_builder::{QueryFragment, QueryId}; /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let conn = establish_connection(); +/// # let mut conn = establish_connection(); /// enum NameOrConst { /// Name, /// Const(String), @@ -727,22 +727,24 @@ use crate::query_builder::{QueryFragment, QueryId}; /// /// let user_one = users::table /// .select(selection(NameOrConst::Name)) -/// .first::(&conn)?; +/// .first::(&mut conn)?; /// assert_eq!(String::from("Sean"), user_one); /// /// let with_name = users::table /// .group_by(users::name) /// .select(selection(NameOrConst::Const("Jane Doe".into()))) -/// .first::(&conn)?; +/// .first::(&mut conn)?; /// assert_eq!(String::from("Jane Doe"), with_name); /// # Ok(()) /// # } /// ``` /// /// ## More advanced query source +/// /// This example is a bit contrived, but in general, if you want to for example filter based on /// different criteria on a joined table, you can use `InnerJoinQuerySource` and /// `LeftJoinQuerySource` in the QS parameter of `BoxableExpression`. +/// /// ```rust /// # include!("../doctest_setup.rs"); /// # use schema::{users, posts}; @@ -754,7 +756,7 @@ use crate::query_builder::{QueryFragment, QueryId}; /// # } /// # /// # fn run_test() -> QueryResult<()> { -/// # let conn = establish_connection(); +/// # let mut conn = establish_connection(); /// enum UserPostFilter { /// User(i32), /// Post(i32), @@ -778,7 +780,7 @@ use crate::query_builder::{QueryFragment, QueryId}; /// .inner_join(posts::table) /// .filter(filter_user_posts(UserPostFilter::User(2))) /// .select((posts::title, users::name)) -/// .first::<(String, String)>(&conn)?; +/// .first::<(String, String)>(&mut conn)?; /// /// assert_eq!( /// ("My first post too".to_string(), "Tess".to_string()), diff --git a/diesel/src/expression/not.rs b/diesel/src/expression/not.rs index e9fb4003cd59..fa45042f74a0 100644 --- a/diesel/src/expression/not.rs +++ b/diesel/src/expression/not.rs @@ -12,15 +12,15 @@ use crate::sql_types::BoolOrNullableBool; /// # /// # fn main() { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// use diesel::dsl::not; /// /// let users_with_name = users.select(id).filter(name.eq("Sean")); /// let users_not_with_name = users.select(id).filter( /// not(name.eq("Sean"))); /// -/// assert_eq!(Ok(1), users_with_name.first(&connection)); -/// assert_eq!(Ok(2), users_not_with_name.first(&connection)); +/// assert_eq!(Ok(1), users_with_name.first(&mut connection)); +/// assert_eq!(Ok(2), users_not_with_name.first(&mut connection)); /// # } /// ``` pub fn not(expr: T) -> not diff --git a/diesel/src/expression/operators.rs b/diesel/src/expression/operators.rs index f5be3bf158c2..99c4b23b9524 100644 --- a/diesel/src/expression/operators.rs +++ b/diesel/src/expression/operators.rs @@ -192,7 +192,7 @@ macro_rules! __diesel_operator_to_sql { /// # /// # fn main() { /// # use schema::users::dsl::*; -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// diesel::infix_operator!(MyEq, " = "); /// /// use diesel::expression::AsExpression; @@ -208,7 +208,7 @@ macro_rules! __diesel_operator_to_sql { /// /// let users_with_name = users.select(id).filter(my_eq(name, "Sean")); /// -/// assert_eq!(Ok(1), users_with_name.first(&connection)); +/// assert_eq!(Ok(1), users_with_name.first(&mut connection)); /// # } /// ``` #[macro_export] diff --git a/diesel/src/expression/select_by.rs b/diesel/src/expression/select_by.rs index 955bfb1e2ef1..dff302c1cfa3 100644 --- a/diesel/src/expression/select_by.rs +++ b/diesel/src/expression/select_by.rs @@ -66,7 +66,7 @@ where T: Selectable, DB: QueryMetadata>, { - fn row_metadata(lookup: &Self::MetadataLookup, out: &mut Vec>) { + fn row_metadata(lookup: &mut Self::MetadataLookup, out: &mut Vec>) { >::SelectExpression>>>::row_metadata( lookup, out, ) diff --git a/diesel/src/expression/sql_literal.rs b/diesel/src/expression/sql_literal.rs index 514166957a60..8604e38bf7af 100644 --- a/diesel/src/expression/sql_literal.rs +++ b/diesel/src/expression/sql_literal.rs @@ -55,16 +55,16 @@ where /// # use self::users::dsl::*; /// # use diesel::dsl::sql; /// # use diesel::sql_types::{Integer, Text, Bool}; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let seans_id = users /// .select(id) /// .filter(sql::("name = ").bind::("Sean")) - /// .get_result(&connection); + /// .get_result(&mut connection); /// assert_eq!(Ok(1), seans_id); /// /// let tess_id = sql::("SELECT id FROM users WHERE name = ") /// .bind::("Tess") - /// .get_result(&connection); + /// .get_result(&mut connection); /// assert_eq!(Ok(2), tess_id); /// # } /// ``` @@ -85,9 +85,9 @@ where /// # use self::users::dsl::*; /// # use diesel::dsl::sql; /// # use diesel::sql_types::{Integer, Text, Bool}; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # diesel::insert_into(users).values(name.eq("Ryan")) - /// # .execute(&connection).unwrap(); + /// # .execute(&mut connection).unwrap(); /// let query = users /// .select(name) /// .filter( @@ -96,7 +96,7 @@ where /// .sql(" AND name <> ") /// .bind::("Ryan") /// ) - /// .get_results(&connection); + /// .get_results(&mut connection); /// let expected = vec!["Tess".to_string()]; /// assert_eq!(Ok(expected), query); /// # } @@ -137,16 +137,16 @@ where /// # use self::users::dsl::*; /// # use diesel::dsl::sql; /// # use diesel::sql_types::Bool; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # diesel::insert_into(users).values(name.eq("Ryan")) - /// # .execute(&connection).unwrap(); + /// # .execute(&mut connection).unwrap(); /// let query = users /// .select(name) /// .filter( /// sql::("id > 1") /// .sql(" AND name <> 'Ryan'") /// ) - /// .get_results(&connection); + /// .get_results(&mut connection); /// let expected = vec!["Tess".to_string()]; /// assert_eq!(Ok(expected), query); /// # } @@ -230,8 +230,8 @@ impl ValidGrouping for SqlLiteral { /// # use schema::users::dsl::*; /// # use diesel::sql_types::Bool; /// use diesel::dsl::sql; -/// # let connection = establish_connection(); -/// let user = users.filter(sql::("name = 'Sean'")).first(&connection)?; +/// # let mut connection = establish_connection(); +/// let user = users.filter(sql::("name = 'Sean'")).first(&mut connection)?; /// let expected = (1, String::from("Sean")); /// assert_eq!(expected, user); /// # Ok(()) @@ -241,10 +241,10 @@ impl ValidGrouping for SqlLiteral { /// # use crate::schema::users::dsl::*; /// # use diesel::dsl::sql; /// # use diesel::sql_types::{Bool, Integer, Text}; -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// # diesel::insert_into(users) /// # .values(name.eq("Ryan")) -/// # .execute(&connection).unwrap(); +/// # .execute(&mut connection).unwrap(); /// let query = users /// .select(name) /// .filter( @@ -253,7 +253,7 @@ impl ValidGrouping for SqlLiteral { /// .sql(" AND name <> ") /// .bind::("Ryan") /// ) -/// .get_results(&connection); +/// .get_results(&mut connection); /// let expected = vec!["Tess".to_string()]; /// assert_eq!(Ok(expected), query); /// # Ok(()) @@ -312,9 +312,9 @@ where /// # use self::users::dsl::*; /// # use diesel::dsl::sql; /// # use diesel::sql_types::{Integer, Bool}; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # diesel::insert_into(users).values(name.eq("Ryan")) - /// # .execute(&connection).unwrap(); + /// # .execute(&mut connection).unwrap(); /// let query = users /// .select(name) /// .filter( @@ -322,7 +322,7 @@ where /// .bind::(1) /// .sql(" AND name <> 'Ryan'") /// ) - /// .get_results(&connection); + /// .get_results(&mut connection); /// let expected = vec!["Tess".to_string()]; /// assert_eq!(Ok(expected), query); /// # } diff --git a/diesel/src/expression_methods/bool_expression_methods.rs b/diesel/src/expression_methods/bool_expression_methods.rs index c31a59f62faa..cb8e7a863865 100644 --- a/diesel/src/expression_methods/bool_expression_methods.rs +++ b/diesel/src/expression_methods/bool_expression_methods.rs @@ -19,18 +19,18 @@ pub trait BoolExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// diesel::insert_into(animals) /// .values(&vec![ /// (species.eq("ferret"), legs.eq(4), name.eq("Freddy")), /// (species.eq("ferret"), legs.eq(4), name.eq("Jack")), /// ]) - /// .execute(&connection)?; + /// .execute(&mut connection)?; /// /// let data = animals.select((species, name)) /// .filter(species.eq("ferret").and(name.eq("Jack"))) - /// .load(&connection)?; + /// .load(&mut connection)?; /// let expected = vec![ /// (String::from("ferret"), Some(String::from("Jack"))), /// ]; @@ -65,18 +65,18 @@ pub trait BoolExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// diesel::insert_into(animals) /// .values(&vec![ /// (species.eq("ferret"), legs.eq(4), name.eq("Freddy")), /// (species.eq("ferret"), legs.eq(4), name.eq("Jack")), /// ]) - /// .execute(&connection)?; + /// .execute(&mut connection)?; /// /// let data = animals.select((species, name)) /// .filter(species.eq("ferret").or(name.eq("Jack"))) - /// .load(&connection)?; + /// .load(&mut connection)?; /// let expected = vec![ /// (String::from("dog"), Some(String::from("Jack"))), /// (String::from("ferret"), Some(String::from("Freddy"))), diff --git a/diesel/src/expression_methods/escape_expression_methods.rs b/diesel/src/expression_methods/escape_expression_methods.rs index e7525e0e9907..6e669eea4d14 100644 --- a/diesel/src/expression_methods/escape_expression_methods.rs +++ b/diesel/src/expression_methods/escape_expression_methods.rs @@ -18,15 +18,15 @@ use crate::sql_types::VarChar; /// # fn main() { /// # use schema::users::dsl::*; /// # use diesel::insert_into; -/// # let connection = establish_connection(); +/// # let mut connection = establish_connection(); /// # insert_into(users).values(name.eq("Ha%%0r")) -/// # .execute(&connection).unwrap(); +/// # .execute(&mut connection).unwrap(); /// let users_with_percent = users.select(name) /// .filter(name.like("%😀%%").escape('😀')) -/// .load(&connection); +/// .load(&mut connection); /// let users_without_percent = users.select(name) /// .filter(name.not_like("%a%%").escape('a')) -/// .load(&connection); +/// .load(&mut connection); /// assert_eq!(Ok(vec![String::from("Ha%%0r")]), users_with_percent); /// assert_eq!(Ok(vec![String::from("Sean"), String::from("Tess")]), users_without_percent); /// # } diff --git a/diesel/src/expression_methods/global_expression_methods.rs b/diesel/src/expression_methods/global_expression_methods.rs index bdf716a846e0..a0cd85603848 100644 --- a/diesel/src/expression_methods/global_expression_methods.rs +++ b/diesel/src/expression_methods/global_expression_methods.rs @@ -16,9 +16,9 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn main() { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users.select(id).filter(name.eq("Sean")); - /// assert_eq!(Ok(1), data.first(&connection)); + /// assert_eq!(Ok(1), data.first(&mut connection)); /// # } /// ``` #[doc(alias = "=")] @@ -39,9 +39,9 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn main() { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users.select(id).filter(name.ne("Sean")); - /// assert_eq!(Ok(2), data.first(&connection)); + /// assert_eq!(Ok(2), data.first(&mut connection)); /// # } /// ``` #[doc(alias = "<>")] @@ -72,22 +72,22 @@ pub trait ExpressionMethods: Expression + Sized { /// # fn main() { /// # use schema::users; /// # use schema::posts; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # connection.execute("INSERT INTO users (name) VALUES /// # ('Jim')").unwrap(); /// let data = users::table.select(users::id).filter(users::name.eq_any(vec!["Sean", "Jim"])); - /// assert_eq!(Ok(vec![1, 3]), data.load(&connection)); + /// assert_eq!(Ok(vec![1, 3]), data.load(&mut connection)); /// /// // Calling `eq_any` with an empty array is the same as doing `WHERE 1=0` /// let data = users::table.select(users::id).filter(users::name.eq_any(Vec::::new())); - /// assert_eq!(Ok(vec![]), data.load::(&connection)); + /// assert_eq!(Ok(vec![]), data.load::(&mut connection)); /// /// // Calling `eq_any` with a subquery is the same as using /// // `WHERE {column} IN {subquery}`. /// /// let subquery = users::table.filter(users::name.eq("Sean")).select(users::id).into_boxed(); /// let data = posts::table.select(posts::id).filter(posts::user_id.eq_any(subquery)); - /// assert_eq!(Ok(vec![1, 2]), data.load::(&connection)); + /// assert_eq!(Ok(vec![1, 2]), data.load::(&mut connection)); /// /// # } /// ``` @@ -114,18 +114,18 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn main() { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # connection.execute("INSERT INTO users (name) VALUES /// # ('Jim')").unwrap(); /// let data = users.select(id).filter(name.ne_all(vec!["Sean", "Jim"])); - /// assert_eq!(Ok(vec![2]), data.load(&connection)); + /// assert_eq!(Ok(vec![2]), data.load(&mut connection)); /// /// let data = users.select(id).filter(name.ne_all(vec!["Tess"])); - /// assert_eq!(Ok(vec![1, 3]), data.load(&connection)); + /// assert_eq!(Ok(vec![1, 3]), data.load(&mut connection)); /// /// // Calling `ne_any` with an empty array is the same as doing `WHERE 1=1` /// let data = users.select(id).filter(name.ne_all(Vec::::new())); - /// assert_eq!(Ok(vec![1, 2, 3]), data.load(&connection)); + /// assert_eq!(Ok(vec![1, 2, 3]), data.load(&mut connection)); /// # } /// ``` #[doc(alias = "in")] @@ -150,12 +150,12 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let data = animals /// .select(species) /// .filter(name.is_null()) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("spider", data); /// # Ok(()) /// # } @@ -176,12 +176,12 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let data = animals /// .select(species) /// .filter(name.is_not_null()) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("dog", data); /// # Ok(()) /// # } @@ -202,11 +202,11 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users /// .select(name) /// .filter(id.gt(1)) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("Tess", data); /// # Ok(()) /// # } @@ -233,11 +233,11 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users /// .select(name) /// .filter(id.ge(2)) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("Tess", data); /// # Ok(()) /// # } @@ -264,11 +264,11 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users /// .select(name) /// .filter(id.lt(2)) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("Sean", data); /// # Ok(()) /// # } @@ -295,11 +295,11 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// let data = users /// .select(name) /// .filter(id.le(2)) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("Sean", data); /// # Ok(()) /// # } @@ -322,12 +322,12 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn main() { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let data = animals /// .select(species) /// .filter(legs.between(2, 6)) - /// .first(&connection); + /// .first(&mut connection); /// # /// assert_eq!(Ok("dog".to_string()), data); /// # } @@ -358,12 +358,12 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::animals::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let data = animals /// .select(species) /// .filter(legs.not_between(2, 6)) - /// .first::(&connection)?; + /// .first::(&mut connection)?; /// assert_eq!("spider", data); /// # Ok(()) /// # } @@ -393,12 +393,12 @@ pub trait ExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let names = users /// .select(name) /// .order(name.desc()) - /// .load::(&connection)?; + /// .load::(&mut connection)?; /// assert_eq!(vec!["Tess", "Sean"], names); /// # Ok(()) /// # } @@ -470,12 +470,12 @@ pub trait NullableExpressionMethods: Expression + Sized { /// fn main() { /// use self::users::dsl::*; /// use self::posts::dsl::{posts, author_name}; - /// let connection = establish_connection(); + /// let mut connection = establish_connection(); /// /// let data = users.inner_join(posts) /// .filter(name.nullable().eq(author_name)) /// .select(name) - /// .load::(&connection); + /// .load::(&mut connection); /// println!("{:?}", data); /// } /// ``` diff --git a/diesel/src/expression_methods/text_expression_methods.rs b/diesel/src/expression_methods/text_expression_methods.rs index 0e817060573c..80d439ac09a9 100644 --- a/diesel/src/expression_methods/text_expression_methods.rs +++ b/diesel/src/expression_methods/text_expression_methods.rs @@ -25,7 +25,7 @@ pub trait TextExpressionMethods: Expression + Sized { /// # use self::users::dsl::*; /// # use diesel::insert_into; /// # - /// # let connection = connection_no_data(); + /// # let mut connection = connection_no_data(); /// # connection.execute("CREATE TABLE users ( /// # id INTEGER PRIMARY KEY, /// # name VARCHAR(255) NOT NULL, @@ -37,10 +37,10 @@ pub trait TextExpressionMethods: Expression + Sized { /// # (id.eq(1), name.eq("Sean"), hair_color.eq(Some("Green"))), /// # (id.eq(2), name.eq("Tess"), hair_color.eq(None)), /// # ]) - /// # .execute(&connection) + /// # .execute(&mut connection) /// # .unwrap(); /// # - /// let names = users.select(name.concat(" the Greatest")).load(&connection); + /// let names = users.select(name.concat(" the Greatest")).load(&mut connection); /// let expected_names = vec![ /// "Sean the Greatest".to_string(), /// "Tess the Greatest".to_string(), @@ -48,7 +48,7 @@ pub trait TextExpressionMethods: Expression + Sized { /// assert_eq!(Ok(expected_names), names); /// /// // If the value is nullable, the output will be nullable - /// let names = users.select(hair_color.concat("ish")).load(&connection); + /// let names = users.select(hair_color.concat("ish")).load(&mut connection); /// let expected_names = vec![ /// Some("Greenish".to_string()), /// None, @@ -82,12 +82,12 @@ pub trait TextExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let starts_with_s = users /// .select(name) /// .filter(name.like("S%")) - /// .load::(&connection)?; + /// .load::(&mut connection)?; /// assert_eq!(vec!["Sean"], starts_with_s); /// # Ok(()) /// # } @@ -118,12 +118,12 @@ pub trait TextExpressionMethods: Expression + Sized { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::users::dsl::*; - /// # let connection = establish_connection(); + /// # let mut connection = establish_connection(); /// # /// let doesnt_start_with_s = users /// .select(name) /// .filter(name.not_like("S%")) - /// .load::(&connection)?; + /// .load::(&mut connection)?; /// assert_eq!(vec!["Tess"], doesnt_start_with_s); /// # Ok(()) /// # } diff --git a/diesel/src/insertable.rs b/diesel/src/insertable.rs index b8f3ea011d4b..8c0da3cb5247 100644 --- a/diesel/src/insertable.rs +++ b/diesel/src/insertable.rs @@ -48,8 +48,8 @@ pub trait Insertable { /// # /// # fn run_test() -> QueryResult<()> { /// # use schema::{posts, users}; - /// # let conn = establish_connection(); - /// # diesel::delete(posts::table).execute(&conn)?; + /// # let mut conn = establish_connection(); + /// # diesel::delete(posts::table).execute(&mut conn)?; /// users::table /// .select(( /// users::name.concat("'s First Post"), @@ -57,11 +57,11 @@ pub trait Insertable { /// )) /// .insert_into(posts::table) /// .into_columns((posts::title, posts::user_id)) - /// .execute(&conn)?; + /// .execute(&mut conn)?; /// /// let inserted_posts = posts::table /// .select(posts::title) - /// .load::(&conn)?; + /// .load::(&mut conn)?; /// let expected = vec!["Sean's First Post", "Tess's First Post"]; /// assert_eq!(expected, inserted_posts); /// # Ok(()) diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index 96211a2569a5..59a15bcf280d 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -95,7 +95,7 @@ // For the `specialization` feature. #![cfg_attr(feature = "unstable", allow(incomplete_features))] // Built-in Lints -#![deny(warnings)] +//#![deny(warnings)] #![warn( missing_debug_implementations, missing_copy_implementations, diff --git a/diesel/src/migration/mod.rs b/diesel/src/migration/mod.rs index 9ce3e697563f..a6ca916ca5f2 100644 --- a/diesel/src/migration/mod.rs +++ b/diesel/src/migration/mod.rs @@ -94,10 +94,10 @@ pub trait MigrationName: Display { /// Represents a migration that interacts with diesel pub trait Migration { /// Apply this migration - fn run(&self, conn: &dyn BoxableConnection) -> Result<()>; + fn run(&self, conn: &mut dyn BoxableConnection) -> Result<()>; /// Revert this migration - fn revert(&self, conn: &dyn BoxableConnection) -> Result<()>; + fn revert(&self, conn: &mut dyn BoxableConnection) -> Result<()>; /// Get a the attached metadata for this migration fn metadata(&self) -> &dyn MigrationMetadata; @@ -141,11 +141,11 @@ pub trait MigrationSource { } impl<'a, DB: Backend> Migration for Box + 'a> { - fn run(&self, conn: &dyn BoxableConnection) -> Result<()> { + fn run(&self, conn: &mut dyn BoxableConnection) -> Result<()> { (&**self).run(conn) } - fn revert(&self, conn: &dyn BoxableConnection) -> Result<()> { + fn revert(&self, conn: &mut dyn BoxableConnection) -> Result<()> { (&**self).revert(conn) } @@ -159,11 +159,11 @@ impl<'a, DB: Backend> Migration for Box + 'a> { } impl<'a, DB: Backend> Migration for &'a dyn Migration { - fn run(&self, conn: &dyn BoxableConnection) -> Result<()> { + fn run(&self, conn: &mut dyn BoxableConnection) -> Result<()> { (&**self).run(conn) } - fn revert(&self, conn: &dyn BoxableConnection) -> Result<()> { + fn revert(&self, conn: &mut dyn BoxableConnection) -> Result<()> { (&**self).revert(conn) } @@ -195,12 +195,12 @@ pub trait MigrationConnection: Connection { /// } /// } /// ``` - fn setup(&self) -> QueryResult; + fn setup(&mut self) -> QueryResult; } #[cfg(feature = "postgres")] impl MigrationConnection for crate::pg::PgConnection { - fn setup(&self) -> QueryResult { + fn setup(&mut self) -> QueryResult { use crate::RunQueryDsl; crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self) } @@ -208,7 +208,7 @@ impl MigrationConnection for crate::pg::PgConnection { #[cfg(feature = "mysql")] impl MigrationConnection for crate::mysql::MysqlConnection { - fn setup(&self) -> QueryResult { + fn setup(&mut self) -> QueryResult { use crate::RunQueryDsl; crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self) } @@ -216,7 +216,7 @@ impl MigrationConnection for crate::mysql::MysqlConnection { #[cfg(feature = "sqlite")] impl MigrationConnection for crate::sqlite::SqliteConnection { - fn setup(&self) -> QueryResult { + fn setup(&mut self) -> QueryResult { use crate::RunQueryDsl; crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self) } diff --git a/diesel/src/mysql/connection/bind.rs b/diesel/src/mysql/connection/bind.rs index 9f070eddb585..9648c30d434d 100644 --- a/diesel/src/mysql/connection/bind.rs +++ b/diesel/src/mysql/connection/bind.rs @@ -622,7 +622,7 @@ mod tests { #[cfg(feature = "extras")] #[test] fn check_all_the_types() { - let conn = crate::test_helpers::connection(); + let mut conn = crate::test_helpers::connection(); conn.execute("DROP TABLE IF EXISTS all_mysql_types CASCADE") .unwrap(); @@ -1149,7 +1149,7 @@ mod tests { #[test] fn check_json_bind() { - let conn: MysqlConnection = crate::test_helpers::connection(); + let mut conn: MysqlConnection = crate::test_helpers::connection(); table! { json_test { @@ -1168,7 +1168,7 @@ mod tests { let json_col_as_json = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()), ); @@ -1185,7 +1185,7 @@ mod tests { let json_col_as_text = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()), ); @@ -1205,7 +1205,7 @@ mod tests { input_bind( "INSERT INTO json_test(id, json_field) VALUES (?, ?)", - &conn, + &mut conn, 41, ( b"{\"abc\": 42}".to_vec(), @@ -1216,7 +1216,7 @@ mod tests { let json_col_as_json = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()), ); @@ -1233,7 +1233,7 @@ mod tests { let json_col_as_text = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()), ); @@ -1253,14 +1253,14 @@ mod tests { input_bind( "INSERT INTO json_test(id, json_field) VALUES (?, ?)", - &conn, + &mut conn, 41, (b"{\"abca\": 42}".to_vec(), MysqlType::String), ); let json_col_as_json = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()), ); @@ -1277,7 +1277,7 @@ mod tests { let json_col_as_text = query_single_table( "SELECT json_field FROM json_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()), ); @@ -1296,7 +1296,7 @@ mod tests { #[test] fn check_enum_bind() { - let conn: MysqlConnection = crate::test_helpers::connection(); + let mut conn: MysqlConnection = crate::test_helpers::connection(); conn.execute("DROP TABLE IF EXISTS enum_test CASCADE") .unwrap(); @@ -1307,8 +1307,11 @@ mod tests { conn.execute("INSERT INTO enum_test(id, enum_field) VALUES (1, 'green')") .unwrap(); - let enum_col_as_enum: BindData = - query_single_table("SELECT enum_field FROM enum_test", &conn, MysqlType::Enum); + let enum_col_as_enum: BindData = query_single_table( + "SELECT enum_field FROM enum_test", + &mut conn, + MysqlType::Enum, + ); assert_eq!( enum_col_as_enum.tpe, @@ -1333,7 +1336,7 @@ mod tests { ] { let enum_col_as_text = query_single_table( "SELECT enum_field FROM enum_test", - &conn, + &mut conn, (*tpe, Flags::ENUM_FLAG), ); @@ -1352,7 +1355,7 @@ mod tests { let enum_col_as_text = query_single_table( "SELECT enum_field FROM enum_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()), ); @@ -1372,13 +1375,16 @@ mod tests { input_bind( "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)", - &conn, + &mut conn, 41, (b"blue".to_vec(), MysqlType::Enum), ); - let enum_col_as_enum = - query_single_table("SELECT enum_field FROM enum_test", &conn, MysqlType::Enum); + let enum_col_as_enum = query_single_table( + "SELECT enum_field FROM enum_test", + &mut conn, + MysqlType::Enum, + ); assert_eq!( enum_col_as_enum.tpe, @@ -1393,7 +1399,7 @@ mod tests { let enum_col_as_text = query_single_table( "SELECT enum_field FROM enum_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG), ); @@ -1408,7 +1414,7 @@ mod tests { let enum_col_as_text = query_single_table( "SELECT enum_field FROM enum_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG), ); @@ -1425,7 +1431,7 @@ mod tests { input_bind( "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)", - &conn, + &mut conn, 41, ( b"red".to_vec(), @@ -1433,8 +1439,11 @@ mod tests { ), ); - let enum_col_as_enum = - query_single_table("SELECT enum_field FROM enum_test", &conn, MysqlType::Enum); + let enum_col_as_enum = query_single_table( + "SELECT enum_field FROM enum_test", + &mut conn, + MysqlType::Enum, + ); assert_eq!( enum_col_as_enum.tpe, @@ -1449,7 +1458,7 @@ mod tests { let enum_col_as_text = query_single_table( "SELECT enum_field FROM enum_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG), ); @@ -1465,7 +1474,7 @@ mod tests { #[test] fn check_set_bind() { - let conn: MysqlConnection = crate::test_helpers::connection(); + let mut conn: MysqlConnection = crate::test_helpers::connection(); conn.execute("DROP TABLE IF EXISTS set_test CASCADE") .unwrap(); @@ -1477,7 +1486,7 @@ mod tests { .unwrap(); let set_col_as_set: BindData = - query_single_table("SELECT set_field FROM set_test", &conn, MysqlType::Set); + query_single_table("SELECT set_field FROM set_test", &mut conn, MysqlType::Set); assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING); assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG)); @@ -1496,7 +1505,7 @@ mod tests { ] { let set_col_as_text = query_single_table( "SELECT set_field FROM set_test", - &conn, + &mut conn, (*tpe, Flags::SET_FLAG), ); @@ -1511,7 +1520,7 @@ mod tests { } let set_col_as_text = query_single_table( "SELECT set_field FROM set_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()), ); @@ -1528,13 +1537,13 @@ mod tests { input_bind( "INSERT INTO set_test(id, set_field) VALUES (?, ?)", - &conn, + &mut conn, 41, (b"blue".to_vec(), MysqlType::Set), ); let set_col_as_set = - query_single_table("SELECT set_field FROM set_test", &conn, MysqlType::Set); + query_single_table("SELECT set_field FROM set_test", &mut conn, MysqlType::Set); assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING); assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG)); @@ -1546,7 +1555,7 @@ mod tests { let set_col_as_text = query_single_table( "SELECT set_field FROM set_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG), ); @@ -1563,13 +1572,13 @@ mod tests { input_bind( "INSERT INTO set_test(id, set_field) VALUES (?, ?)", - &conn, + &mut conn, 41, (b"red".to_vec(), MysqlType::String), ); let set_col_as_set = - query_single_table("SELECT set_field FROM set_test", &conn, MysqlType::Set); + query_single_table("SELECT set_field FROM set_test", &mut conn, MysqlType::Set); assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING); assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG)); @@ -1581,7 +1590,7 @@ mod tests { let set_col_as_text = query_single_table( "SELECT set_field FROM set_test", - &conn, + &mut conn, (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG), ); diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs index 5d2d8e095ab4..b0614e5b00c1 100644 --- a/diesel/src/mysql/connection/mod.rs +++ b/diesel/src/mysql/connection/mod.rs @@ -20,14 +20,14 @@ use crate::result::*; /// `mysql://[user[:password]@]host/database_name` pub struct MysqlConnection { raw_connection: RawConnection, - transaction_manager: AnsiTransactionManager, + transaction_state: AnsiTransactionManagerData, statement_cache: StatementCache, } unsafe impl Send for MysqlConnection {} impl SimpleConnection for MysqlConnection { - fn batch_execute(&self, query: &str) -> QueryResult<()> { + fn batch_execute(&mut self, query: &str) -> QueryResult<()> { self.raw_connection .enable_multi_statements(|| self.raw_connection.execute(query)) } @@ -35,6 +35,8 @@ impl SimpleConnection for MysqlConnection { impl Connection for MysqlConnection { type Backend = Mysql; + type TransactionManager = AnsiTransactionManager; + type TransactionData = AnsiTransactionManagerData; fn establish(database_url: &str) -> ConnectionResult { use crate::result::ConnectionError::CouldntSetupConfiguration; @@ -42,9 +44,9 @@ impl Connection for MysqlConnection { let raw_connection = RawConnection::new(); let connection_options = ConnectionOptions::parse(database_url)?; raw_connection.connect(&connection_options)?; - let conn = MysqlConnection { - raw_connection: raw_connection, - transaction_manager: AnsiTransactionManager::new(), + let mut conn = MysqlConnection { + raw_connection, + transaction_state: AnsiTransactionManagerData::default(), statement_cache: StatementCache::new(), }; conn.set_config_options() @@ -53,14 +55,14 @@ impl Connection for MysqlConnection { } #[doc(hidden)] - fn execute(&self, query: &str) -> QueryResult { + fn execute(&mut self, query: &str) -> QueryResult { self.raw_connection .execute(query) .map(|_| self.raw_connection.affected_rows()) } #[doc(hidden)] - fn load(&self, source: T) -> QueryResult> + fn load(&mut self, source: T) -> QueryResult> where T: AsQuery, T::Query: QueryFragment + QueryId, @@ -72,13 +74,13 @@ impl Connection for MysqlConnection { let mut stmt = self.prepare_query(&source.as_query())?; let mut metadata = Vec::new(); - Mysql::row_metadata(&(), &mut metadata); + Mysql::row_metadata(&mut (), &mut metadata); let results = unsafe { stmt.results(metadata)? }; results.map(|row| U::build_from_row(&row).map_err(DeserializationError)) } #[doc(hidden)] - fn execute_returning_count(&self, source: &T) -> QueryResult + fn execute_returning_count(&mut self, source: &T) -> QueryResult where T: QueryFragment + QueryId, { @@ -90,21 +92,22 @@ impl Connection for MysqlConnection { } #[doc(hidden)] - fn transaction_manager(&self) -> &dyn TransactionManager { - &self.transaction_manager + fn transaction_state(&mut self) -> &mut AnsiTransactionManagerData { + &mut self.transaction_state } } impl MysqlConnection { - fn prepare_query(&self, source: &T) -> QueryResult> + fn prepare_query(&mut self, source: &T) -> QueryResult> where T: QueryFragment + QueryId, { - let mut stmt = self - .statement_cache - .cached_statement(source, &[], |sql| self.raw_connection.prepare(sql))?; + let cache = &mut self.statement_cache; + let conn = &mut self.raw_connection; + + let mut stmt = cache.cached_statement(source, &[], |sql| conn.prepare(sql))?; let mut bind_collector = RawBytesBindCollector::new(); - source.collect_binds(&mut bind_collector, &())?; + source.collect_binds(&mut bind_collector, &mut ())?; let binds = bind_collector .metadata .into_iter() @@ -113,7 +116,7 @@ impl MysqlConnection { Ok(stmt) } - fn set_config_options(&self) -> QueryResult<()> { + fn set_config_options(&mut self) -> QueryResult<()> { self.execute("SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT'))")?; self.execute("SET time_zone = '+00:00';")?; self.execute("SET character_set_client = 'utf8mb4'")?; @@ -141,14 +144,14 @@ mod tests { #[test] fn batch_execute_handles_single_queries_with_results() { - let connection = connection(); + let mut connection = connection(); assert!(connection.batch_execute("SELECT 1").is_ok()); assert!(connection.batch_execute("SELECT 1").is_ok()); } #[test] fn batch_execute_handles_multi_queries_with_results() { - let connection = connection(); + let mut connection = connection(); let query = "SELECT 1; SELECT 2; SELECT 3;"; assert!(connection.batch_execute(query).is_ok()); assert!(connection.batch_execute(query).is_ok()); @@ -156,7 +159,7 @@ mod tests { #[test] fn execute_handles_queries_which_return_results() { - let connection = connection(); + let mut connection = connection(); assert!(connection.execute("SELECT 1").is_ok()); assert!(connection.execute("SELECT 1").is_ok()); } diff --git a/diesel/src/mysql/types/date_and_time.rs b/diesel/src/mysql/types/date_and_time.rs index 093dd49fe0bd..bf219c395aaa 100644 --- a/diesel/src/mysql/types/date_and_time.rs +++ b/diesel/src/mysql/types/date_and_time.rs @@ -162,120 +162,111 @@ mod tests { use crate::prelude::*; use crate::select; use crate::sql_types::{Date, Datetime, Time, Timestamp}; - - fn connection() -> MysqlConnection { - dotenv().ok(); - - let connection_url = ::std::env::var("MYSQL_UNIT_TEST_DATABASE_URL") - .or_else(|_| ::std::env::var("MYSQL_DATABASE_URL")) - .or_else(|_| ::std::env::var("DATABASE_URL")) - .expect("DATABASE_URL must be set in order to run tests"); - MysqlConnection::establish(&connection_url).unwrap() - } + use crate::test_helpers::connection; #[test] fn unix_epoch_encodes_correctly() { - let connection = connection(); + let mut connection = connection(); let time = NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 0); let query = select(sql::("CAST('1970-01-01' AS DATETIME)").eq(time)); - assert!(query.get_result::(&connection).unwrap()); + assert!(query.get_result::(&mut connection).unwrap()); let query = select(sql::("CAST('1970-01-01' AS DATETIME)").eq(time)); - assert!(query.get_result::(&connection).unwrap()); + assert!(query.get_result::(&mut connection).unwrap()); } #[test] fn unix_epoch_decodes_correctly() { - let connection = connection(); + let mut connection = connection(); let time = NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 0); let epoch_from_sql = - select(sql::("CAST('1970-01-01' AS DATETIME)")).get_result(&connection); + select(sql::("CAST('1970-01-01' AS DATETIME)")).get_result(&mut connection); assert_eq!(Ok(time), epoch_from_sql); let epoch_from_sql = - select(sql::("CAST('1970-01-01' AS DATETIME)")).get_result(&connection); + select(sql::("CAST('1970-01-01' AS DATETIME)")).get_result(&mut connection); assert_eq!(Ok(time), epoch_from_sql); } #[test] fn times_relative_to_now_encode_correctly() { - let connection = connection(); + let mut connection = connection(); let time = Utc::now().naive_utc() + Duration::days(1); let query = select(now.lt(time)); - assert!(query.get_result::(&connection).unwrap()); + assert!(query.get_result::(&mut connection).unwrap()); let time = Utc::now().naive_utc() - Duration::days(1); let query = select(now.gt(time)); - assert!(query.get_result::(&connection).unwrap()); + assert!(query.get_result::(&mut connection).unwrap()); } #[test] fn times_of_day_encode_correctly() { - let connection = connection(); + let mut connection = connection(); let midnight = NaiveTime::from_hms(0, 0, 0); let query = select(sql::