From 18aaf11747a3a4ea6b4cc5a484519660cadeb2a8 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 22 Apr 2022 17:17:10 +0200 Subject: [PATCH 001/107] Add missing fields to diesel_dynamic_schema/Cargo.toml --- diesel_dynamic_schema/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/diesel_dynamic_schema/Cargo.toml b/diesel_dynamic_schema/Cargo.toml index 12939f5197a4..5f59deaa8257 100644 --- a/diesel_dynamic_schema/Cargo.toml +++ b/diesel_dynamic_schema/Cargo.toml @@ -4,6 +4,12 @@ version = "0.2.0-rc.0" license = "MIT OR Apache-2.0" edition = "2018" autotests = false +description = "A safe, extensible ORM and Query Builder for PostgreSQL, SQLite, and MySQL" +documentation = "https://docs.rs/diesel/" +homepage = "https://diesel.rs" +repository = "https://github.com/diesel-rs/diesel" +keywords = ["orm", "database", "sql"] +categories = ["database"] include = ["src/**/*", "LICENSE-*", "README.md"] [dependencies.diesel] From 5f8fd9c4508d1d2448ddb8383f15fd77cf48a221 Mon Sep 17 00:00:00 2001 From: Martinez Date: Fri, 22 Apr 2022 18:57:04 +0300 Subject: [PATCH 002/107] Fix links in migration guide --- guide_drafts/migration_guide.md | 50 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md index 1fe1e8c2df02..9f37c6e8bbb2 100644 --- a/guide_drafts/migration_guide.md +++ b/guide_drafts/migration_guide.md @@ -9,39 +9,39 @@ are marked as deprecated in Diesel 1.4.x. Any code base using migrating to Diesel 2.0 is expected to be affected at least by the following changes: -* [Diesel now requires a mutable reference to the connection](2-0-0-mutable-connection) -* [Changed derive attributes](2-0-0-derive-attributes) +* [Diesel now requires a mutable reference to the connection](#2-0-0-mutable-connection) +* [Changed derive attributes](#2-0-0-derive-attributes) Users of `diesel_migration` are additionally affected by the following change: -* [`diesel_migration` rewrite](2-0-0-upgrade-migrations) +* [`diesel_migration` rewrite](#2-0-0-upgrade-migrations) Users of `BoxableExpression` might be affected by the following change: -* [Changed nullability of operators](2-0-0-nullability-ops) +* [Changed nullability of operators](#2-0-0-nullability-ops) Users that implement support for their SQL types or type mappings are affected by the following changes: -* [Changed required traits for custom SQL types](2-0-0-custom-type-implementation) -* [Changed `ToSql` implementations](2-0-0-to-sql) -* [Changed `FromSql` implementations](2-0-0-from-sql) +* [Changed required traits for custom SQL types](#2-0-0-custom-type-implementation) +* [Changed `ToSql` implementations](#2-0-0-to-sql) +* [Changed `FromSql` implementations](#2-0-0-from-sql) `no_arg_sql_function!` macro is now pending deprecation. Users of the macro are advised to consider `sql_function!` macro. -* [Deprecated usage of `no_arg_sql_function!` macro](2-0-0-no_arg_sql_function) +* [Deprecated usage of `no_arg_sql_function!` macro](#2-0-0-no_arg_sql_function) Users that update generic Diesel code will also be affected by the following changes: -* [Removing `NonAggregate` in favor of `ValidGrouping`](2-0-0-upgrade-non-aggregate) -* [Changed generic bounds](2-0-0-generic-changes) +* [Removing `NonAggregate` in favor of `ValidGrouping`](#2-0-0-upgrade-non-aggregate) +* [Changed generic bounds](#2-0-0-generic-changes) Additionally this release contains many changes for users that implemented a custom backend/connection. We do not provide explicit migration steps but we encourage users to reach out with questions pertaining to these changes. -## Mutable Connections required - + +## Mutable Connections required Diesel now requires mutable access to the `Connection` to perform any database interaction. The following changes are required for all usages of any `Connection` type: @@ -56,8 +56,7 @@ are required for all usages of any `Connection` type: We expect this to be a straightforward change as the connection already can execute only one query at a time. -## Derive attributes - +## Derive attributes We have updated all of our Diesel derive attributes to follow the patterns that are used widely in the Rust's ecosystem. This means that all of them need to be wrapped by `#[diesel()]` now. You can now specify multiple attributes on the same line using `,` separator. @@ -66,8 +65,7 @@ This is backward compatible and thus all of your old attributes will still work, warnings. The attributes can be upgraded by either looking at the warnings or by reading diesel derive documentation reference. -## `diesel_migration` rewrite - +## `diesel_migration` rewrite We have completely rewritten the `diesel_migration` crate. As a part of this rewrite all free standing functions are removed from `diesel_migration`. Equivalent functionality @@ -102,8 +100,7 @@ fn run_migration(conn: &PgConnection) { } ``` -## Changed nullability of operators - +## Changed nullability of operators We changed the way how we handle the propagation of null values through binary operators. Diesel 1.x always assumed that the result of a binary operation `value_a > value_b` is not nullable, which does not match the behaviour of the @@ -115,8 +112,7 @@ there we recommend to use one of the following functions: * `NullableExpressionMethods::nullable()` * `NullableExpressionMethods::assume_not_nullable()` -## Custom SQL type implementations - +## Custom SQL type implementations We changed how we mark sql types as nullable at type level. For this we replaced the `NonNull` trait with a more generic `SqlType` trait, which allows to mark a sql type as (non-) nullable. This may affect custom @@ -137,7 +133,7 @@ Additionally, the diesel CLI tool was changed so that it automatically generates as long as they appear on any table. This feature currently only supports the PostgreSQL backend, as all other supported backends do not support real custom types at SQL level at all. -## Changed `ToSql` implementations +## Changed `ToSql` implementations We restructured the way Diesel serializes Rust values to their backend specific representation. This enables us to skip copying the value at all if the specific backend supports writing to a @@ -155,8 +151,7 @@ For backend concrete implementations, the following functions allow You to work -## Changed `FromSql` implementations - +## Changed `FromSql` implementations We changed the raw value representation for both PostgreSQL and MySQL backends, from a `& [u8]` to an opaque type. This allows us to include additional information like the database side @@ -177,8 +172,7 @@ impl FromSql for YourType { -## `no_arg_sql_function` - +## `no_arg_sql_function` The `no_arg_sql_function` was deprecated without direct replacement. At the same time the `sql_function!` macro gained support for sql functions without argument. This support generates slightly @@ -198,8 +192,7 @@ affects all of the usages of the `no_arg_sql_function!` in third party crates. + diesel::select(now()) ``` -### Replacement of `NonAggregate` with `ValidGrouping` - +### Replacement of `NonAggregate` with `ValidGrouping` Diesel now fully enforces the aggregation rules, which required us to change the way we represent the aggregation at the type system level. This is used to provide `group_by` support. Diesel's aggregation rules @@ -230,8 +223,7 @@ change shows the strictly equivalent version: ``` -## Other changes to generics - +## Other changes to generics In addition to the changes listed above, we changed numerous internal details of Diesel. This will have impact on most codebases that include non-trivial generic code abstracting over Diesel. This section tries to list as much of those From c1d1f2a1791cf98f85a0bbb5d95bfda6e1758810 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Sat, 23 Apr 2022 08:28:36 +0200 Subject: [PATCH 003/107] Fix potential name collisions in code generated by the `table!` macro This commit fixes potential name collisions in code generated by the `table!` macro by prefixing function argument names with `__diesel_internal`. The underlying problem here is that rust accepts patterns as part of the function signature. This combined with the fact that each zero sized struct (so all column/table structs) are type + value at the same time results in problems as soon as the users tries to create a column/table with the same name as one of the used arguments. So for example if the users has a table that contains an `alias` column, that would have caused a name collision inside of the following function signature: ```rust fn map(column: C, alias: &$crate::query_source::Alias) -> Self::Out ``` Rustc would have interpreted `alias` here as zero sized struct literal, which of course has a different type than the corresponding RHS. That results in a compiler error about mismatched types. This commit fixes this problem by prefixing the corresponding variables with `__diesel_internal`, which is hopefully reasonably uncommon, so that no one uses that as column name prefix. --- diesel/src/macros/mod.rs | 62 ++++++++++++++++++++-------------------- diesel/src/macros/ops.rs | 4 +-- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/diesel/src/macros/mod.rs b/diesel/src/macros/mod.rs index a5c80b97359b..57f8b44c856f 100644 --- a/diesel/src/macros/mod.rs +++ b/diesel/src/macros/mod.rs @@ -63,9 +63,9 @@ macro_rules! __diesel_internal_backend_specific_table_impls { type FromClause = $crate::query_builder::Only; type OnClause = <$crate::query_builder::Only as $crate::JoinTo<$table>>::OnClause; - fn join_target(rhs: $crate::query_builder::Only) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::query_builder::Only::::join_target($table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::query_builder::Only) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::query_builder::Only::::join_target($table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -113,13 +113,13 @@ macro_rules! __diesel_column { $crate::internal::table_macro::StaticQueryFragmentInstance: $crate::query_builder::QueryFragment, { #[allow(non_snake_case)] - fn walk_ast<'b>(&'b self, mut __out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> + fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); - FROM_CLAUSE.walk_ast(__out.reborrow())?; - __out.push_sql("."); - __out.push_identifier($sql_name) + FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; + __diesel_internal_out.push_sql("."); + __diesel_internal_out.push_identifier($sql_name) } } @@ -195,9 +195,9 @@ macro_rules! __diesel_column { { type Output = $crate::dsl::Eq; - fn eq_all(self, rhs: T) -> Self::Output { + fn eq_all(self, __diesel_internal_rhs: T) -> Self::Output { use $crate::expression_methods::ExpressionMethods; - self.eq(rhs) + self.eq(__diesel_internal_rhs) } } @@ -805,8 +805,8 @@ macro_rules! __diesel_table_impl { DB: $crate::backend::Backend,
::Component: $crate::query_builder::QueryFragment { - fn walk_ast<'b>(&'b self, pass: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { -
::STATIC_COMPONENT.walk_ast(pass) + fn walk_ast<'b>(&'b self, __diesel_internal_pass: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { +
::STATIC_COMPONENT.walk_ast(__diesel_internal_pass) } } @@ -887,8 +887,8 @@ macro_rules! __diesel_table_impl { { type Out = $crate::query_source::AliasedField; - fn map(column: C, alias: &$crate::query_source::Alias) -> Self::Out { - alias.field(column) + fn map(__diesel_internal_column: C, __diesel_internal_alias: &$crate::query_source::Alias) -> Self::Out { + __diesel_internal_alias.field(__diesel_internal_column) } } @@ -904,9 +904,9 @@ macro_rules! __diesel_table_impl { type FromClause = $crate::internal::table_macro::Join; type OnClause = <$crate::internal::table_macro::Join as $crate::JoinTo
>::OnClause; - fn join_target(rhs: $crate::internal::table_macro::Join) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::internal::table_macro::Join::join_target(table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::Join) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::Join::join_target(table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -916,9 +916,9 @@ macro_rules! __diesel_table_impl { type FromClause = $crate::internal::table_macro::JoinOn; type OnClause = <$crate::internal::table_macro::JoinOn as $crate::JoinTo
>::OnClause; - fn join_target(rhs: $crate::internal::table_macro::JoinOn) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::internal::table_macro::JoinOn::join_target(table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::JoinOn) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::JoinOn::join_target(table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -929,9 +929,9 @@ macro_rules! __diesel_table_impl { type FromClause = $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause, S, D, W, O, L, Of, G>; type OnClause = <$crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause, S, D, W, O, L, Of, G> as $crate::JoinTo
>::OnClause; - fn join_target(rhs: $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause, S, D, W, O, L, Of, G>) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::internal::table_macro::SelectStatement::join_target(table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause, S, D, W, O, L, Of, G>) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::SelectStatement::join_target(table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -941,9 +941,9 @@ macro_rules! __diesel_table_impl { { type FromClause = $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause, ST, DB>; type OnClause = <$crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause, ST, DB> as $crate::JoinTo
>::OnClause; - fn join_target(rhs: $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause, ST, DB>) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::internal::table_macro::BoxedSelectStatement::join_target(table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause, ST, DB>) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::BoxedSelectStatement::join_target(table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -954,9 +954,9 @@ macro_rules! __diesel_table_impl { type FromClause = $crate::query_source::Alias; type OnClause = <$crate::query_source::Alias as $crate::JoinTo
>::OnClause; - fn join_target(rhs: $crate::query_source::Alias) -> (Self::FromClause, Self::OnClause) { - let (_, on_clause) = $crate::query_source::Alias::::join_target(table); - (rhs, on_clause) + fn join_target(__diesel_internal_rhs: $crate::query_source::Alias) -> (Self::FromClause, Self::OnClause) { + let (_, __diesel_internal_on_clause) = $crate::query_source::Alias::::join_target(table); + (__diesel_internal_rhs, __diesel_internal_on_clause) } } @@ -1015,13 +1015,13 @@ macro_rules! __diesel_table_impl {
::FromClause: $crate::query_builder::QueryFragment, { #[allow(non_snake_case)] - fn walk_ast<'b>(&'b self, mut __out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> + fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { use $crate::QuerySource; const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); - FROM_CLAUSE.walk_ast(__out.reborrow())?; - __out.push_sql(".*"); + FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; + __diesel_internal_out.push_sql(".*"); Ok(()) } } diff --git a/diesel/src/macros/ops.rs b/diesel/src/macros/ops.rs index 6f460644c736..626627ec2b84 100644 --- a/diesel/src/macros/ops.rs +++ b/diesel/src/macros/ops.rs @@ -14,8 +14,8 @@ macro_rules! operator_allowed { { type Output = $crate::internal::table_macro::ops::$op; - fn $fn_name(self, rhs: Rhs) -> Self::Output { - $crate::internal::table_macro::ops::$op::new(self, rhs.as_expression()) + fn $fn_name(self, __diesel_internal_rhs: Rhs) -> Self::Output { + $crate::internal::table_macro::ops::$op::new(self, __diesel_internal_rhs.as_expression()) } } }; From fc0fd7b7b8543d96da7ffaf6ca0de059bf28a56d Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 26 Apr 2022 14:24:38 +0200 Subject: [PATCH 004/107] Remove the note about unsupported nullable arrays from the documentation --- diesel/src/pg/types/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index 2935795d633f..919a43b50d18 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -86,8 +86,7 @@ pub mod sql_types { /// The [`Array`] SQL type. /// /// This wraps another type to represent a SQL array of that type. - /// Multidimensional arrays are not supported, - /// nor are arrays containing null. + /// Multidimensional arrays are not supported. /// /// ### [`ToSql`] impls /// From 0f19c930f13a9365727d901c9c41f9d464dbd7f3 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 26 Apr 2022 14:39:41 +0200 Subject: [PATCH 005/107] Add a note about the `Array` -> `Array>` change to the migration guide --- guide_drafts/migration_guide.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md index 9f37c6e8bbb2..b5fb1a1b2190 100644 --- a/guide_drafts/migration_guide.md +++ b/guide_drafts/migration_guide.md @@ -20,6 +20,10 @@ Users of `BoxableExpression` might be affected by the following change: * [Changed nullability of operators](#2-0-0-nullability-ops) +Users of tables containing an column of the type `Array` are affected by the following change: + +* [Changed nullability of array elemetns](#2-0-0-nullability-of-array-elements) + Users that implement support for their SQL types or type mappings are affected by the following changes: @@ -112,6 +116,16 @@ there we recommend to use one of the following functions: * `NullableExpressionMethods::nullable()` * `NullableExpressionMethods::assume_not_nullable()` +## Changed nullability of array elements + +We changed the infered SQL type for columns with array types for the PostgreSQL backend. Instead of using `Array` +we now infer `Array>` to support arrays containing `NULL` values. This change implies a change mapping +of columns of the corresponding types. It is possible to handle this change using one of the following strategies: + +* Use `Vec>` as rust side type instead of `Vec` +* Manually set the corresponding column to `Array` in your schema, to signal that this array does not contain null values. You may want to use the `patch_file` key for diesel CLI for this. +* Use `#[diesel(deserialize_as = "…")]` to explicitly overwrite the used deserialization implementation for this specific struct field. Checkout the documentation of `#[derive(Queryable)]` for details. + ## Custom SQL type implementations We changed how we mark sql types as nullable at type level. For this we replaced the `NonNull` trait with a From 724b1f2683c58a5d83d9d65c5fc6a7c4bd8c0ffc Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 26 Apr 2022 14:40:05 +0200 Subject: [PATCH 006/107] Add a missing lifetime to the `FromSql` example from the migration guide --- guide_drafts/migration_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md index b5fb1a1b2190..3c12240bef92 100644 --- a/guide_drafts/migration_guide.md +++ b/guide_drafts/migration_guide.md @@ -177,7 +177,7 @@ Any affected backend needs to perform the following changes: ```diff impl FromSql for YourType { - fn from_sql(bytes: &[u8]) -> deserialize::Result { -+ fn from_sql(value: backend::RawValue) -> deserialize::Result { ++ fn from_sql(value: backend::RawValue<'_, DB>) -> deserialize::Result { + let bytes = value.as_bytes(); // … } From 0b011458ca308339d571e743f1caf8dd4f7dfb0c Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 26 Apr 2022 17:49:17 +0000 Subject: [PATCH 007/107] Apply suggestions from code review Co-authored-by: Christopher Fleetwood <45471420+FL33TW00D@users.noreply.github.com> --- guide_drafts/migration_guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md index 3c12240bef92..2e9be036c14a 100644 --- a/guide_drafts/migration_guide.md +++ b/guide_drafts/migration_guide.md @@ -20,7 +20,7 @@ Users of `BoxableExpression` might be affected by the following change: * [Changed nullability of operators](#2-0-0-nullability-ops) -Users of tables containing an column of the type `Array` are affected by the following change: +Users of tables containing a column of the type `Array` are affected by the following change: * [Changed nullability of array elemetns](#2-0-0-nullability-of-array-elements) @@ -118,13 +118,13 @@ there we recommend to use one of the following functions: ## Changed nullability of array elements -We changed the infered SQL type for columns with array types for the PostgreSQL backend. Instead of using `Array` +We changed the inferred SQL type for columns with array types for the PostgreSQL backend. Instead of using `Array` we now infer `Array>` to support arrays containing `NULL` values. This change implies a change mapping of columns of the corresponding types. It is possible to handle this change using one of the following strategies: * Use `Vec>` as rust side type instead of `Vec` * Manually set the corresponding column to `Array` in your schema, to signal that this array does not contain null values. You may want to use the `patch_file` key for diesel CLI for this. -* Use `#[diesel(deserialize_as = "…")]` to explicitly overwrite the used deserialization implementation for this specific struct field. Checkout the documentation of `#[derive(Queryable)]` for details. +* Use `#[diesel(deserialize_as = "…")]` to explicitly overwrite the deserialization implementation used for this specific struct field. Checkout the documentation of `#[derive(Queryable)]` for details. ## Custom SQL type implementations From 10db1b8a2a7be9a34a193c2d0a12272baadad76f Mon Sep 17 00:00:00 2001 From: DrVilepis <63553760+DrVilepis@users.noreply.github.com> Date: Wed, 27 Apr 2022 16:02:02 +0300 Subject: [PATCH 008/107] Fixed typo --- diesel/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index fc55327e96d5..1dc697aee1b8 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -142,7 +142,7 @@ //! provided by `uuid` //! - `network-address`: This feature flag enables support for (de)serializing IP and Macadresse values from the //! database using types provided by `ipnetwork` -//! - `numeric`: This feature flag enables support for (de)support numeric values from the database using types +//! - `numeric`: This feature flag enables support for (de)serializing numeric values from the database using types //! provided by `bigdecimal` //! - `r2d2`: This feature flag enables support for the `r2d2` connection pool implementation. //! - `extras`: This feature enables the feature flaged support for any third party crate. This implies the From b3d913a1d56459b0585fc45c4e7196cc0269237b Mon Sep 17 00:00:00 2001 From: Zhenhui Xie Date: Fri, 29 Apr 2022 19:12:40 +0800 Subject: [PATCH 009/107] docs: Fix typo in nullability operators section --- guide_drafts/migration_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md index 2e9be036c14a..24418630c1ff 100644 --- a/guide_drafts/migration_guide.md +++ b/guide_drafts/migration_guide.md @@ -114,7 +114,7 @@ of `BoxableExpression` as it may change the resulting sql type there. As a possi there we recommend to use one of the following functions: * `NullableExpressionMethods::nullable()` -* `NullableExpressionMethods::assume_not_nullable()` +* `NullableExpressionMethods::assume_not_null()` ## Changed nullability of array elements From ca743afd75dd774b978bf935745c1988757926a5 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 29 Apr 2022 18:24:21 +0200 Subject: [PATCH 010/107] Allow `DISTINCT ON` to be used with queries containing an explicit sort order --- diesel/src/pg/query_builder/distinct_on.rs | 27 ++++++++++++++++++++++ diesel_tests/tests/distinct.rs | 19 ++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/diesel/src/pg/query_builder/distinct_on.rs b/diesel/src/pg/query_builder/distinct_on.rs index cab64bec9c99..06bf8ffe744a 100644 --- a/diesel/src/pg/query_builder/distinct_on.rs +++ b/diesel/src/pg/query_builder/distinct_on.rs @@ -23,6 +23,33 @@ where T::SqlType: SingleValue, { } +impl ValidOrderingForDistinct> for OrderClause> +where + T: Expression, + T::SqlType: SingleValue, +{ +} +impl ValidOrderingForDistinct> for OrderClause> +where + T: Expression, + T::SqlType: SingleValue, +{ +} + +impl ValidOrderingForDistinct> + for OrderClause<(crate::helper_types::Desc,)> +where + T: Expression, + T::SqlType: SingleValue, +{ +} +impl ValidOrderingForDistinct> + for OrderClause<(crate::helper_types::Asc,)> +where + T: Expression, + T::SqlType: SingleValue, +{ +} impl QueryFragment for DistinctOnClause where diff --git a/diesel_tests/tests/distinct.rs b/diesel_tests/tests/distinct.rs index ab2f99ecf3db..ccbc28c9cb2c 100644 --- a/diesel_tests/tests/distinct.rs +++ b/diesel_tests/tests/distinct.rs @@ -32,13 +32,30 @@ fn distinct_on() { .select((name, hair_color)) .order(name) .distinct_on(name); - let expected_data = vec![ + let mut expected_data = vec![ ("Sean".to_string(), Some("black".to_string())), ("Tess".to_string(), None), ]; let data: Vec<_> = source.load(connection).unwrap(); assert_eq!(expected_data, data); + + let source = users + .select((name, hair_color)) + .order(name.asc()) + .distinct_on(name); + let data: Vec<_> = source.load(connection).unwrap(); + + assert_eq!(expected_data, data); + + let source = users + .select((name, hair_color)) + .order(name.desc()) + .distinct_on(name); + let data: Vec<_> = source.load(connection).unwrap(); + + expected_data.reverse(); + assert_eq!(expected_data, data); } #[cfg(feature = "postgres")] From 6256d45adddc31a3951e62e1104f9f838633012b Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 29 Apr 2022 19:11:05 +0200 Subject: [PATCH 011/107] Fix #3151 Allow `ORDER BY` clauses to be used in any combination subquery by either put parenthesis around the subqueries (Postgres/Mysql) or adding a wrapping subquery (Sqlite). --- .../src/query_builder/combination_clause.rs | 30 +++++++++++-------- diesel_tests/tests/combination.rs | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/diesel/src/query_builder/combination_clause.rs b/diesel/src/query_builder/combination_clause.rs index 5435bd395e37..23a7002e0a6c 100644 --- a/diesel/src/query_builder/combination_clause.rs +++ b/diesel/src/query_builder/combination_clause.rs @@ -26,8 +26,8 @@ where pub struct CombinationClause { combinator: Combinator, duplicate_rule: Rule, - source: Source, - rhs: RhsParenthesisWrapper, + source: ParenthesisWrapper, + rhs: ParenthesisWrapper, } impl CombinationClause { @@ -41,8 +41,8 @@ impl CombinationClause QueryFragment where Combinator: QueryFragment, Rule: QueryFragment, - Source: QueryFragment, - RhsParenthesisWrapper: QueryFragment, + ParenthesisWrapper: QueryFragment, + ParenthesisWrapper: QueryFragment, DB: Backend + SupportsCombinationClause + DieselReserveSpecialization, { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> { @@ -215,7 +215,7 @@ pub trait SupportsCombinationClause {} #[derive(Debug, Copy, Clone, QueryId)] /// Wrapper used to wrap rhs sql in parenthesis when supported by backend -pub struct RhsParenthesisWrapper(T); +pub struct ParenthesisWrapper(T); #[cfg(feature = "postgres")] mod postgres { @@ -224,7 +224,7 @@ mod postgres { use crate::query_builder::{AstPass, QueryFragment}; use crate::QueryResult; - impl> QueryFragment for RhsParenthesisWrapper { + impl> QueryFragment for ParenthesisWrapper { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> { out.push_sql("("); self.0.walk_ast(out.reborrow())?; @@ -248,7 +248,7 @@ mod mysql { use crate::query_builder::{AstPass, QueryFragment}; use crate::QueryResult; - impl> QueryFragment for RhsParenthesisWrapper { + impl> QueryFragment for ParenthesisWrapper { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> { out.push_sql("("); self.0.walk_ast(out.reborrow())?; @@ -268,9 +268,15 @@ mod sqlite { use crate::sqlite::Sqlite; use crate::QueryResult; - impl> QueryFragment for RhsParenthesisWrapper { - fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> { - self.0.walk_ast(out) // SQLite does not support parenthesis around Ths + impl> QueryFragment for ParenthesisWrapper { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> { + // SQLite does not support parenthesis around Ths + // we can emulate this by construct a fake outer + // SELECT * FROM (inner_query) statement + out.push_sql("SELECT * FROM ("); + self.0.walk_ast(out.reborrow())?; + out.push_sql(")"); + Ok(()) } } diff --git a/diesel_tests/tests/combination.rs b/diesel_tests/tests/combination.rs index 04893e26535b..262fcde7ebb5 100644 --- a/diesel_tests/tests/combination.rs +++ b/diesel_tests/tests/combination.rs @@ -116,3 +116,33 @@ fn except() { .unwrap(); assert_eq!(expected_data, data); } + +#[test] +fn union_with_order() { + let conn = &mut connection(); + let data = vec![ + NewUser::new("Sean", None), + NewUser::new("Tess", None), + NewUser::new("Jim", None), + ]; + insert_into(users::table) + .values(&data) + .execute(conn) + .unwrap(); + + let users = users::table + .select(users::name) + .order_by(users::id.asc()) + .limit(1) + .union( + users::table + .order_by(users::id.desc()) + .select(users::name) + .limit(1), + ) + .positional_order_by(1) + .load::(conn) + .unwrap(); + + assert_eq!(vec![String::from("Jim"), "Sean".into()], users); +} From 3228fece0133f619232d57e9064b9e7534c8c05e Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 29 Apr 2022 20:51:48 +0200 Subject: [PATCH 012/107] Fix compile tests --- diesel_compile_tests/Cargo.lock | 4 ++-- .../fail/distinct_on_requires_matching_order_clause.stderr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock index 010398bff0b8..502c4cfe96a6 100644 --- a/diesel_compile_tests/Cargo.lock +++ b/diesel_compile_tests/Cargo.lock @@ -51,7 +51,7 @@ dependencies = [ [[package]] name = "diesel" -version = "2.0.0" +version = "2.0.0-rc.0" dependencies = [ "bigdecimal", "bitflags", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.0.0" +version = "2.0.0-rc.0" dependencies = [ "proc-macro-error", "proc-macro2", diff --git a/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr b/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr index 0441b7d7725c..94bcfb7b03b6 100644 --- a/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr +++ b/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr @@ -27,7 +27,7 @@ error[E0277]: the trait bound `diesel::query_builder::order_clause::OrderClause< as query_dsl::order_dsl::ValidOrderingForDistinct>> as query_dsl::order_dsl::ValidOrderingForDistinct>> as query_dsl::order_dsl::ValidOrderingForDistinct>> - and 14 others + and 18 others = note: required because of the requirements on the impl of `OrderDsl` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, DistinctOnClause>` error[E0308]: mismatched types @@ -59,5 +59,5 @@ error[E0277]: the trait bound `diesel::query_builder::order_clause::OrderClause< as query_dsl::order_dsl::ValidOrderingForDistinct>> as query_dsl::order_dsl::ValidOrderingForDistinct>> as query_dsl::order_dsl::ValidOrderingForDistinct>> - and 14 others + and 18 others = note: required because of the requirements on the impl of `OrderDsl` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, DistinctOnClause>` From f1b29e1f0c84965f98ec13eaa14a0218554e7db9 Mon Sep 17 00:00:00 2001 From: Otto Castle Date: Sun, 1 May 2022 11:00:55 +0100 Subject: [PATCH 013/107] add concat, like and not like for Postgres Binary type --- .../src/pg/expression/expression_methods.rs | 180 +++++++++++++++++- diesel/src/pg/expression/helper_types.rs | 16 +- diesel/src/pg/expression/operators.rs | 5 +- 3 files changed, 197 insertions(+), 4 deletions(-) diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs index 939e1403e7ca..e6ceed27fa4d 100644 --- a/diesel/src/pg/expression/expression_methods.rs +++ b/diesel/src/pg/expression/expression_methods.rs @@ -10,7 +10,8 @@ use crate::dsl; use crate::expression::grouped::Grouped; use crate::expression::operators::{Asc, Desc}; use crate::expression::{AsExpression, Expression, IntoSql, TypedExpressionType}; -use crate::sql_types::{Array, Inet, Integer, Jsonb, SqlType, Text, VarChar}; +use crate::pg::expression::expression_methods::private::BinaryOrNullableBinary; +use crate::sql_types::{Array, Binary, Inet, Integer, Jsonb, SqlType, Text, VarChar}; use crate::EscapeExpressionMethods; /// PostgreSQL specific methods which are present on all expressions. @@ -2177,9 +2178,179 @@ where { } +/// PostgreSQL specific methods present on Binary expressions. +#[cfg(feature = "postgres_backend")] +pub trait PgBinaryExpressionMethods: Expression + Sized { + /// Concatenates two PostgreSQL byte arrays using the `||` operator. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # table! { + /// # users { + /// # id -> Integer, + /// # name -> Binary, + /// # hair_color -> Nullable, + /// # } + /// # } + /// # + /// # fn main() { + /// # use self::users::dsl::*; + /// # use diesel::insert_into; + /// # + /// # let connection = &mut connection_no_data(); + /// # diesel::sql_query("CREATE TABLE users ( + /// # id INTEGER PRIMARY KEY, + /// # name BYTEA NOT NULL, + /// # hair_color BYTEA + /// # )").execute(connection).unwrap(); + /// # + /// # insert_into(users) + /// # .values(&vec![ + /// # (id.eq(1), name.eq("Sean".as_bytes()), Some(hair_color.eq(Some("Green".as_bytes())))), + /// # (id.eq(2), name.eq("Tess".as_bytes()), None), + /// # ]) + /// # .execute(connection) + /// # .unwrap(); + /// # + /// let names = users.select(name.concat(" the Greatest".as_bytes())).load(connection); + /// let expected_names = vec![ + /// b"Sean the Greatest".to_vec(), + /// b"Tess the Greatest".to_vec() + /// ]; + /// assert_eq!(Ok(expected_names), names); + /// + /// // If the value is nullable, the output will be nullable + /// let names = users.select(hair_color.concat("ish".as_bytes())).load(connection); + /// let expected_names = vec![ + /// Some(b"Greenish".to_vec()), + /// None, + /// ]; + /// assert_eq!(Ok(expected_names), names); + /// # } + /// ``` + fn concat(self, other: T) -> dsl::ConcatBinary + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(ConcatBinary::new(self, other.as_expression())) + } + + /// Creates a PostgreSQL binary `LIKE` expression. + /// + /// This method is case sensitive. There is no case-insensitive + /// equivalent as of PostgreSQL 14. + /// + /// # Examples + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # table! { + /// # users { + /// # id -> Integer, + /// # name -> Binary, + /// # } + /// # } + /// # + /// # fn main() { + /// # use self::users::dsl::*; + /// # use diesel::insert_into; + /// # + /// # let connection = &mut connection_no_data(); + /// # diesel::sql_query("CREATE TABLE users ( + /// # id INTEGER PRIMARY KEY, + /// # name BYTEA NOT NULL + /// # )").execute(connection).unwrap(); + /// # + /// # insert_into(users) + /// # .values(&vec![ + /// # (id.eq(1), name.eq("Sean".as_bytes())), + /// # (id.eq(2), name.eq("Tess".as_bytes())) + /// # ]) + /// # .execute(connection) + /// # .unwrap(); + /// # + /// let starts_with_s = users + /// .select(name) + /// .filter(name.like(b"S%".to_vec())) + /// .load(connection); + /// assert_eq!(Ok(vec![b"Sean".to_vec()]), starts_with_s); + /// # } + /// ``` + fn like(self, other: T) -> dsl::LikeBinary + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(LikeBinary::new(self, other.as_expression())) + } + + /// Creates a PostgreSQL binary `LIKE` expression. + /// + /// This method is case sensitive. There is no case-insensitive + /// equivalent as of PostgreSQL 14. + /// + /// # Examples + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # table! { + /// # users { + /// # id -> Integer, + /// # name -> Binary, + /// # } + /// # } + /// # + /// # fn main() { + /// # use self::users::dsl::*; + /// # use diesel::insert_into; + /// # + /// # let connection = &mut connection_no_data(); + /// # diesel::sql_query("CREATE TABLE users ( + /// # id INTEGER PRIMARY KEY, + /// # name BYTEA NOT NULL + /// # )").execute(connection).unwrap(); + /// # + /// # insert_into(users) + /// # .values(&vec![ + /// # (id.eq(1), name.eq("Sean".as_bytes())), + /// # (id.eq(2), name.eq("Tess".as_bytes())) + /// # ]) + /// # .execute(connection) + /// # .unwrap(); + /// # + /// let starts_with_s = users + /// .select(name) + /// .filter(name.not_like(b"S%".to_vec())) + /// .load(connection); + /// assert_eq!(Ok(vec![b"Tess".to_vec()]), starts_with_s); + /// # } + /// ``` + fn not_like(self, other: T) -> dsl::NotLikeBinary + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(NotLikeBinary::new(self, other.as_expression())) + } +} + +#[doc(hidden)] +impl PgBinaryExpressionMethods for T +where + T: Expression, + T::SqlType: BinaryOrNullableBinary, +{ +} + mod private { use crate::sql_types::{ - Array, Cidr, Inet, Integer, Json, Jsonb, Nullable, Range, SqlType, Text, + Array, Binary, Cidr, Inet, Integer, Json, Jsonb, Nullable, Range, SqlType, Text, }; use crate::{Expression, IntoSql}; @@ -2361,4 +2532,9 @@ mod private { pub trait TextOrInteger {} impl TextOrInteger for Text {} impl TextOrInteger for Integer {} + + pub trait BinaryOrNullableBinary {} + + impl BinaryOrNullableBinary for Binary {} + impl BinaryOrNullableBinary for Nullable {} } diff --git a/diesel/src/pg/expression/helper_types.rs b/diesel/src/pg/expression/helper_types.rs index 374058ad5db9..be3a4f3f74c2 100644 --- a/diesel/src/pg/expression/helper_types.rs +++ b/diesel/src/pg/expression/helper_types.rs @@ -1,7 +1,7 @@ use crate::dsl::{AsExpr, AsExprOf, SqlTypeOf}; use crate::expression::grouped::Grouped; use crate::pg::types::sql_types::Array; -use crate::sql_types::{Inet, Integer, Jsonb, VarChar}; +use crate::sql_types::{Binary, Inet, Integer, Jsonb, VarChar}; /// The return type of [`lhs.ilike(rhs)`](super::expression_methods::PgTextExpressionMethods::ilike) #[cfg(feature = "postgres_backend")] @@ -170,3 +170,17 @@ pub type RetrieveByPathAsTextJson = #[cfg(feature = "postgres_backend")] pub type RemoveByPathFromJsonb = Grouped>>>; + +/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::concat) +#[cfg(feature = "postgres_backend")] +pub type ConcatBinary = + Grouped>>; + +/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::like) +#[cfg(feature = "postgres_backend")] +pub type LikeBinary = Grouped>>; + +/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::not_like) +#[cfg(feature = "postgres_backend")] +pub type NotLikeBinary = + Grouped>>; diff --git a/diesel/src/pg/expression/operators.rs b/diesel/src/pg/expression/operators.rs index 83db89d46eb1..ea99bf376ecf 100644 --- a/diesel/src/pg/expression/operators.rs +++ b/diesel/src/pg/expression/operators.rs @@ -5,7 +5,7 @@ use crate::pg::Pg; use crate::query_builder::update_statement::changeset::AssignmentTarget; use crate::query_builder::{AstPass, QueryFragment, QueryId}; use crate::sql_types::{ - Array, Bigint, Bool, DieselNumericOps, Inet, Integer, Jsonb, SqlType, Text, + Array, Bigint, Binary, Bool, DieselNumericOps, Inet, Integer, Jsonb, SqlType, Text, }; use crate::{Column, QueryResult}; @@ -49,6 +49,9 @@ __diesel_infix_operator!( ); infix_operator!(RetrieveByPathAsTextJson, " #>> ", Text, backend: Pg); infix_operator!(RemoveByPathFromJsonb, " #-", Jsonb, backend: Pg); +infix_operator!(ConcatBinary, " || ", Binary, backend: Pg); +infix_operator!(LikeBinary, " LIKE ", backend: Pg); +infix_operator!(NotLikeBinary, " NOT LIKE ", backend: Pg); #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)] #[doc(hidden)] From db88c11c457c519af47b96bb6fddf39d6e6992f3 Mon Sep 17 00:00:00 2001 From: Otto Castle Date: Sun, 1 May 2022 11:24:59 +0100 Subject: [PATCH 014/107] add compile test --- diesel_compile_tests/Cargo.lock | 4 +-- ...array_expressions_must_be_same_type.stderr | 14 ++++----- .../fail/find_requires_correct_type.stderr | 4 +-- ...quires_value_of_same_type_as_column.stderr | 2 +- ..._binary_expressions_only_usable_with_pg.rs | 30 +++++++++++++++++++ ...ary_expressions_only_usable_with_pg.stderr | 15 ++++++++++ 6 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs create mode 100644 diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock index 010398bff0b8..502c4cfe96a6 100644 --- a/diesel_compile_tests/Cargo.lock +++ b/diesel_compile_tests/Cargo.lock @@ -51,7 +51,7 @@ dependencies = [ [[package]] name = "diesel" -version = "2.0.0" +version = "2.0.0-rc.0" dependencies = [ "bigdecimal", "bitflags", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.0.0" +version = "2.0.0-rc.0" dependencies = [ "proc-macro-error", "proc-macro2", diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr index 19531cbf9017..a8e03f7dabb2 100644 --- a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr +++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr @@ -110,7 +110,7 @@ error[E0277]: the trait bound `{integer}: SelectableExpression` is <(T0, T1) as SelectableExpression> <(T0, T1, T2) as SelectableExpression> <(T0, T1, T2, T3) as SelectableExpression> - and 155 others + and 158 others = note: required because of the requirements on the impl of `SelectableExpression` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound), diesel::sql_types::Double>` @@ -134,7 +134,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied <(T0, T1) as ValidGrouping<__GroupByClause>> <(T0, T1, T2) as ValidGrouping<__GroupByClause>> <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>> - and 140 others + and 143 others = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound), diesel::sql_types::Double>` @@ -152,7 +152,7 @@ error[E0277]: the trait bound `{integer}: SelectableExpression` is <(T0, T1) as SelectableExpression> <(T0, T1, T2) as SelectableExpression> <(T0, T1, T2, T3) as SelectableExpression> - and 155 others + and 158 others = note: required because of the requirements on the impl of `SelectableExpression` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound), diesel::sql_types::Double>` @@ -171,7 +171,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied <(T0, T1) as ValidGrouping<__GroupByClause>> <(T0, T1, T2) as ValidGrouping<__GroupByClause>> <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>> - and 140 others + and 143 others = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound), diesel::sql_types::Double>` @@ -189,7 +189,7 @@ error[E0277]: the trait bound `{integer}: QueryFragment` is not satisfied <() as QueryFragment> <(T0, T1) as QueryFragment<__DB>> <(T0, T1, T2) as QueryFragment<__DB>> - and 269 others + and 272 others = note: required because of the requirements on the impl of `QueryFragment` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `SelectStatement), diesel::sql_types::Double>>>` @@ -206,7 +206,7 @@ error[E0277]: the trait bound `{integer}: QueryId` is not satisfied <() as QueryId> <(T0, T1) as QueryId> <(T0, T1, T2) as QueryId> - and 231 others + and 234 others = note: required because of the requirements on the impl of `QueryId` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `QueryId` for `SelectStatement), diesel::sql_types::Double>>>` @@ -228,6 +228,6 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied <(T0, T1) as diesel::Expression> <(T0, T1, T2) as diesel::Expression> <(T0, T1, T2, T3) as diesel::Expression> - and 120 others + and 123 others = note: required because of the requirements on the impl of `AsExpression` for `{integer}` = note: required because of the requirements on the impl of `AsExpressionList` for `({integer}, f64)` diff --git a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr index 474029af0af7..2a109d996122 100644 --- a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr +++ b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr @@ -32,7 +32,7 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied <(T0, T1) as diesel::Expression> <(T0, T1, T2) as diesel::Expression> <(T0, T1, T2, T3) as diesel::Expression> - and 124 others + and 127 others = note: required because of the requirements on the impl of `diesel::Expression` for `diesel::expression::operators::Eq` = note: required because of the requirements on the impl of `FilterDsl>>` for `SelectStatement>` @@ -47,7 +47,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied <(T0, T1) as ValidGrouping<__GroupByClause>> <(T0, T1, T2) as ValidGrouping<__GroupByClause>> <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>> - and 146 others + and 149 others = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::operators::Eq` = note: required because of the requirements on the impl of `NonAggregate` for `diesel::expression::grouped::Grouped>` = note: required because of the requirements on the impl of `FilterDsl>>` for `SelectStatement>` diff --git a/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr b/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr index e5677bc9515c..cab95e1a46c7 100644 --- a/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr +++ b/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr @@ -9,5 +9,5 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied <(T0, T1) as diesel::Expression> <(T0, T1, T2) as diesel::Expression> <(T0, T1, T2, T3) as diesel::Expression> - and 124 others + and 127 others = note: required because of the requirements on the impl of `AsExpression` for `{integer}` diff --git a/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs new file mode 100644 index 000000000000..9154c1de34fa --- /dev/null +++ b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs @@ -0,0 +1,30 @@ +extern crate diesel; + +use diesel::prelude::*; + +table! { + users { + id -> Integer, + name -> Binary, + } +} + +fn main() { + use self::users::dsl::*; + + let mut connection = SqliteConnection::establish("").unwrap(); + + users + .select(name.concat(b"foo".to_vec())) + .filter(name.like(b"bar".to_vec())) + .filter(name.not_like(b"baz".to_vec())) + .get_result::>(&mut connection).unwrap(); + + let mut connection = MysqlConnection::establish("").unwrap(); + + users + .select(name.concat(b"foo".to_vec())) + .filter(name.like(b"bar".to_vec())) + .filter(name.not_like(b"baz".to_vec())) + .get_result::>(&mut connection).unwrap(); +} diff --git a/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr new file mode 100644 index 000000000000..329e659f6af0 --- /dev/null +++ b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `::Backend == Pg` + --> tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs:21:10 + | +21 | .get_result::>(&mut connection).unwrap(); + | ^^^^^^^^^^ expected struct `Sqlite`, found struct `Pg` + | + = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, Vec>` for `SelectStatement, diesel::query_builder::select_clause::SelectClause>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>, diesel::expression::grouped::Grouped>>>>>>>` + +error[E0271]: type mismatch resolving `::Backend == Pg` + --> tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs:29:10 + | +29 | .get_result::>(&mut connection).unwrap(); + | ^^^^^^^^^^ expected struct `Mysql`, found struct `Pg` + | + = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::MysqlConnection, Vec>` for `SelectStatement, diesel::query_builder::select_clause::SelectClause>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>, diesel::expression::grouped::Grouped>>>>>>>` From fb70fd70791010ab9fe8d02c21d78d6946f16dd7 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 2 May 2022 16:36:11 +0200 Subject: [PATCH 015/107] Fix #3156 Our `R2D2Connection::is_broken` implementations where broken in such a way that they marked any valid connection as broken as soon as it was checked into the pool again. This resulted in the pool opening new connections everytime a connection was checked out of the pool, which obviously removes the possibility of reusing the same connection again and again. This commit fixes that issue and adds some tests to ensure that we do not break this again in the future. --- diesel/src/mysql/connection/mod.rs | 2 +- diesel/src/pg/connection/mod.rs | 2 +- diesel/src/r2d2.rs | 144 ++++++++++++++++++++++++---- diesel/src/sqlite/connection/mod.rs | 2 +- 4 files changed, 128 insertions(+), 22 deletions(-) diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs index 7e5bc4746690..8c8568aa94a0 100644 --- a/diesel/src/mysql/connection/mod.rs +++ b/diesel/src/mysql/connection/mod.rs @@ -147,7 +147,7 @@ impl crate::r2d2::R2D2Connection for MysqlConnection { self.transaction_state .status .transaction_depth() - .map(|d| d.is_none()) + .map(|d| d.is_some()) .unwrap_or(true) } } diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs index c1a6cf3c8b44..d55724b69cd4 100644 --- a/diesel/src/pg/connection/mod.rs +++ b/diesel/src/pg/connection/mod.rs @@ -180,7 +180,7 @@ impl crate::r2d2::R2D2Connection for PgConnection { self.transaction_state .status .transaction_depth() - .map(|d| d.is_none()) + .map(|d| d.is_some()) .unwrap_or(true) } } diff --git a/diesel/src/r2d2.rs b/diesel/src/r2d2.rs index ddac7c96e818..62f5efb9eb10 100644 --- a/diesel/src/r2d2.rs +++ b/diesel/src/r2d2.rs @@ -327,6 +327,28 @@ where } } +#[derive(QueryId)] +pub(crate) struct CheckConnectionQuery; + +impl QueryFragment for CheckConnectionQuery +where + DB: Backend, +{ + fn walk_ast<'b>( + &'b self, + mut pass: crate::query_builder::AstPass<'_, 'b, DB>, + ) -> QueryResult<()> { + pass.push_sql("SELECT 1"); + Ok(()) + } +} + +impl Query for CheckConnectionQuery { + type SqlType = crate::sql_types::Integer; +} + +impl RunQueryDsl for CheckConnectionQuery {} + #[cfg(test)] mod tests { use std::sync::mpsc; @@ -394,26 +416,110 @@ mod tests { let query = select("foo".into_sql::()); assert_eq!("foo", query.get_result::(&mut conn).unwrap()); } -} -#[derive(QueryId)] -pub(crate) struct CheckConnectionQuery; + #[test] + fn check_pool_does_actually_hold_connections() { + use std::sync::atomic::{AtomicU32, Ordering}; + + #[derive(Debug)] + struct TestEventHandler { + acquire_count: Arc, + release_count: Arc, + checkin_count: Arc, + checkout_count: Arc, + } -impl QueryFragment for CheckConnectionQuery -where - DB: Backend, -{ - fn walk_ast<'b>( - &'b self, - mut pass: crate::query_builder::AstPass<'_, 'b, DB>, - ) -> QueryResult<()> { - pass.push_sql("SELECT 1"); - Ok(()) - } -} + impl r2d2::HandleEvent for TestEventHandler { + fn handle_acquire(&self, _event: r2d2::event::AcquireEvent) { + self.acquire_count.fetch_add(1, Ordering::Relaxed); + } + fn handle_release(&self, _event: r2d2::event::ReleaseEvent) { + self.release_count.fetch_add(1, Ordering::Relaxed); + } + fn handle_checkout(&self, _event: r2d2::event::CheckoutEvent) { + self.checkout_count.fetch_add(1, Ordering::Relaxed); + } + fn handle_checkin(&self, _event: r2d2::event::CheckinEvent) { + self.checkin_count.fetch_add(1, Ordering::Relaxed); + } + } -impl Query for CheckConnectionQuery { - type SqlType = crate::sql_types::Integer; -} + let acquire_count = Arc::new(AtomicU32::new(0)); + let release_count = Arc::new(AtomicU32::new(0)); + let checkin_count = Arc::new(AtomicU32::new(0)); + let checkout_count = Arc::new(AtomicU32::new(0)); -impl RunQueryDsl for CheckConnectionQuery {} + let handler = Box::new(TestEventHandler { + acquire_count: acquire_count.clone(), + release_count: release_count.clone(), + checkin_count: checkin_count.clone(), + checkout_count: checkout_count.clone(), + }); + + let manager = ConnectionManager::::new(database_url()); + let pool = Pool::builder() + .max_size(1) + .test_on_check_out(true) + .event_handler(handler) + .build(manager) + .unwrap(); + + assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + assert_eq!(release_count.load(Ordering::Relaxed), 0); + assert_eq!(checkin_count.load(Ordering::Relaxed), 0); + assert_eq!(checkout_count.load(Ordering::Relaxed), 0); + + // check that we reuse connections with the pool + { + let conn = pool.get().unwrap(); + + assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + assert_eq!(release_count.load(Ordering::Relaxed), 0); + assert_eq!(checkin_count.load(Ordering::Relaxed), 0); + assert_eq!(checkout_count.load(Ordering::Relaxed), 1); + std::mem::drop(conn); + } + + assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + assert_eq!(release_count.load(Ordering::Relaxed), 0); + assert_eq!(checkin_count.load(Ordering::Relaxed), 1); + assert_eq!(checkout_count.load(Ordering::Relaxed), 1); + + // check that we remove a connection with open transactions from the pool + { + let mut conn = pool.get().unwrap(); + + assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + assert_eq!(release_count.load(Ordering::Relaxed), 0); + assert_eq!(checkin_count.load(Ordering::Relaxed), 1); + assert_eq!(checkout_count.load(Ordering::Relaxed), 2); + + ::TransactionManager::begin_transaction(&mut *conn) + .unwrap(); + } + + assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + assert_eq!(release_count.load(Ordering::Relaxed), 1); + assert_eq!(checkin_count.load(Ordering::Relaxed), 2); + assert_eq!(checkout_count.load(Ordering::Relaxed), 2); + + // check that we remove a connection from the pool that was + // open during panicing + #[allow(unreachable_code, unused_variables)] + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let conn = pool.get(); + assert_eq!(acquire_count.load(Ordering::Relaxed), 2); + assert_eq!(release_count.load(Ordering::Relaxed), 1); + assert_eq!(checkin_count.load(Ordering::Relaxed), 2); + assert_eq!(checkout_count.load(Ordering::Relaxed), 3); + panic!(); + std::mem::drop(conn); + })) + .unwrap_err(); + + assert_eq!(acquire_count.load(Ordering::Relaxed), 2); + assert_eq!(release_count.load(Ordering::Relaxed), 2); + assert_eq!(checkin_count.load(Ordering::Relaxed), 3); + assert_eq!(checkout_count.load(Ordering::Relaxed), 3); + } +} diff --git a/diesel/src/sqlite/connection/mod.rs b/diesel/src/sqlite/connection/mod.rs index 3d85958519ba..e85ac7883c89 100644 --- a/diesel/src/sqlite/connection/mod.rs +++ b/diesel/src/sqlite/connection/mod.rs @@ -144,7 +144,7 @@ impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection { self.transaction_state .status .transaction_depth() - .map(|d| d.is_none()) + .map(|d| d.is_some()) .unwrap_or(true) } } From 353b408db8faa67194ad1044f4f07a40070dfb32 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 3 May 2022 17:33:12 +0200 Subject: [PATCH 016/107] Apply suggestions from PR review --- diesel/src/mysql/connection/mod.rs | 14 +++++++++----- diesel/src/pg/connection/mod.rs | 14 +++++++++----- diesel/src/sqlite/connection/mod.rs | 14 +++++++++----- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs index 8c8568aa94a0..7cc7a7140b90 100644 --- a/diesel/src/mysql/connection/mod.rs +++ b/diesel/src/mysql/connection/mod.rs @@ -144,11 +144,15 @@ impl crate::r2d2::R2D2Connection for MysqlConnection { } fn is_broken(&mut self) -> bool { - self.transaction_state - .status - .transaction_depth() - .map(|d| d.is_some()) - .unwrap_or(true) + match self.transaction_state.status.transaction_depth() { + // all transactions are closed + // so we don't consider this connection broken + Ok(None) => false, + // The transaction manager is in an error state + // or contains an open transaction + // Therefore we consider this connection broken + Err(_) | Ok(Some(_)) => true, + } } } diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs index d55724b69cd4..fcd608b4ab6b 100644 --- a/diesel/src/pg/connection/mod.rs +++ b/diesel/src/pg/connection/mod.rs @@ -177,11 +177,15 @@ impl crate::r2d2::R2D2Connection for PgConnection { } fn is_broken(&mut self) -> bool { - self.transaction_state - .status - .transaction_depth() - .map(|d| d.is_some()) - .unwrap_or(true) + match self.transaction_state.status.transaction_depth() { + // all transactions are closed + // so we don't consider this connection broken + Ok(None) => false, + // The transaction manager is in an error state + // or contains an open transaction + // Therefore we consider this connection broken + Err(_) | Ok(Some(_)) => true, + } } } diff --git a/diesel/src/sqlite/connection/mod.rs b/diesel/src/sqlite/connection/mod.rs index e85ac7883c89..b6dffcb87f2b 100644 --- a/diesel/src/sqlite/connection/mod.rs +++ b/diesel/src/sqlite/connection/mod.rs @@ -141,11 +141,15 @@ impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection { } fn is_broken(&mut self) -> bool { - self.transaction_state - .status - .transaction_depth() - .map(|d| d.is_some()) - .unwrap_or(true) + match self.transaction_state.status.transaction_depth() { + // all transactions are closed + // so we don't consider this connection broken + Ok(None) => false, + // The transaction manager is in an error state + // or contains an open transaction + // Therefore we consider this connection broken + Err(_) | Ok(Some(_)) => true, + } } } From 61351f779a3076bfa8b8cecdea19caa560fc95fc Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 3 May 2022 22:20:33 +0200 Subject: [PATCH 017/107] Optimise build times This commit replaces some recursive macros with simpler implementations by generating non recursive where clauses by just forwarding to the next smaller impl on the corresponding tuple. According to my measurements this reduces the build time for a `cargo check --no-default-features --features "sqlite 64-column-table"` build from ~1min 20s to ~1min 05s. --- .../insert_with_default_for_sqlite.rs | 46 ++---------- diesel/src/type_impls/tuples.rs | 71 ++++++------------- 2 files changed, 29 insertions(+), 88 deletions(-) diff --git a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs index 23b9960c7bcc..c992b1bdd9fb 100644 --- a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs +++ b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs @@ -357,46 +357,14 @@ macro_rules! tuple_impls { } macro_rules! impl_contains_defaultable_value { - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident,], - bounds = [$($bounds: tt)*], - out = [$($out: tt)*], - )=> { - impl<$($ST,)*> ContainsDefaultableValue for ($($ST,)*) - where - $($ST: ContainsDefaultableValue,)* - $($bounds)* - $T1::Out: Any<$($out)*>, - { - type Out = <$T1::Out as Any<$($out)*>>::Out; - } - - }; - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident, $($T: ident,)+], - bounds = [$($bounds: tt)*], - out = [$($out: tt)*], - )=> { - impl_contains_defaultable_value! { - @build - start_ts = [$($ST,)*], - ts = [$($T,)*], - bounds = [$($bounds)* $T1::Out: Any<$($out)*>,], - out = [<$T1::Out as Any<$($out)*>>::Out], - } - }; ($T1: ident, $($T: ident,)+) => { - impl_contains_defaultable_value! { - @build - start_ts = [$T1, $($T,)*], - ts = [$($T,)*], - bounds = [], - out = [$T1::Out], - } + impl<$T1, $($T,)*> ContainsDefaultableValue for ($T1, $($T,)*) + where $T1: ContainsDefaultableValue, + ($($T,)*): ContainsDefaultableValue, + $T1::Out: Any<<($($T,)*) as ContainsDefaultableValue>::Out> + { + type Out = <$T1::Out as Any<<($($T,)*) as ContainsDefaultableValue>::Out>>::Out; + } }; ($T1: ident,) => { impl<$T1> ContainsDefaultableValue for ($T1,) diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs index df6af762ed78..d35f4a597f40 100644 --- a/diesel/src/type_impls/tuples.rs +++ b/diesel/src/type_impls/tuples.rs @@ -5,8 +5,8 @@ use crate::deserialize::{ }; use crate::expression::{ is_contained_in_group_by, AppearsOnTable, AsExpression, AsExpressionList, Expression, - IsContainedInGroupBy, QueryMetadata, Selectable, SelectableExpression, TypedExpressionType, - ValidGrouping, + IsContainedInGroupBy, MixedAggregates, QueryMetadata, Selectable, SelectableExpression, + TypedExpressionType, ValidGrouping, }; use crate::insertable::{CanInsertInSingleQuery, InsertValues, Insertable, InsertableOptionHelper}; use crate::query_builder::*; @@ -114,12 +114,6 @@ macro_rules! tuple_impls { const HAS_STATIC_QUERY_ID: bool = $($T::HAS_STATIC_QUERY_ID &&)+ true; } - const _: () = { - #[derive(ValidGrouping)] - #[diesel(foreign_derive)] - struct TupleWrapper<$($T,)*>(($($T,)*)); - }; - impl_valid_grouping_for_tuple_of_columns!($($T,)*); impl<$($T,)+ Tab> UndecoratedInsertRecord for ($($T,)+) @@ -453,49 +447,22 @@ macro_rules! impl_from_sql_row { } macro_rules! impl_valid_grouping_for_tuple_of_columns { - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident,], - bounds = [$($bounds: tt)*], - is_aggregate = [$($is_aggregate: tt)*], - ) => { - impl<$($ST,)* Col> IsContainedInGroupByfor ($($ST,)*) - where Col: Column, - $($ST: IsContainedInGroupBy,)* - $($bounds)* - <$T1 as IsContainedInGroupBy>::Output: is_contained_in_group_by::IsAny<$($is_aggregate)*>, + ($T1: ident, $($T: ident,)+) => { + impl<$T1, $($T,)* GB> ValidGrouping for ($T1, $($T,)*) + where + $T1: ValidGrouping, + ($($T,)*): ValidGrouping, + $T1::IsAggregate: MixedAggregates<<($($T,)*) as ValidGrouping>::IsAggregate>, { - type Output = <<$T1 as IsContainedInGroupBy>::Output as is_contained_in_group_by::IsAny<$($is_aggregate)*>>::Output; + type IsAggregate = <$T1::IsAggregate as MixedAggregates<<($($T,)*) as ValidGrouping>::IsAggregate>>::Output; } - }; - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident, $($T: ident,)+], - bounds = [$($bounds: tt)*], - is_aggregate = [$($is_aggregate: tt)*], - ) => { - impl_valid_grouping_for_tuple_of_columns! { - @build - start_ts = [$($ST,)*], - ts = [$($T,)*], - bounds = [ - $($bounds)* - <$T1 as IsContainedInGroupBy>::Output: is_contained_in_group_by::IsAny<$($is_aggregate)*>, - ], - is_aggregate = [ - <<$T1 as IsContainedInGroupBy>::Output as is_contained_in_group_by::IsAny<$($is_aggregate)*>>::Output - ], - } - }; - ($T1: ident, $($T: ident,)+) => { - impl_valid_grouping_for_tuple_of_columns! { - @build - start_ts = [$T1, $($T,)*], - ts = [$($T,)*], - bounds = [], - is_aggregate = [<$T1 as IsContainedInGroupBy>::Output], + impl<$T1, $($T,)* Col> IsContainedInGroupByfor ($T1, $($T,)*) + where Col: Column, + ($($T,)*): IsContainedInGroupBy, + $T1: IsContainedInGroupBy, + $T1::Output: is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy>::Output> + { + type Output = <$T1::Output as is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy>::Output>>::Output; } }; ($T1: ident,) => { @@ -505,6 +472,12 @@ macro_rules! impl_valid_grouping_for_tuple_of_columns { { type Output = <$T1 as IsContainedInGroupBy>::Output; } + + impl<$T1, GB> ValidGrouping for ($T1,) + where $T1: ValidGrouping + { + type IsAggregate = $T1::IsAggregate; + } }; } From fb3142500d96849c984a8c6aeabdd7ae5cf723fc Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Tue, 3 May 2022 19:27:11 -0400 Subject: [PATCH 018/107] WIP implementation of ipnet based conversions --- diesel/Cargo.toml | 2 + diesel/src/lib.rs | 8 +- diesel/src/pg/types/ipnet_address.rs | 273 +++++++++++++++++++++++++++ diesel/src/pg/types/mod.rs | 51 ++--- diesel_tests/Cargo.toml | 3 +- 5 files changed, 312 insertions(+), 25 deletions(-) create mode 100644 diesel/src/pg/types/ipnet_address.rs diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 78341f1eba8e..fbff1fd65e38 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -25,6 +25,7 @@ url = { version = "2.1.0", optional = true } percent-encoding = { version = "2.1.0", optional = true } uuid = { version = ">=0.7.0, <2.0.0", optional = true } ipnetwork = { version = ">=0.12.2, <0.19.0", optional = true } +ipnet = { version = "2.5.0", optional = true } num-bigint = { version = ">=0.2.0, <0.5.0", optional = true } num-traits = { version = "0.2.0", optional = true } num-integer = { version = "0.1.39", optional = true } @@ -58,6 +59,7 @@ mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backen without-deprecated = ["diesel_derives/without-deprecated"] with-deprecated = ["diesel_derives/with-deprecated"] network-address = ["ipnetwork", "libc"] +ipnet-address = ["ipnet", "libc"] numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"] postgres_backend = ["diesel_derives/postgres", "bitflags", "byteorder", "itoa"] mysql_backend = ["diesel_derives/mysql", "byteorder"] diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index 1dc697aee1b8..e810d03d4eaf 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -140,8 +140,12 @@ //! types provided by `chrono` //! - `uuid`: This feature flag enables support for (de)serializing uuid values from the database using types //! provided by `uuid` -//! - `network-address`: This feature flag enables support for (de)serializing IP and Macadresse values from the -//! database using types provided by `ipnetwork` +//! - `network-address`: This feature flag enables support for (de)serializing +//! IP values from the database using types provided by `ipnetwork`. Mutually +//! exclusive with `ipnet-address. +//! - `ipnet-address`: This feature flag enables support for (de)serializing IP +//! values from the database using types provided by `ipnet`. Mutually exclusive +//! with `network-address. //! - `numeric`: This feature flag enables support for (de)serializing numeric values from the database using types //! provided by `bigdecimal` //! - `r2d2`: This feature flag enables support for the `r2d2` connection pool implementation. diff --git a/diesel/src/pg/types/ipnet_address.rs b/diesel/src/pg/types/ipnet_address.rs new file mode 100644 index 000000000000..76c6b292e3be --- /dev/null +++ b/diesel/src/pg/types/ipnet_address.rs @@ -0,0 +1,273 @@ +extern crate libc; + +use ipnet::{IpNet, Ipv4Net, Ipv6Net}; +use std::io::prelude::*; +use std::net::{Ipv4Addr, Ipv6Addr}; + +use crate::deserialize::{self, FromSql, FromSqlRow}; +use crate::pg::{Pg, PgValue}; +#[cfg(test)] +use crate::query_builder::bind_collector::ByteWrapper; +use crate::serialize::{self, IsNull, Output, ToSql}; +use crate::sql_types::{Cidr, Inet}; + +#[cfg(windows)] +const AF_INET: u8 = 2; +// Maybe not used, but defining to follow Rust's libstd/net/sys +#[cfg(target_os = "redox")] +const AF_INET: u8 = 1; +#[cfg(not(any(windows, target_os = "redox")))] +const AF_INET: u8 = libc::AF_INET as u8; + +const PGSQL_AF_INET: u8 = AF_INET; +const PGSQL_AF_INET6: u8 = AF_INET + 1; + +#[allow(dead_code)] +mod foreign_derives { + use super::*; + use crate::expression::AsExpression; + + #[derive(AsExpression, FromSqlRow)] + #[diesel(foreign_derive)] + #[diesel(sql_type = Inet)] + #[diesel(sql_type = Cidr)] + struct IpNetworkProxy(IpNet); +} + +macro_rules! err { + () => { + Err("invalid network address format".into()) + }; + ($msg:expr) => { + Err(format!("invalid network address format. {}", $msg).into()) + }; +} + +macro_rules! assert_or_error { + ($cond:expr) => { + if !$cond { + return err!(); + } + }; + + ($cond:expr, $msg:expr) => { + if !$cond { + return err!($msg); + } + }; +} + +macro_rules! impl_Sql { + ($ty: ty, $net_type: expr) => { + #[cfg(all(feature = "postgres_backend", feature = "ipnet-address"))] + impl FromSql<$ty, Pg> for IpNet { + fn from_sql(value: PgValue<'_>) -> deserialize::Result { + // https://github.com/postgres/postgres/blob/55c3391d1e6a201b5b891781d21fe682a8c64fe6/src/include/utils/inet.h#L23-L28 + let bytes = value.as_bytes(); + assert_or_error!(4 <= bytes.len(), "input is too short."); + let af = bytes[0]; + let prefix = bytes[1]; + let net_type = bytes[2]; + let len = bytes[3]; + assert_or_error!( + net_type == $net_type, + format!("returned type isn't a {}", stringify!($ty)) + ); + if af == PGSQL_AF_INET { + assert_or_error!(bytes.len() == 8); + assert_or_error!(len == 4, "the data isn't the size of ipv4"); + let b = &bytes[4..]; + let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]); + let inet = Ipv4Net::new(addr, prefix)?; + Ok(IpNet::V4(inet)) + } else if af == PGSQL_AF_INET6 { + assert_or_error!(bytes.len() == 20); + assert_or_error!(len == 16, "the data isn't the size of ipv6"); + let b = &bytes[4..]; + let addr = Ipv6Addr::from([ + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], + b[12], b[13], b[14], b[15], + ]); + let inet = Ipv6Net::new(addr, prefix)?; + Ok(IpNet::V6(inet)) + } else { + err!() + } + } + } + + #[cfg(all(feature = "postgres_backend", feature = "ipnet-address"))] + impl ToSql<$ty, Pg> for IpNet { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + let net_type = $net_type; + match *self { + IpNet::V4(ref net) => { + let mut data = [0u8; 8]; + let af = PGSQL_AF_INET; + let prefix = net.prefix_len(); + let len: u8 = 4; + let addr = net.network().octets(); + data[0] = af; + data[1] = prefix; + data[2] = net_type; + data[3] = len; + data[4..].copy_from_slice(&addr); + out.write_all(&data).map(|_| IsNull::No).map_err(Into::into) + } + IpNet::V6(ref net) => { + let mut data = [0u8; 20]; + let af = PGSQL_AF_INET6; + let prefix = net.prefix_len(); + let len: u8 = 16; + let addr = net.network().octets(); + data[0] = af; + data[1] = prefix; + data[2] = net_type; + data[3] = len; + data[4..].copy_from_slice(&addr); + out.write_all(&data).map(|_| IsNull::No).map_err(Into::into) + } + } + } + } + }; +} + +impl_Sql!(Inet, 0); +impl_Sql!(Cidr, 1); + +#[test] +fn v4address_to_sql() { + macro_rules! test_to_sql { + ($ty:ty, $net_type:expr) => { + let mut buffer = Vec::new(); + { + let mut bytes = Output::test(ByteWrapper(&mut buffer)); + let test_address = + IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap()); + ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap(); + } + assert_eq!(buffer, vec![PGSQL_AF_INET, 32, $net_type, 4, 127, 0, 0, 1]); + }; + } + + test_to_sql!(Inet, 0); + test_to_sql!(Cidr, 1); +} + +#[test] +fn some_v4address_from_sql() { + macro_rules! test_some_address_from_sql { + ($ty:tt) => { + let input_address = + IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap()); + let mut buffer = Vec::new(); + { + let mut bytes = Output::test(ByteWrapper(&mut buffer)); + ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap(); + } + let output_address = FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap(); + assert_eq!(input_address, output_address); + }; + } + + test_some_address_from_sql!(Cidr); + test_some_address_from_sql!(Inet); +} + +#[test] +fn v6address_to_sql() { + macro_rules! test_to_sql { + ($ty:ty, $net_type:expr) => { + let mut buffer = Vec::new(); + { + let mut bytes = Output::test(ByteWrapper(&mut buffer)); + let test_address = IpNet::V6( + Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap(), + ); + ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap(); + } + assert_eq!( + buffer, + vec![ + PGSQL_AF_INET6, + 64, + $net_type, + 16, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ] + ); + }; + } + + test_to_sql!(Inet, 0); + test_to_sql!(Cidr, 1); +} + +#[test] +fn some_v6address_from_sql() { + macro_rules! test_some_address_from_sql { + ($ty:tt) => { + let input_address = + IpNet::V6(Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap()); + let mut buffer = Vec::new(); + { + let mut bytes = Output::test(ByteWrapper(&mut buffer)); + ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap(); + } + let output_address = FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap(); + assert_eq!(input_address, output_address); + }; + } + + test_some_address_from_sql!(Inet); + test_some_address_from_sql!(Cidr); +} + +#[test] +fn bad_address_from_sql() { + macro_rules! bad_address_from_sql { + ($ty:tt) => { + let address: Result = + FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&[7, PGSQL_AF_INET, 0])); + assert_eq!( + address.unwrap_err().to_string(), + "invalid network address format. input is too short." + ); + }; + } + + bad_address_from_sql!(Inet); + bad_address_from_sql!(Cidr); +} + +#[test] +fn no_address_from_sql() { + macro_rules! test_no_address_from_sql { + ($ty:ty) => { + let address: Result = FromSql::<$ty, Pg>::from_nullable_sql(None); + assert_eq!( + address.unwrap_err().to_string(), + "Unexpected null for non-null column" + ); + }; + } + + test_no_address_from_sql!(Inet); + test_no_address_from_sql!(Cidr); +} diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index 919a43b50d18..94865c072e48 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -11,6 +11,8 @@ mod json; mod mac_addr; #[doc(hidden)] pub(in crate::pg) mod money; +#[cfg(feature = "ipnet-address")] +mod ipnet_address; #[cfg(feature = "network-address")] mod network_address; mod numeric; @@ -20,6 +22,9 @@ mod record; #[cfg(feature = "uuid")] mod uuid; +#[cfg(all(feature = "network-address", feature = "ipnet-address"))] +compile_error!("Features 'network-address' and 'ipnet-address' cannot be enabled at the same time"); + /// PostgreSQL specific SQL types /// /// Note: All types in this module can be accessed through `diesel::sql_types` @@ -404,23 +409,24 @@ pub mod sql_types { /// Alias for `MacAddr` to be able to use it with `infer_schema`. pub type Macaddr = MacAddr; - /// The [`INET`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` + /// The [`INET`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` or `feature = "ipnet-address"`. /// /// ### [`ToSql`] impls /// - /// - [`ipnetwork::IpNetwork`][IpNetwork] + #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")] + #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")] + #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")] /// /// ### [`FromSql`] impls /// - /// - [`ipnetwork::IpNetwork`][IpNetwork] + #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")] + #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")] + #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")] /// /// [`ToSql`]: crate::serialize::ToSql /// [`FromSql`]: crate::deserialize::FromSql #[cfg_attr(feature = "ipnetwork", doc = " [IpNetwork]: ipnetwork::IpNetwork")] - #[cfg_attr( - not(feature = "ipnetwork"), - doc = " [IpNetwork]: https://docs.rs/ipnetwork/*/ipnetwork/enum.IpNetwork.html" - )] + #[cfg_attr(feature = "ipnet", doc = " [IpNet]: ipnet::IpNet")] /// /// # Examples /// @@ -434,9 +440,8 @@ pub mod sql_types { /// } /// } /// - /// # #[cfg(feature = "network-address")] + /// # #[cfg(any(feature = "network-address", feature = "ipnet-address"))] /// # fn main() -> Result<(), Box> { - /// use ipnetwork::IpNetwork; /// /// # use diesel::insert_into; /// # use self::clients::dsl::*; @@ -445,7 +450,8 @@ pub mod sql_types { /// # id SERIAL PRIMARY KEY, /// # ip_address INET NOT NULL /// # )").execute(connection)?; - /// let addr = "10.1.9.32/32".parse::()?; + #[cfg_attr(feature = "ipnetwork", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] + #[cfg_attr(feature = "ipnet", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] /// let inserted_address = insert_into(clients) /// .values(ip_address.eq(&addr)) /// .returning(ip_address) @@ -454,7 +460,7 @@ pub mod sql_types { /// # Ok(()) /// # } /// # - /// # #[cfg(not(feature = "network-address"))] + /// # #[cfg(not(any(feature = "network-address", feature = "ipnet-address")))] /// # fn main() {} /// ``` #[cfg(feature = "postgres_backend")] @@ -462,23 +468,24 @@ pub mod sql_types { #[diesel(postgres_type(oid = 869, array_oid = 1041))] pub struct Inet; - /// The [`CIDR`](https://www.postgresql.org/docs/postgresql/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` + /// The [`CIDR`](https://www.postgresql.org/docs/postgresql/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` or `feature = "ipnet-address"`. /// /// ### [`ToSql`] impls /// - /// - [`ipnetwork::IpNetwork`][IpNetwork] + #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")] + #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")] + #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")] /// /// ### [`FromSql`] impls /// - /// - [`ipnetwork::IpNetwork`][IpNetwork] + #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")] + #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")] + #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")] /// /// [`ToSql`]: crate::serialize::ToSql /// [`FromSql`]: crate::deserialize::FromSql #[cfg_attr(feature = "ipnetwork", doc = " [IpNetwork]: ipnetwork::IpNetwork")] - #[cfg_attr( - not(feature = "ipnetwork"), - doc = " [IpNetwork]: https://docs.rs/ipnetwork/*/ipnetwork/enum.IpNetwork.html" - )] + #[cfg_attr(feature = "ipnet", doc = " [IpNet]: ipnet::IpNet")] /// /// # Examples /// @@ -492,9 +499,8 @@ pub mod sql_types { /// } /// } /// - /// # #[cfg(feature = "network-address")] + /// # #[cfg(any(feature = "network-address", feature = "ipnet-address"))] /// # fn main() -> Result<(), Box> { - /// use ipnetwork::IpNetwork; /// /// # use diesel::insert_into; /// # use self::clients::dsl::*; @@ -503,7 +509,8 @@ pub mod sql_types { /// # id SERIAL PRIMARY KEY, /// # ip_address CIDR NOT NULL /// # )").execute(connection)?; - /// let addr = "10.1.9.32/32".parse::()?; + #[cfg_attr(feature = "ipnetwork", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] + #[cfg_attr(feature = "ipnet", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] /// let inserted_addr = insert_into(clients) /// .values(ip_address.eq(&addr)) /// .returning(ip_address) @@ -511,7 +518,7 @@ pub mod sql_types { /// assert_eq!(addr, inserted_addr); /// # Ok(()) /// # } - /// # #[cfg(not(feature = "network-address"))] + /// # #[cfg(not(any(feature = "network-address", feature = "ipnet-address")))] /// # fn main() {} /// ``` #[cfg(feature = "postgres_backend")] diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 588225e428ae..bcef482e393a 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -10,7 +10,8 @@ edition = "2018" [dependencies] assert_matches = "1.0.1" chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] } -diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "network-address", "numeric", "with-deprecated"] } +# TODO: Previously, this used the 'network-address' feature. +diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "numeric", "with-deprecated"] } diesel_migrations = { path = "../diesel_migrations" } dotenvy = "0.15" quickcheck = "1.0.3" From 11d9800a2bb91d488b490b941e44969e7fd850cc Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Tue, 3 May 2022 20:11:51 -0400 Subject: [PATCH 019/107] Fix tests, no longer mutually exclusive --- diesel/src/lib.rs | 6 +- diesel/src/pg/types/ipnet_address.rs | 8 +-- diesel/src/pg/types/mod.rs | 15 ++--- diesel_tests/Cargo.toml | 3 +- diesel_tests/tests/types.rs | 86 +++++++++++++++++++++++++++ diesel_tests/tests/types_roundtrip.rs | 38 ++++++++++++ 6 files changed, 136 insertions(+), 20 deletions(-) diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index e810d03d4eaf..bcdfaa41b5c4 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -141,11 +141,9 @@ //! - `uuid`: This feature flag enables support for (de)serializing uuid values from the database using types //! provided by `uuid` //! - `network-address`: This feature flag enables support for (de)serializing -//! IP values from the database using types provided by `ipnetwork`. Mutually -//! exclusive with `ipnet-address. +//! IP values from the database using types provided by `ipnetwork`. //! - `ipnet-address`: This feature flag enables support for (de)serializing IP -//! values from the database using types provided by `ipnet`. Mutually exclusive -//! with `network-address. +//! values from the database using types provided by `ipnet`. //! - `numeric`: This feature flag enables support for (de)serializing numeric values from the database using types //! provided by `bigdecimal` //! - `r2d2`: This feature flag enables support for the `r2d2` connection pool implementation. diff --git a/diesel/src/pg/types/ipnet_address.rs b/diesel/src/pg/types/ipnet_address.rs index 76c6b292e3be..10a5e6b8c84d 100644 --- a/diesel/src/pg/types/ipnet_address.rs +++ b/diesel/src/pg/types/ipnet_address.rs @@ -159,8 +159,7 @@ fn v4address_to_sql() { fn some_v4address_from_sql() { macro_rules! test_some_address_from_sql { ($ty:tt) => { - let input_address = - IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap()); + let input_address = IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap()); let mut buffer = Vec::new(); { let mut bytes = Output::test(ByteWrapper(&mut buffer)); @@ -182,9 +181,8 @@ fn v6address_to_sql() { let mut buffer = Vec::new(); { let mut bytes = Output::test(ByteWrapper(&mut buffer)); - let test_address = IpNet::V6( - Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap(), - ); + let test_address = + IpNet::V6(Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap()); ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap(); } assert_eq!( diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index 94865c072e48..4e0632e0487e 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -6,13 +6,13 @@ pub(in crate::pg) mod date_and_time; #[doc(hidden)] pub(in crate::pg) mod floats; mod integers; +#[cfg(feature = "ipnet-address")] +mod ipnet_address; #[cfg(feature = "serde_json")] mod json; mod mac_addr; #[doc(hidden)] pub(in crate::pg) mod money; -#[cfg(feature = "ipnet-address")] -mod ipnet_address; #[cfg(feature = "network-address")] mod network_address; mod numeric; @@ -22,9 +22,6 @@ mod record; #[cfg(feature = "uuid")] mod uuid; -#[cfg(all(feature = "network-address", feature = "ipnet-address"))] -compile_error!("Features 'network-address' and 'ipnet-address' cannot be enabled at the same time"); - /// PostgreSQL specific SQL types /// /// Note: All types in this module can be accessed through `diesel::sql_types` @@ -450,8 +447,8 @@ pub mod sql_types { /// # id SERIAL PRIMARY KEY, /// # ip_address INET NOT NULL /// # )").execute(connection)?; - #[cfg_attr(feature = "ipnetwork", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] - #[cfg_attr(feature = "ipnet", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] + /// // Parsing "ipnet::IpNet" would also work. + /// let addr = "10.1.9.32/32".parse::()?; /// let inserted_address = insert_into(clients) /// .values(ip_address.eq(&addr)) /// .returning(ip_address) @@ -509,8 +506,8 @@ pub mod sql_types { /// # id SERIAL PRIMARY KEY, /// # ip_address CIDR NOT NULL /// # )").execute(connection)?; - #[cfg_attr(feature = "ipnetwork", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] - #[cfg_attr(feature = "ipnet", doc = "let addr = \"10.1.9.32/32\".parse::()?;")] + /// // Parsing "ipnet::IpNet" would also work. + /// let addr = "10.1.9.32/32".parse::()?; /// let inserted_addr = insert_into(clients) /// .values(ip_address.eq(&addr)) /// .returning(ip_address) diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index bcef482e393a..20cae4da6dad 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -10,8 +10,7 @@ edition = "2018" [dependencies] assert_matches = "1.0.1" chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] } -# TODO: Previously, this used the 'network-address' feature. -diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "numeric", "with-deprecated"] } +diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "ipnet-address", "network-address", "numeric", "with-deprecated"] } diesel_migrations = { path = "../diesel_migrations" } dotenvy = "0.15" quickcheck = "1.0.3" diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index 01250036d61c..a339d7fcf869 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -1077,6 +1077,26 @@ fn pg_v4address_from_sql() { query_single_value::(query) ); } + +#[test] +#[cfg(feature = "postgres")] +fn pg_v4address_from_sql_ipnet() { + use std::str::FromStr; + + let query = "'192.168.1.0/24'::cidr"; + let expected_value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap()); + assert_eq!( + expected_value, + query_single_value::(query) + ); + let query = "'192.168.1.0/24'::inet"; + let expected_value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap()); + assert_eq!( + expected_value, + query_single_value::(query) + ); +} + #[test] #[cfg(feature = "postgres")] fn pg_v6address_from_sql() { @@ -1099,6 +1119,24 @@ fn pg_v6address_from_sql() { ); } +#[test] +#[cfg(feature = "postgres")] +fn pg_v6address_from_sql_ipnet() { + use std::str::FromStr; + + let query = "'2001:4f8:3:ba::/64'::cidr"; + let expected_value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap()); + assert_eq!( + expected_value, + query_single_value::(query) + ); + let query = "'2001:4f8:3:ba::/64'::inet"; + let expected_value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap()); + assert_eq!( + expected_value, + query_single_value::(query) + ); +} #[test] #[cfg(feature = "postgres")] fn pg_v4address_to_sql_v4address() { @@ -1126,6 +1164,30 @@ fn pg_v4address_to_sql_v4address() { )); } +#[test] +#[cfg(feature = "postgres")] +fn pg_v4address_to_sql_v4address_ipnet() { + use std::str::FromStr; + + let expected_value = "'192.168.1'::cidr"; + let value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap()); + assert!(query_to_sql_equality::( + expected_value, + value + )); + let expected_value = "'192.168.1.0/24'::inet"; + let value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap()); + assert!(query_to_sql_equality::( + expected_value, + value + )); + let expected_non_equal_value = "'192.168.1.0/23'::inet"; + assert!(!query_to_sql_equality::( + expected_non_equal_value, + value + )); +} + #[test] #[cfg(feature = "postgres")] fn pg_v6address_to_sql_v6address() { @@ -1153,6 +1215,30 @@ fn pg_v6address_to_sql_v6address() { )); } +#[test] +#[cfg(feature = "postgres")] +fn pg_v6address_to_sql_v6address_ipnet() { + use std::str::FromStr; + + let expected_value = "'2001:4f8:3:ba::/64'::cidr"; + let value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap()); + assert!(query_to_sql_equality::( + expected_value, + value + )); + let expected_value = "'2001:4f8:3:ba::/64'::cidr"; + let value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap()); + assert!(query_to_sql_equality::( + expected_value, + value + )); + let expected_non_equal_value = "'2001:4f8:3:ba::/63'::cidr"; + assert!(!query_to_sql_equality::( + expected_non_equal_value, + value + )); +} + #[test] #[cfg(feature = "postgres")] fn pg_json_from_sql() { diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index bc752aaa9467..9766a514435a 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -184,19 +184,43 @@ mod pg_types { mk_macaddr ); test_round_trip!(cidr_v4_roundtrips, Cidr, (u8, u8, u8, u8), mk_ipv4); + test_round_trip!( + cidr_v4_roundtrips_ipnet, + Cidr, + (u8, u8, u8, u8), + mk_ipv4_ipnet + ); test_round_trip!( cidr_v6_roundtrips, Cidr, (u16, u16, u16, u16, u16, u16, u16, u16), mk_ipv6 ); + test_round_trip!( + cidr_v6_roundtrips_ipnet, + Cidr, + (u16, u16, u16, u16, u16, u16, u16, u16), + mk_ipv6_ipnet + ); test_round_trip!(inet_v4_roundtrips, Inet, (u8, u8, u8, u8), mk_ipv4); + test_round_trip!( + inet_v4_roundtrips_ipnet, + Inet, + (u8, u8, u8, u8), + mk_ipv4_ipnet + ); test_round_trip!( inet_v6_roundtrips, Inet, (u16, u16, u16, u16, u16, u16, u16, u16), mk_ipv6 ); + test_round_trip!( + inet_v6_roundtrips_ipnet, + Inet, + (u16, u16, u16, u16, u16, u16, u16, u16), + mk_ipv6_ipnet + ); test_round_trip!(bigdecimal_roundtrips, Numeric, (i64, u64), mk_bigdecimal); test_round_trip!(int4range_roundtrips, Range, (i32, i32), mk_bounds); test_round_trip!(int8range_roundtrips, Range, (i64, i64), mk_bounds); @@ -244,6 +268,12 @@ mod pg_types { ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::new(ip, 32).unwrap()) } + fn mk_ipv4_ipnet(data: (u8, u8, u8, u8)) -> ipnet::IpNet { + use std::net::Ipv4Addr; + let ip = Ipv4Addr::new(data.0, data.1, data.2, data.3); + ipnet::IpNet::V4(ipnet::Ipv4Net::new(ip, 32).unwrap()) + } + fn mk_ipv6(data: (u16, u16, u16, u16, u16, u16, u16, u16)) -> ipnetwork::IpNetwork { use std::net::Ipv6Addr; let ip = Ipv6Addr::new( @@ -252,6 +282,14 @@ mod pg_types { ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::new(ip, 128).unwrap()) } + fn mk_ipv6_ipnet(data: (u16, u16, u16, u16, u16, u16, u16, u16)) -> ipnet::IpNet { + use std::net::Ipv6Addr; + let ip = Ipv6Addr::new( + data.0, data.1, data.2, data.3, data.4, data.5, data.6, data.7, + ); + ipnet::IpNet::V6(ipnet::Ipv6Net::new(ip, 128).unwrap()) + } + fn mk_bounds(data: (T, T)) -> (Bound, Bound) { if data.0 == data.1 { // This is invalid but we don't have a way to say that to quickcheck From a363512ea2680fabac166f79e6b07911fbd8a523 Mon Sep 17 00:00:00 2001 From: Steven Chu Date: Wed, 4 May 2022 20:01:35 -0700 Subject: [PATCH 020/107] Update documentation for r2d2 to be more complete --- diesel/src/r2d2.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/diesel/src/r2d2.rs b/diesel/src/r2d2.rs index 62f5efb9eb10..f6e17d1ecbe6 100644 --- a/diesel/src/r2d2.rs +++ b/diesel/src/r2d2.rs @@ -78,16 +78,18 @@ //! //! When used inside a pool, if an individual connection becomes //! broken (as determined by the [R2D2Connection::is_broken] method) -//! then `r2d2` will close and return the connection to the DB. +//! then, when the connection goes out of scope, `r2d2` will close +//! and return the connection to the DB. //! //! `diesel` determines broken connections by whether or not the current //! thread is panicking or if individual `Connection` structs are //! broken (determined by the `is_broken()` method). Generically, these //! are left to individual backends to implement themselves. //! -//! For SQLite, PG, and MySQL backends, specifically, `is_broken()` -//! is determined by whether or not the `TransactionManagerStatus` (as a part -//! of the `AnsiTransactionManager` struct) is in an `InError` state. +//! For SQLite, PG, and MySQL backends `is_broken()` is determined +//! by whether or not the `TransactionManagerStatus` (as a part +//! of the `AnsiTransactionManager` struct) is in an `InError` state +//! or contains an open transaction when the connection goes out of scope. //! pub use r2d2::*; From 2c2a79573732100b342c181fa8dd8e13b6aab93b Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 5 May 2022 08:53:48 +0200 Subject: [PATCH 021/107] Fix broken bound in diesel_cli Technically this seems to be a breaking change, but as we haven't released 2.0 yet this is fine. --- .../src/infer_schema_internals/information_schema.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/diesel_cli/src/infer_schema_internals/information_schema.rs b/diesel_cli/src/infer_schema_internals/information_schema.rs index cf4b2ef22503..0587164bca9b 100644 --- a/diesel_cli/src/infer_schema_internals/information_schema.rs +++ b/diesel_cli/src/infer_schema_internals/information_schema.rs @@ -4,7 +4,7 @@ use std::error::Error; use diesel::backend::Backend; use diesel::deserialize::{FromSql, FromSqlRow}; use diesel::dsl::*; -use diesel::expression::{is_aggregate, MixedAggregates, QueryMetadata, ValidGrouping}; +use diesel::expression::{is_aggregate, QueryMetadata, ValidGrouping}; #[cfg(feature = "mysql")] use diesel::mysql::Mysql; #[cfg(feature = "postgres")] @@ -160,10 +160,12 @@ where )>, Conn::Backend, >, - is_aggregate::No: MixedAggregates< - <::TypeSchema as ValidGrouping<()>>::IsAggregate, - Output = is_aggregate::No, - >, + ( + columns::column_name, + ::TypeColumn, + ::TypeSchema, + columns::__is_nullable, + ): ValidGrouping<()>, String: FromSql, Option: FromSql, Conn::Backend>, Order< From f2aff801cd1eb04f87caaccaa67db5c904e4e86b Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 5 May 2022 09:08:54 +0200 Subject: [PATCH 022/107] Bring back __GroupByClause as generic parameter as it makes the error messages easier to understand in my opinion --- diesel/src/type_impls/tuples.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs index d35f4a597f40..ade4495375e5 100644 --- a/diesel/src/type_impls/tuples.rs +++ b/diesel/src/type_impls/tuples.rs @@ -448,14 +448,15 @@ macro_rules! impl_from_sql_row { macro_rules! impl_valid_grouping_for_tuple_of_columns { ($T1: ident, $($T: ident,)+) => { - impl<$T1, $($T,)* GB> ValidGrouping for ($T1, $($T,)*) + impl<$T1, $($T,)* __GroupByClause> ValidGrouping<__GroupByClause> for ($T1, $($T,)*) where - $T1: ValidGrouping, - ($($T,)*): ValidGrouping, - $T1::IsAggregate: MixedAggregates<<($($T,)*) as ValidGrouping>::IsAggregate>, + $T1: ValidGrouping<__GroupByClause>, + ($($T,)*): ValidGrouping<__GroupByClause>, + $T1::IsAggregate: MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>, { - type IsAggregate = <$T1::IsAggregate as MixedAggregates<<($($T,)*) as ValidGrouping>::IsAggregate>>::Output; + type IsAggregate = <$T1::IsAggregate as MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>>::Output; } + impl<$T1, $($T,)* Col> IsContainedInGroupByfor ($T1, $($T,)*) where Col: Column, ($($T,)*): IsContainedInGroupBy, @@ -473,8 +474,8 @@ macro_rules! impl_valid_grouping_for_tuple_of_columns { type Output = <$T1 as IsContainedInGroupBy>::Output; } - impl<$T1, GB> ValidGrouping for ($T1,) - where $T1: ValidGrouping + impl<$T1, __GroupByClause> ValidGrouping<__GroupByClause> for ($T1,) + where $T1: ValidGrouping<__GroupByClause> { type IsAggregate = $T1::IsAggregate; } From ce39fe7a4a30bfecde55d5352be87f354de52577 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 5 May 2022 09:09:29 +0200 Subject: [PATCH 023/107] Fix compile tests --- .../fail/array_expressions_must_be_same_type.stderr | 8 ++++---- .../tests/fail/select_requires_valid_grouping.stderr | 6 ++++-- diesel_compile_tests/tests/fail/selectable.stderr | 12 ++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr index 19531cbf9017..d4b5b6cf206f 100644 --- a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr +++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr @@ -27,8 +27,8 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied | crate::dsl::BareSelect: AsQuery, | ------- required by this bound in `diesel::select` | - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::internal::derives::as_expression::Bound, f64)` - = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64,)` + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, f64), diesel::sql_types::Integer>>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement, f64), diesel::sql_types::Integer>>>` @@ -52,8 +52,8 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied 11 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64` | - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::internal::derives::as_expression::Bound, f64)` - = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64,)` + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, f64), diesel::sql_types::Integer>>>` = note: required because of the requirements on the impl of `LoadQuery<'_, _, Vec>` for `SelectStatement, f64), diesel::sql_types::Integer>>>` diff --git a/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr b/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr index 74051871804c..8bde75ed07d2 100644 --- a/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr +++ b/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr @@ -61,7 +61,7 @@ error[E0277]: the trait bound `users::columns::id: IsContainedInGroupBy` for `(users::columns::id, posts::columns::id)` = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `comments::columns::id` - = note: 1 redundant requirements hidden + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)` = note: required because of the requirements on the impl of `SelectDsl<((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>>, Inner>, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::DefaultSelectClause, diesel::expression::grouped::Grouped, NullableExpression>>>>>, Inner>, diesel::expression::grouped::Grouped, NullableExpression>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause<(users::columns::id, posts::columns::id)>>` @@ -77,8 +77,10 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy> > and 2 others + = note: required because of the requirements on the impl of `IsContainedInGroupBy` for `(posts::columns::id,)` + = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `IsContainedInGroupBy` for `(users::columns::id, posts::columns::id)` = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `comments::columns::id` - = note: 1 redundant requirements hidden + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)` = note: required because of the requirements on the impl of `SelectDsl<((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>>, Inner>, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::DefaultSelectClause, diesel::expression::grouped::Grouped, NullableExpression>>>>>, Inner>, diesel::expression::grouped::Grouped, NullableExpression>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause<(users::columns::id, posts::columns::id)>>` diff --git a/diesel_compile_tests/tests/fail/selectable.stderr b/diesel_compile_tests/tests/fail/selectable.stderr index 810636588cf3..140f3f1e8b62 100644 --- a/diesel_compile_tests/tests/fail/selectable.stderr +++ b/diesel_compile_tests/tests/fail/selectable.stderr @@ -138,7 +138,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy> > = note: required because of the requirements on the impl of `ValidGrouping` for `users::columns::name` - = note: 2 redundant requirements hidden + = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping` for `diesel::expression::select_by::SelectBy` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::DefaultSelectClause, diesel::expression::grouped::Grouped, NullableExpression>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` @@ -169,7 +169,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy> > = note: required because of the requirements on the impl of `ValidGrouping` for `users::columns::name` - = note: 2 redundant requirements hidden + = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping` for `diesel::expression::select_by::SelectBy` = note: required because of the requirements on the impl of `Query` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::SelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::SelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` @@ -183,8 +183,8 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count)` - = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::name, diesel::expression::count::count::count)` + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::select_by::SelectBy` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>>` @@ -197,8 +197,8 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count)` - = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::name, diesel::expression::count::count::count)` + = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::select_by::SelectBy` = note: required because of the requirements on the impl of `Query` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::SelectClause>>` = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithPostCount>` for `SelectStatement, diesel::expression::grouped::Grouped, NullableExpression>>>>, diesel::query_builder::select_clause::SelectClause>>` From 914d62a7b7e7159cf55174a35a8527116b06a297 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 5 May 2022 10:33:10 +0200 Subject: [PATCH 024/107] This commit fixes a potential race condition in our r2d2 tests This was triggered by the fact that the pool tries to open a new connection after the old one was closed. As this happens in a background thread this happens concurrently to our test code. That means if establishing a new connection is fast that will increase the acquire_count before we checked it. We observed this happening for sqlite. I've opted into just not checking the acquire count there as this is not really relevant anyway at that points. --- diesel/src/r2d2.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/diesel/src/r2d2.rs b/diesel/src/r2d2.rs index f6e17d1ecbe6..84254902f30c 100644 --- a/diesel/src/r2d2.rs +++ b/diesel/src/r2d2.rs @@ -500,7 +500,11 @@ mod tests { .unwrap(); } - assert_eq!(acquire_count.load(Ordering::Relaxed), 1); + // we are not interested in the acquire count here + // as the pool opens a new connection in the background + // that could lead to this test failing if that happens to fast + // (which is sometimes the case for sqlite) + //assert_eq!(acquire_count.load(Ordering::Relaxed), 1); assert_eq!(release_count.load(Ordering::Relaxed), 1); assert_eq!(checkin_count.load(Ordering::Relaxed), 2); assert_eq!(checkout_count.load(Ordering::Relaxed), 2); @@ -519,7 +523,11 @@ mod tests { })) .unwrap_err(); - assert_eq!(acquire_count.load(Ordering::Relaxed), 2); + // we are not interested in the acquire count here + // as the pool opens a new connection in the background + // that could lead to this test failing if that happens to fast + // (which is sometimes the case for sqlite) + //assert_eq!(acquire_count.load(Ordering::Relaxed), 2); assert_eq!(release_count.load(Ordering::Relaxed), 2); assert_eq!(checkin_count.load(Ordering::Relaxed), 3); assert_eq!(checkout_count.load(Ordering::Relaxed), 3); From a69e8d461523b2fdbaee22dceeaa3f53ad3eca01 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 10 May 2022 08:55:07 +0200 Subject: [PATCH 025/107] Make TransactionDepthChange public This is kind of required as otherwise custom connection implementations cannot provide their own transaction manager implementation. --- diesel/src/connection/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel/src/connection/mod.rs b/diesel/src/connection/mod.rs index b1d82951f30d..bc8fe23cd8ca 100644 --- a/diesel/src/connection/mod.rs +++ b/diesel/src/connection/mod.rs @@ -22,7 +22,7 @@ use crate::result::*; use std::fmt::Debug; pub use self::transaction_manager::{ - AnsiTransactionManager, TransactionManager, TransactionManagerStatus, + AnsiTransactionManager, TransactionDepthChange, TransactionManager, TransactionManagerStatus, ValidTransactionManagerStatus, }; From 768b98d7a6d70392d784d6f69abee07cb05d9e7d Mon Sep 17 00:00:00 2001 From: Chris Eckhardt Date: Thu, 12 May 2022 13:40:05 -0500 Subject: [PATCH 026/107] Fix doc typo for `fn sql_query` --- diesel/src/query_builder/functions.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/diesel/src/query_builder/functions.rs b/diesel/src/query_builder/functions.rs index 153ef0b9e07a..5ef19cad96ab 100644 --- a/diesel/src/query_builder/functions.rs +++ b/diesel/src/query_builder/functions.rs @@ -588,8 +588,7 @@ pub fn replace_into(target: T) -> IncompleteReplaceStatement { /// # #[cfg(not(feature = "postgres"))] /// // Checkout the documentation of your database for the correct /// // bind placeholder -/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?") -/// # ; +/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?"); /// let users = users /// .bind::(1) /// .bind::("Tess") From 448df6b61566dbd419554fc82abd018357848846 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 20 May 2022 10:18:20 +0200 Subject: [PATCH 027/107] Address #3173 This is a tricky one. It seems like the behaviour described in that issue should work out of the box, but it doesn't. I've spend some time to investigate various solutions to make this work, but I came to the conclusion that the current behaviour is the correct one. The underlying issue here is that such an query promotes the inner `Nullable<_>` of the field onto the outer `Queryable` wrapper. Without `Selectable` that would require a select clause like `.select((table::column.assume_not_null(),).nullable())`. This is technically a safe pattern, but requires the usage of the "advanced" `assume_not_null()` method to forcibly convert types to their not null representation. Possible solutions tried to make the enable constructs shown in that issue: * I've tried to make the `impl Selectable for Option` return the following `SelectExpression`: `dsl::Nullable>` where `AssumeNotNull` converts each tuple element to the corresponding not nullable expression, while `Nullable` wraps the tuple itself into a nullable type wrapper. * I've tried to apply a similar approach like that one above, but only for derived impls by manipulating the generated code for a optional field with `#[diesel(embed)]` Both solutions require changes to our sql type system, as for example allowing to load a non nullable value into a `Option` to enable their usage in a more general scope as the presented example case. (See the added test cases for this). That by itself would be fine in my opinion, as this is always a safe operation. Unfortunately the `AssumeNotNull` transformation would be applied recursively for all sub-tuples, which in turn would cause trouble with nested joins (again see the examples). We would be able to workaround this issue by allowing the `FromSql for Option` impl for non-nullable types to catch null values, which in turn really feels like a bad hack. (You would like to get an error there instead, but nested nullable information are gone.) All in all this lead me to the conclusion that the current behaviour is correct. This PR adds a few additional tests (an adjusted version of the test from the bug report + more tests around nested joins) and does move around some code bits that I noticed while working on this. I think the official answer for the bug report would be: Either wrap the inner type also in an `Option` or provide a manual `Selectable` impl that does the "right" thing there. --- diesel/src/expression/nullable.rs | 13 - diesel/src/query_dsl/load_dsl.rs | 4 +- diesel/src/type_impls/option.rs | 19 +- diesel_derives/tests/as_changeset.rs | 2 + diesel_derives/tests/selectable.rs | 28 + diesel_derives/tests/tests.rs | 2 - diesel_tests/tests/joins.rs | 16 +- .../tests/schema/backend_specifics.rs | 4 +- diesel_tests/tests/schema/mod.rs | 16 +- .../tests/schema/postgres_specific_schema.rs | 4 +- diesel_tests/tests/select_by.rs | 512 ++++++++++++++++++ 11 files changed, 583 insertions(+), 37 deletions(-) diff --git a/diesel/src/expression/nullable.rs b/diesel/src/expression/nullable.rs index 223c636e5538..8912b002a6e9 100644 --- a/diesel/src/expression/nullable.rs +++ b/diesel/src/expression/nullable.rs @@ -48,19 +48,6 @@ impl QueryId for Nullable { const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID; } -impl Selectable for Option -where - DB: Backend, - T: Selectable, - Nullable: Expression, -{ - type SelectExpression = Nullable; - - fn construct_selection() -> Self::SelectExpression { - Nullable::new(T::construct_selection()) - } -} - impl SelectableExpression for Nullable where Self: AppearsOnTable, diff --git a/diesel/src/query_dsl/load_dsl.rs b/diesel/src/query_dsl/load_dsl.rs index a601beb671c3..d03ffefe7575 100644 --- a/diesel/src/query_dsl/load_dsl.rs +++ b/diesel/src/query_dsl/load_dsl.rs @@ -195,8 +195,8 @@ mod private { } #[cfg_attr( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", - cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes") + doc_cfg, + doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")) )] pub trait CompatibleType { type SqlType; diff --git a/diesel/src/type_impls/option.rs b/diesel/src/type_impls/option.rs index 929255311f10..b61615a8309e 100644 --- a/diesel/src/type_impls/option.rs +++ b/diesel/src/type_impls/option.rs @@ -5,6 +5,7 @@ use crate::expression::*; use crate::query_builder::QueryId; use crate::serialize::{self, IsNull, Output, ToSql}; use crate::sql_types::{is_nullable, HasSqlType, Nullable, SingleValue, SqlType}; +use crate::NullableExpressionMethods; impl HasSqlType> for DB where @@ -109,15 +110,25 @@ where } } -#[cfg(all(test, feature = "postgres"))] -use crate::pg::Pg; -#[cfg(all(test, feature = "postgres"))] -use crate::sql_types; +impl Selectable for Option +where + DB: Backend, + T: Selectable, + crate::dsl::Nullable: Expression, +{ + type SelectExpression = crate::dsl::Nullable; + + fn construct_selection() -> Self::SelectExpression { + T::construct_selection().nullable() + } +} #[test] #[cfg(feature = "postgres")] fn option_to_sql() { + use crate::pg::Pg; use crate::query_builder::bind_collector::ByteWrapper; + use crate::sql_types; type Type = sql_types::Nullable; diff --git a/diesel_derives/tests/as_changeset.rs b/diesel_derives/tests/as_changeset.rs index 33057d9f8291..cd68ef01ed52 100644 --- a/diesel_derives/tests/as_changeset.rs +++ b/diesel_derives/tests/as_changeset.rs @@ -1,3 +1,5 @@ +use diesel::deserialize::FromSqlRow; +use diesel::expression::AsExpression; use diesel::*; use helpers::*; use schema::*; diff --git a/diesel_derives/tests/selectable.rs b/diesel_derives/tests/selectable.rs index 5174b5e5ca7f..76272cdcbf94 100644 --- a/diesel_derives/tests/selectable.rs +++ b/diesel_derives/tests/selectable.rs @@ -86,3 +86,31 @@ fn embedded_option() { let data = my_structs::table.select(A::as_select()).get_result(conn); assert!(data.is_err()); } + +#[test] +fn embedded_option_with_nullable_field() { + table! { + my_structs (foo) { + foo -> Integer, + bar -> Nullable, + } + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] + #[diesel(table_name = my_structs)] + struct A { + foo: i32, + #[diesel(embed)] + b: Option, + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] + #[diesel(table_name = my_structs)] + struct B { + bar: Option, + } + + let conn = &mut connection(); + let data = my_structs::table.select(A::as_select()).get_result(conn); + assert!(data.is_err()); +} diff --git a/diesel_derives/tests/tests.rs b/diesel_derives/tests/tests.rs index 0d09bf99ab2e..91a99948a645 100644 --- a/diesel_derives/tests/tests.rs +++ b/diesel_derives/tests/tests.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - #[macro_use] extern crate cfg_if; #[macro_use] diff --git a/diesel_tests/tests/joins.rs b/diesel_tests/tests/joins.rs index f56e4e0c2a3e..70f4fe73e114 100644 --- a/diesel_tests/tests/joins.rs +++ b/diesel_tests/tests/joins.rs @@ -701,7 +701,7 @@ fn selecting_crazy_nested_joins() { assert_eq!(Ok(expected), data); } -fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestData) { +pub(crate) fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestData) { let mut connection = connection_with_sean_and_tess_in_users_table(); let sean = find_user_by_name("Sean", &mut connection); @@ -775,11 +775,11 @@ fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestD (connection, test_data) } -struct TestData { - sean: User, - tess: User, - posts: Vec, - comments: Vec, - likes: Vec, - followings: Vec, +pub struct TestData { + pub sean: User, + pub tess: User, + pub posts: Vec, + pub comments: Vec, + pub likes: Vec, + pub followings: Vec, } diff --git a/diesel_tests/tests/schema/backend_specifics.rs b/diesel_tests/tests/schema/backend_specifics.rs index 91055d246fae..224e81882bee 100644 --- a/diesel_tests/tests/schema/backend_specifics.rs +++ b/diesel_tests/tests/schema/backend_specifics.rs @@ -1,6 +1,8 @@ use super::*; -#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)] +#[derive( + PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName, Selectable, +)] #[diesel(belongs_to(User))] #[diesel(table_name = posts)] pub struct Post { diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs index 954f71e565ce..1533b52034b0 100644 --- a/diesel_tests/tests/schema/mod.rs +++ b/diesel_tests/tests/schema/mod.rs @@ -61,8 +61,8 @@ impl UserName { } } -#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] -#[diesel(belongs_to(Post))] +#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, Selectable)] +#[diesel(belongs_to(Post), table_name = comments)] pub struct Comment { id: i32, post_id: i32, @@ -79,7 +79,9 @@ impl Comment { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable, Selectable, +)] #[diesel(belongs_to(User))] #[diesel(belongs_to(Post))] #[diesel(table_name = followings)] @@ -177,14 +179,16 @@ pub struct NullableColumn { value: Option, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations, Selectable, +)] #[diesel(table_name = likes)] -#[diesel(primary_key(user_id, comment_id))] +#[diesel(primary_key(comment_id, user_id))] #[diesel(belongs_to(User))] #[diesel(belongs_to(Comment))] pub struct Like { - pub user_id: i32, pub comment_id: i32, + pub user_id: i32, } #[cfg(feature = "postgres")] diff --git a/diesel_tests/tests/schema/postgres_specific_schema.rs b/diesel_tests/tests/schema/postgres_specific_schema.rs index d1a48bc0651f..2d9152e6eedd 100644 --- a/diesel_tests/tests/schema/postgres_specific_schema.rs +++ b/diesel_tests/tests/schema/postgres_specific_schema.rs @@ -1,6 +1,8 @@ use super::{posts, User}; -#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)] +#[derive( + PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName, Selectable, +)] #[diesel(table_name = posts)] #[diesel(belongs_to(User))] pub struct Post { diff --git a/diesel_tests/tests/select_by.rs b/diesel_tests/tests/select_by.rs index 91daad4137e0..b695ca31b4be 100644 --- a/diesel_tests/tests/select_by.rs +++ b/diesel_tests/tests/select_by.rs @@ -217,3 +217,515 @@ fn mixed_selectable_and_plain_select() { .unwrap(); assert_eq!(expected_data, actual_data); } + +// The following tests are duplicates from tests in joins.rs +// They are used to verify that selectable behaves equivalent to the corresponding +// raw select +#[test] +fn selecting_parent_child_grandchild() { + use crate::joins::TestData; + + let (mut connection, test_data) = + crate::joins::connection_with_fixture_data_for_multitable_joins(); + let TestData { + sean, + tess, + posts, + comments, + .. + } = test_data; + + let data = users::table + .inner_join(posts::table.inner_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(<(User, (Post, Comment)) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + (sean.clone(), (posts[0].clone(), comments[0].clone())), + (sean.clone(), (posts[0].clone(), comments[2].clone())), + (sean.clone(), (posts[2].clone(), comments[1].clone())), + ]; + assert_eq!(Ok(expected.clone()), data); + + let data = users::table + .inner_join( + posts::table + .on(users::id.eq(posts::user_id).and(posts::id.eq(posts[0].id))) + .inner_join(comments::table), + ) + .order((users::id, posts::id, comments::id)) + .select(<(User, (Post, Comment)) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + (sean.clone(), (posts[0].clone(), comments[0].clone())), + (sean.clone(), (posts[0].clone(), comments[2].clone())), + ]; + assert_eq!(Ok(expected), data); + + let data = users::table + .inner_join(posts::table.left_outer_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(<(User, (Post, Option)) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + (sean.clone(), (posts[0].clone(), Some(comments[0].clone()))), + (sean.clone(), (posts[0].clone(), Some(comments[2].clone()))), + (sean.clone(), (posts[2].clone(), Some(comments[1].clone()))), + (tess.clone(), (posts[1].clone(), None)), + ]; + assert_eq!(Ok(expected), data); + + let data = users::table + .left_outer_join(posts::table.left_outer_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(<(User, Option<(Post, Option)>) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + ( + sean.clone(), + Some((posts[0].clone(), Some(comments[0].clone()))), + ), + ( + sean.clone(), + Some((posts[0].clone(), Some(comments[2].clone()))), + ), + ( + sean.clone(), + Some((posts[2].clone(), Some(comments[1].clone()))), + ), + (tess.clone(), Some((posts[1].clone(), None))), + ]; + assert_eq!(Ok(expected), data); + + let data = users::table + .left_outer_join(posts::table.inner_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(<(User, Option<(Post, Comment)>) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + (sean.clone(), Some((posts[0].clone(), comments[0].clone()))), + (sean.clone(), Some((posts[0].clone(), comments[2].clone()))), + (sean.clone(), Some((posts[2].clone(), comments[1].clone()))), + (tess.clone(), None), + ]; + assert_eq!(Ok(expected), data); +} + +#[test] +fn selecting_parent_child_grandchild_nested() { + use crate::joins::TestData; + + let (mut connection, test_data) = + crate::joins::connection_with_fixture_data_for_multitable_joins(); + let TestData { + sean, + tess, + posts, + comments, + .. + } = test_data; + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = users)] + struct User1 { + id: i32, + name: String, + hair_color: Option, + #[diesel(embed)] + post: Post1, + } + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = posts)] + struct Post1 { + id: i32, + user_id: i32, + title: String, + body: Option, + #[diesel(embed)] + comment: Comment, + } + + let data = users::table + .inner_join(posts::table.inner_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(User1::as_select()) + .load(&mut connection); + let expected = vec![ + User1 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post1 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: comments[0].clone(), + }, + }, + User1 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post1 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: comments[2].clone(), + }, + }, + User1 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post1 { + id: posts[2].id, + user_id: posts[2].user_id, + title: posts[2].title.clone(), + body: posts[2].body.clone(), + comment: comments[1].clone(), + }, + }, + ]; + assert_eq!(Ok(expected.clone()), data); + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = users)] + struct User2 { + id: i32, + name: String, + hair_color: Option, + #[diesel(embed)] + post: Post2, + } + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = posts)] + struct Post2 { + id: i32, + user_id: i32, + title: String, + body: Option, + #[diesel(embed)] + comment: Option, + } + + let data = users::table + .inner_join(posts::table.left_outer_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(User2::as_select()) + .load(&mut connection); + let expected = vec![ + User2 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post2 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: Some(comments[0].clone()), + }, + }, + User2 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post2 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: Some(comments[2].clone()), + }, + }, + User2 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Post2 { + id: posts[2].id, + user_id: posts[2].user_id, + title: posts[2].title.clone(), + body: posts[2].body.clone(), + comment: Some(comments[1].clone()), + }, + }, + User2 { + id: tess.id, + name: tess.name.clone(), + hair_color: tess.hair_color.clone(), + post: Post2 { + id: posts[1].id, + user_id: posts[1].user_id, + title: posts[1].title.clone(), + body: posts[1].body.clone(), + comment: None, + }, + }, + ]; + assert_eq!(Ok(expected), data); + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = users)] + struct User3 { + id: i32, + name: String, + hair_color: Option, + #[diesel(embed)] + post: Option, + } + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = posts)] + struct Post3 { + id: i32, + user_id: i32, + title: String, + body: Option, + #[diesel(embed)] + comment: Option, + } + + let data = users::table + .left_outer_join(posts::table.left_outer_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(User3::as_select()) + .load(&mut connection); + let expected = vec![ + User3 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post3 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: Some(comments[0].clone()), + }), + }, + User3 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post3 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: Some(comments[2].clone()), + }), + }, + User3 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post3 { + id: posts[2].id, + user_id: posts[2].user_id, + title: posts[2].title.clone(), + body: posts[2].body.clone(), + comment: Some(comments[1].clone()), + }), + }, + User3 { + id: tess.id, + name: tess.name.clone(), + hair_color: tess.hair_color.clone(), + post: Some(Post3 { + id: posts[1].id, + user_id: posts[1].user_id, + title: posts[1].title.clone(), + body: posts[1].body.clone(), + comment: None, + }), + }, + ]; + assert_eq!(Ok(expected), data); + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = users)] + struct User4 { + id: i32, + name: String, + hair_color: Option, + #[diesel(embed)] + post: Option, + } + + #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] + #[diesel(table_name = posts)] + struct Post4 { + id: i32, + user_id: i32, + title: String, + body: Option, + #[diesel(embed)] + comment: Comment, + } + + let data = users::table + .left_outer_join(posts::table.inner_join(comments::table)) + .order((users::id, posts::id, comments::id)) + .select(User4::as_select()) + .load(&mut connection); + let expected = vec![ + User4 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post4 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: comments[0].clone(), + }), + }, + User4 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post4 { + id: posts[0].id, + user_id: posts[0].user_id, + title: posts[0].title.clone(), + body: posts[0].body.clone(), + comment: comments[2].clone(), + }), + }, + User4 { + id: sean.id, + name: sean.name.clone(), + hair_color: sean.hair_color.clone(), + post: Some(Post4 { + id: posts[2].id, + user_id: posts[2].user_id, + title: posts[2].title.clone(), + body: posts[2].body.clone(), + comment: comments[1].clone(), + }), + }, + User4 { + id: tess.id, + name: tess.name.clone(), + hair_color: tess.hair_color.clone(), + post: None, + }, + ]; + assert_eq!(Ok(expected), data); +} + +#[test] +fn selecting_grandchild_child_parent() { + use crate::joins::TestData; + let (mut connection, test_data) = + crate::joins::connection_with_fixture_data_for_multitable_joins(); + let TestData { + sean, + posts, + comments, + .. + } = test_data; + + let data = comments::table + .inner_join(posts::table.inner_join(users::table)) + .order((users::id, posts::id, comments::id)) + .select(<(Comment, (Post, User)) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + (comments[0].clone(), (posts[0].clone(), sean.clone())), + (comments[2].clone(), (posts[0].clone(), sean.clone())), + (comments[1].clone(), (posts[2].clone(), sean.clone())), + ]; + assert_eq!(Ok(expected), data); +} + +#[test] +fn selecting_crazy_nested_joins() { + use crate::joins::TestData; + let (mut connection, test_data) = + crate::joins::connection_with_fixture_data_for_multitable_joins(); + let TestData { + sean, + tess, + posts, + likes, + comments, + followings, + .. + } = test_data; + + let data = users::table + .inner_join( + posts::table + .left_join(comments::table.left_join(likes::table)) + .left_join(followings::table), + ) + .select(<( + User, + (Post, Option<(Comment, Option)>, Option), + ) as SelectableHelper<_>>::as_select()) + .order((users::id, posts::id, comments::id)) + .load(&mut connection); + let expected = vec![ + ( + sean.clone(), + ( + posts[0].clone(), + Some((comments[0].clone(), Some(likes[0].clone()))), + None, + ), + ), + ( + sean.clone(), + (posts[0].clone(), Some((comments[2].clone(), None)), None), + ), + ( + sean.clone(), + (posts[2].clone(), Some((comments[1].clone(), None)), None), + ), + ( + tess.clone(), + (posts[1].clone(), None, Some(followings[0].clone())), + ), + ]; + assert_eq!(Ok(expected), data); + + let data = users::table + .inner_join(posts::table.left_join(comments::table.left_join(likes::table))) + .left_join(followings::table) + .order((users::id, posts::id, comments::id)) + .select(<( + User, + (Post, Option<(Comment, Option)>), + Option, + ) as SelectableHelper<_>>::as_select()) + .load(&mut connection); + let expected = vec![ + ( + sean.clone(), + ( + posts[0].clone(), + Some((comments[0].clone(), Some(likes[0].clone()))), + ), + Some(followings[0]), + ), + ( + sean.clone(), + (posts[0].clone(), Some((comments[2].clone(), None))), + Some(followings[0]), + ), + ( + sean.clone(), + (posts[2].clone(), Some((comments[1].clone(), None))), + Some(followings[0]), + ), + (tess.clone(), (posts[1].clone(), None), None), + ]; + assert_eq!(Ok(expected), data); +} From e289d33b3d6e94e06426bbe1f817fa23f7436856 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 20 May 2022 11:17:32 +0200 Subject: [PATCH 028/107] Address (unreleated) CI errors --- diesel/src/mysql/connection/mod.rs | 2 -- diesel/src/pg/connection/mod.rs | 1 - diesel/src/sqlite/connection/mod.rs | 1 - diesel_cli/src/database.rs | 7 ------- 4 files changed, 11 deletions(-) diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs index 7cc7a7140b90..e34422534925 100644 --- a/diesel/src/mysql/connection/mod.rs +++ b/diesel/src/mysql/connection/mod.rs @@ -99,7 +99,6 @@ impl Connection for MysqlConnection { StatementIterator::from_stmt(stmt, &metadata) } - #[doc(hidden)] fn execute_returning_count(&mut self, source: &T) -> QueryResult where T: QueryFragment + QueryId, @@ -131,7 +130,6 @@ impl Connection for MysqlConnection { } } - #[doc(hidden)] fn transaction_state(&mut self) -> &mut AnsiTransactionManager { &mut self.transaction_state } diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs index fcd608b4ab6b..c24d3fcfc021 100644 --- a/diesel/src/pg/connection/mod.rs +++ b/diesel/src/pg/connection/mod.rs @@ -146,7 +146,6 @@ impl Connection for PgConnection { }) } - #[doc(hidden)] fn execute_returning_count(&mut self, source: &T) -> QueryResult where T: QueryFragment + QueryId, diff --git a/diesel/src/sqlite/connection/mod.rs b/diesel/src/sqlite/connection/mod.rs index b6dffcb87f2b..eec42f1db571 100644 --- a/diesel/src/sqlite/connection/mod.rs +++ b/diesel/src/sqlite/connection/mod.rs @@ -113,7 +113,6 @@ impl Connection for SqliteConnection { Ok(StatementIterator::new(statement_use)) } - #[doc(hidden)] fn execute_returning_count(&mut self, source: &T) -> QueryResult where T: QueryFragment + QueryId, diff --git a/diesel_cli/src/database.rs b/diesel_cli/src/database.rs index ab5ab25be33e..3d410f2bccaa 100644 --- a/diesel_cli/src/database.rs +++ b/diesel_cli/src/database.rs @@ -122,13 +122,6 @@ impl InferConnection { } macro_rules! call_with_conn { - ( - $database_url:expr, - $($func:ident)::+ - ) => { - call_with_conn!($database_url, $($func)::+ ()) - }; - ( $database_url:expr, $($func:ident)::+ ($($args:expr),*) From cd20ce76eb028214131e06c484405f21abf1773f Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 23 May 2022 14:43:47 +0200 Subject: [PATCH 029/107] Make sure clippy runs for test code as well This is to prevent things like #3182 to slip through again --- .github/workflows/ci.yml | 44 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d123063de725..35ddc95dbb62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -377,10 +377,46 @@ jobs: find ~/.cargo/registry -iname "*clippy.toml" -delete - name: Run clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all + run: + cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "postgres diesel/postgres" + cargo clippy --tests --manifest-path diesel/Cargo.toml --features "postgres" + cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "postgres diesel/postgres" + cargo clippy --tests --manifest-path diesel_migrations/migrations_internals/Cargo.toml + cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "postgres diesel/postgres" + cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" + cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres" + cargo clippy --tests --manifest-path examples/postgres/getting_started_step1/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/getting_started_step2/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/advanced-blog-cli/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/all_about_inserts/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/all_about_updates/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/custom_types/Cargo.toml + + cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "sqlite diesel/sqlite" + cargo clippy --tests --manifest-path diesel/Cargo.toml --features "sqlite" + cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "sqlite diesel/sqlite" + cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "sqlite diesel/sqlite" + cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" + cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite" + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step1/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step2/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/all_about_inserts/Cargo.toml + + cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "mysql diesel/mysql" + cargo clippy --tests --manifest-path diesel/Cargo.toml --features "mysql" + cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "mysql diesel/mysql" + cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "mysql diesel/mysql" + cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" + cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql" + cargo clippy --tests --manifest-path examples/mysql/getting_started_step1/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/getting_started_step2/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/all_about_inserts/Cargo.toml - name: Check formating uses: actions-rs/cargo@v1 From 0565d92f7856270213848c5033cdc986c0fffcac Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 23 May 2022 14:44:16 +0200 Subject: [PATCH 030/107] Fix a large number of clippy warnings Addresses #3182 --- diesel/src/connection/transaction_manager.rs | 6 +++ diesel/src/lib.rs | 2 +- diesel/src/mysql/connection/bind.rs | 4 +- diesel/src/mysql/connection/stmt/iterator.rs | 8 +--- diesel/src/mysql/query_builder/mod.rs | 2 +- diesel/src/pg/connection/mod.rs | 24 ++++++----- .../pg/expression/extensions/interval_dsl.rs | 3 ++ diesel/src/pg/types/array.rs | 3 ++ diesel/src/pg/types/date_and_time/std_time.rs | 2 +- .../select_statement/dsl_impls.rs | 4 +- diesel/src/query_source/mod.rs | 3 ++ diesel/src/sqlite/connection/functions.rs | 3 ++ diesel/src/sqlite/connection/mod.rs | 4 +- diesel/src/sqlite/connection/raw.rs | 1 - diesel/src/sqlite/query_builder/mod.rs | 2 +- diesel_derives/src/as_changeset.rs | 9 +++-- diesel_derives/src/insertable.rs | 9 +++-- .../migrations_internals/src/lib.rs | 3 +- .../migrations_macros/src/embed_migrations.rs | 2 +- diesel_tests/tests/annotations.rs | 8 ++-- diesel_tests/tests/boxed_queries.rs | 4 +- diesel_tests/tests/errors.rs | 2 + diesel_tests/tests/expressions/ops.rs | 20 +++++----- diesel_tests/tests/internal_details.rs | 4 +- diesel_tests/tests/joins.rs | 40 ++++++++----------- .../tests/schema/backend_specifics.rs | 4 +- diesel_tests/tests/schema/mod.rs | 15 +++---- .../tests/schema/postgres_specific_schema.rs | 4 +- diesel_tests/tests/schema_dsl/structures.rs | 9 ++--- diesel_tests/tests/schema_inference.rs | 2 +- diesel_tests/tests/select.rs | 2 +- diesel_tests/tests/select_by.rs | 27 ++++++------- diesel_tests/tests/transactions.rs | 4 +- diesel_tests/tests/types_roundtrip.rs | 13 +++--- diesel_tests/tests/update.rs | 2 +- 35 files changed, 126 insertions(+), 128 deletions(-) diff --git a/diesel/src/connection/transaction_manager.rs b/diesel/src/connection/transaction_manager.rs index e63f7db43374..21306ccf7bd7 100644 --- a/diesel/src/connection/transaction_manager.rs +++ b/diesel/src/connection/transaction_manager.rs @@ -672,6 +672,9 @@ mod test { #[test] #[cfg(feature = "mysql")] + // This function uses a collect with side effects (spawning threads) + // so clippy is wrong here + #[allow(clippy::needless_collect)] fn mysql_transaction_depth_commits_tracked_properly_on_serialization_failure() { use crate::result::DatabaseErrorKind::SerializationFailure; use crate::result::Error::DatabaseError; @@ -775,6 +778,9 @@ mod test { #[test] #[cfg(feature = "mysql")] + // This function uses a collect with side effects (spawning threads) + // so clippy is wrong here + #[allow(clippy::needless_collect)] fn mysql_nested_transaction_depth_commits_tracked_properly_on_serialization_failure() { use crate::result::DatabaseErrorKind::SerializationFailure; use crate::result::Error::DatabaseError; diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index 1dc697aee1b8..8e736809d142 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -178,7 +178,6 @@ clippy::redundant_field_names, clippy::type_complexity )] -#![cfg_attr(test, allow(clippy::option_map_unwrap_or, clippy::result_unwrap_used))] #![warn( clippy::unwrap_used, clippy::print_stdout, @@ -191,6 +190,7 @@ clippy::items_after_statements, clippy::used_underscore_binding )] +#![cfg_attr(test, allow(clippy::map_unwrap_or, clippy::unwrap_used))] extern crate diesel_derives; diff --git a/diesel/src/mysql/connection/bind.rs b/diesel/src/mysql/connection/bind.rs index 2ca4c2d141e8..5a276a73676a 100644 --- a/diesel/src/mysql/connection/bind.rs +++ b/diesel/src/mysql/connection/bind.rs @@ -1289,8 +1289,6 @@ mod tests { #[test] fn check_json_bind() { - let conn = &mut crate::test_helpers::connection(); - table! { json_test { id -> Integer, @@ -1298,6 +1296,8 @@ mod tests { } } + let conn = &mut crate::test_helpers::connection(); + crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE") .execute(conn) .unwrap(); diff --git a/diesel/src/mysql/connection/stmt/iterator.rs b/diesel/src/mysql/connection/stmt/iterator.rs index 63f7feef39fc..eba7f8ae3ba8 100644 --- a/diesel/src/mysql/connection/stmt/iterator.rs +++ b/diesel/src/mysql/connection/stmt/iterator.rs @@ -301,24 +301,20 @@ fn fun_with_row_iters() { Row::get(&first_row, 0).unwrap(), Row::get(&first_row, 1).unwrap(), ); - let first_values = (first_fields.0.value(), first_fields.1.value()); + let _first_values = (first_fields.0.value(), first_fields.1.value()); assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_values); assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_fields); let second_row = row_iter.next().unwrap().unwrap(); let second_fields = ( Row::get(&second_row, 0).unwrap(), Row::get(&second_row, 1).unwrap(), ); - let second_values = (second_fields.0.value(), second_fields.1.value()); + let _second_values = (second_fields.0.value(), second_fields.1.value()); assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_values); assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_fields); assert!(row_iter.next().is_none()); diff --git a/diesel/src/mysql/query_builder/mod.rs b/diesel/src/mysql/query_builder/mod.rs index 37d73cc9275e..75d54c674ee5 100644 --- a/diesel/src/mysql/query_builder/mod.rs +++ b/diesel/src/mysql/query_builder/mod.rs @@ -26,7 +26,7 @@ impl QueryBuilder for MysqlQueryBuilder { fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> { self.push_sql("`"); - self.push_sql(&identifier.replace("`", "``")); + self.push_sql(&identifier.replace('`', "``")); self.push_sql("`"); Ok(()) } diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs index c24d3fcfc021..0e187eec8ab3 100644 --- a/diesel/src/pg/connection/mod.rs +++ b/diesel/src/pg/connection/mod.rs @@ -273,12 +273,8 @@ mod tests { let query = crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection); - if let Err(err) = query { - if let DatabaseError(_, string) = err { - assert_eq!(Some(26), string.statement_position()); - } else { - unreachable!(); - } + if let Err(DatabaseError(_, string)) = query { + assert_eq!(Some(26), string.statement_position()); } else { unreachable!(); } @@ -367,14 +363,14 @@ mod tests { let insert = query .insert_into(users::table) .into_columns((users::id, users::name)); - assert_eq!(true, insert.execute(connection).is_ok()); + assert!(insert.execute(connection).is_ok()); assert_eq!(1, connection.statement_cache.len()); let query = users::table.filter(users::id.eq(42)).into_boxed(); let insert = query .insert_into(users::table) .into_columns((users::id, users::name)); - assert_eq!(true, insert.execute(connection).is_ok()); + assert!(insert.execute(connection).is_ok()); assert_eq!(2, connection.statement_cache.len()); } @@ -392,7 +388,7 @@ mod tests { let insert = crate::insert_into(users::table).values((users::id.eq(42), users::name.eq("Foo"))); - assert_eq!(true, insert.execute(connection).is_ok()); + assert!(insert.execute(connection).is_ok()); assert_eq!(1, connection.statement_cache.len()); } @@ -410,7 +406,7 @@ mod tests { let insert = crate::insert_into(users::table) .values(vec![(users::id.eq(42), users::name.eq("Foo"))]); - assert_eq!(true, insert.execute(connection).is_ok()); + assert!(insert.execute(connection).is_ok()); assert_eq!(0, connection.statement_cache.len()); } @@ -428,7 +424,7 @@ mod tests { let insert = crate::insert_into(users::table).values([(users::id.eq(42), users::name.eq("Foo"))]); - assert_eq!(true, insert.execute(connection).is_ok()); + assert!(insert.execute(connection).is_ok()); assert_eq!(1, connection.statement_cache.len()); } @@ -585,6 +581,9 @@ mod tests { } #[test] + // This function uses collect with an side effect (spawning threads) + // so this is a false positive from clippy + #[allow(clippy::needless_collect)] fn postgres_transaction_depth_is_tracked_properly_on_serialization_failure() { use crate::pg::connection::raw::PgTransactionStatus; use crate::result::DatabaseErrorKind::SerializationFailure; @@ -692,6 +691,9 @@ mod tests { } #[test] + // This function uses collect with an side effect (spawning threads) + // so this is a false positive from clippy + #[allow(clippy::needless_collect)] fn postgres_transaction_depth_is_tracked_properly_on_nested_serialization_failure() { use crate::pg::connection::raw::PgTransactionStatus; use crate::result::DatabaseErrorKind::SerializationFailure; diff --git a/diesel/src/pg/expression/extensions/interval_dsl.rs b/diesel/src/pg/expression/extensions/interval_dsl.rs index 3d2c0d52c06f..c9fb66eee254 100644 --- a/diesel/src/pg/expression/extensions/interval_dsl.rs +++ b/diesel/src/pg/expression/extensions/interval_dsl.rs @@ -242,6 +242,9 @@ impl IntervalDsl for f64 { } #[cfg(test)] +// those macros define nested function +// that's fine for this test code +#[allow(clippy::items_after_statements)] mod tests { extern crate dotenvy; extern crate quickcheck; diff --git a/diesel/src/pg/types/array.rs b/diesel/src/pg/types/array.rs index 948560240df0..e80eb3216810 100644 --- a/diesel/src/pg/types/array.rs +++ b/diesel/src/pg/types/array.rs @@ -64,6 +64,9 @@ use crate::expression::AsExpression; macro_rules! array_as_expression { ($ty:ty, $sql_type:ty) => { #[cfg(feature = "postgres_backend")] + // this simplifies the macro implemntation + // as some macro calls use this lifetime + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b, ST: 'static, T> AsExpression<$sql_type> for $ty { type Expression = Bound<$sql_type, Self>; diff --git a/diesel/src/pg/types/date_and_time/std_time.rs b/diesel/src/pg/types/date_and_time/std_time.rs index bd1880142da7..a25ec6c5b154 100644 --- a/diesel/src/pg/types/date_and_time/std_time.rs +++ b/diesel/src/pg/types/date_and_time/std_time.rs @@ -31,7 +31,7 @@ impl FromSql for SystemTime { fn from_sql(bytes: PgValue<'_>) -> deserialize::Result { let usecs_passed = >::from_sql(bytes)?; let before_epoch = usecs_passed < 0; - let time_passed = usecs_to_duration(usecs_passed.abs() as u64); + let time_passed = usecs_to_duration(usecs_passed.unsigned_abs()); if before_epoch { Ok(pg_epoch() - time_passed) diff --git a/diesel/src/query_builder/select_statement/dsl_impls.rs b/diesel/src/query_builder/select_statement/dsl_impls.rs index 8353f1c4d150..b73338089da3 100644 --- a/diesel/src/query_builder/select_statement/dsl_impls.rs +++ b/diesel/src/query_builder/select_statement/dsl_impls.rs @@ -604,7 +604,7 @@ where } } -impl<'a, F, S, D, W, O, LOf, G, H> SelectNullableDsl +impl SelectNullableDsl for SelectStatement, D, W, O, LOf, G, H> { type Output = SelectStatement>, D, W, O, LOf, G, H>; @@ -624,7 +624,7 @@ impl<'a, F, S, D, W, O, LOf, G, H> SelectNullableDsl } } -impl<'a, F, D, W, O, LOf, G, H> SelectNullableDsl +impl SelectNullableDsl for SelectStatement, D, W, O, LOf, G, H> where F: AsQuerySource, diff --git a/diesel/src/query_source/mod.rs b/diesel/src/query_source/mod.rs index 1a1a07eebbeb..aaf1be08060f 100644 --- a/diesel/src/query_source/mod.rs +++ b/diesel/src/query_source/mod.rs @@ -32,6 +32,9 @@ pub trait QuerySource { /// The actual `FROM` clause of this type. This is typically only called in /// `QueryFragment` implementations. + // from here is something different than from in rust + // as this literally refercs to SQL from. + #[allow(clippy::wrong_self_convention)] fn from_clause(&self) -> Self::FromClause; /// The default select clause of this type, which should be used if no /// select clause was explicitly specified. This should always be a tuple of diff --git a/diesel/src/sqlite/connection/functions.rs b/diesel/src/sqlite/connection/functions.rs index 6fed6485f4f2..1fdf00043a77 100644 --- a/diesel/src/sqlite/connection/functions.rs +++ b/diesel/src/sqlite/connection/functions.rs @@ -96,6 +96,9 @@ where Args::build_from_row(&row).map_err(Error::DeserializationError) } +// clippy is wrong here, the let binding is required +// for lifetime reasons +#[allow(clippy::let_unit_value)] pub(super) fn process_sql_function_result( result: &'_ Ret, ) -> QueryResult> diff --git a/diesel/src/sqlite/connection/mod.rs b/diesel/src/sqlite/connection/mod.rs index eec42f1db571..1241ad58a89f 100644 --- a/diesel/src/sqlite/connection/mod.rs +++ b/diesel/src/sqlite/connection/mod.rs @@ -456,7 +456,7 @@ mod tests { #[test] fn register_noarg_function() { let connection = &mut SqliteConnection::establish(":memory:").unwrap(); - answer::register_impl(&connection, || 42).unwrap(); + answer::register_impl(connection, || 42).unwrap(); let answer = crate::select(answer()).get_result::(connection); assert_eq!(Ok(42), answer); @@ -465,7 +465,7 @@ mod tests { #[test] fn register_nondeterministic_noarg_function() { let connection = &mut SqliteConnection::establish(":memory:").unwrap(); - answer::register_nondeterministic_impl(&connection, || 42).unwrap(); + answer::register_nondeterministic_impl(connection, || 42).unwrap(); let answer = crate::select(answer()).get_result::(connection); assert_eq!(Ok(42), answer); diff --git a/diesel/src/sqlite/connection/raw.rs b/diesel/src/sqlite/connection/raw.rs index d7571b58f8f0..247f65abaa73 100644 --- a/diesel/src/sqlite/connection/raw.rs +++ b/diesel/src/sqlite/connection/raw.rs @@ -475,7 +475,6 @@ extern "C" fn run_aggregator_final_function for SqliteQueryBuilder { fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> { self.push_sql("`"); - self.push_sql(&identifier.replace("`", "``")); + self.push_sql(&identifier.replace('`', "``")); self.push_sql("`"); Ok(()) } diff --git a/diesel_derives/src/as_changeset.rs b/diesel_derives/src/as_changeset.rs index a180bd96fbb3..0344f9c5e81b 100644 --- a/diesel_derives/src/as_changeset.rs +++ b/diesel_derives/src/as_changeset.rs @@ -33,10 +33,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { let treat_none_as_null = model.treat_none_as_null(); - let (_, ty_generics, where_clause) = item.generics.split_for_impl(); - let mut impl_generics = item.generics.clone(); - impl_generics.params.push(parse_quote!('update)); - let (impl_generics, _, _) = impl_generics.split_for_impl(); + let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); let mut generate_borrowed_changeset = true; @@ -106,6 +103,10 @@ pub fn derive(item: DeriveInput) -> TokenStream { }; let changeset_borrowed = if generate_borrowed_changeset { + let mut impl_generics = item.generics.clone(); + impl_generics.params.push(parse_quote!('update)); + let (impl_generics, _, _) = impl_generics.split_for_impl(); + quote! { impl #impl_generics AsChangeset for &'update #struct_name #ty_generics #where_clause diff --git a/diesel_derives/src/insertable.rs b/diesel_derives/src/insertable.rs index 296a899743db..753a10737eff 100644 --- a/diesel_derives/src/insertable.rs +++ b/diesel_derives/src/insertable.rs @@ -13,10 +13,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { let table_name = &model.table_name(); let struct_name = &item.ident; - let (_, ty_generics, where_clause) = item.generics.split_for_impl(); - let mut impl_generics = item.generics.clone(); - impl_generics.params.push(parse_quote!('insert)); - let (impl_generics, ..) = impl_generics.split_for_impl(); + let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); let mut generate_borrowed_insert = true; @@ -97,6 +94,10 @@ pub fn derive(item: DeriveInput) -> TokenStream { }; let insert_borrowed = if generate_borrowed_insert { + let mut impl_generics = item.generics.clone(); + impl_generics.params.push(parse_quote!('insert)); + let (impl_generics, ..) = impl_generics.split_for_impl(); + quote! { impl #impl_generics Insertable<#table_name::table> for &'insert #struct_name #ty_generics diff --git a/diesel_migrations/migrations_internals/src/lib.rs b/diesel_migrations/migrations_internals/src/lib.rs index 75165ebb8d4c..a31d68e07817 100644 --- a/diesel_migrations/migrations_internals/src/lib.rs +++ b/diesel_migrations/migrations_internals/src/lib.rs @@ -59,8 +59,7 @@ pub fn search_for_migrations_directory(path: &Path) -> Option { if migration_path.is_dir() { Some(migration_path) } else { - path.parent() - .and_then(|p| search_for_migrations_directory(p)) + path.parent().and_then(search_for_migrations_directory) } } diff --git a/diesel_migrations/migrations_macros/src/embed_migrations.rs b/diesel_migrations/migrations_macros/src/embed_migrations.rs index 6f7d77db38e7..b59c58d79e3f 100644 --- a/diesel_migrations/migrations_macros/src/embed_migrations.rs +++ b/diesel_migrations/migrations_macros/src/embed_migrations.rs @@ -9,7 +9,7 @@ pub fn expand(path: String) -> proc_macro2::TokenStream { let migrations_path_opt = if path.is_empty() { None } else { - Some(path.replace("\"", "")) + Some(path.replace('"', "")) }; let migrations_expr = migration_directory_from_given_path(migrations_path_opt.as_deref()) .unwrap_or_else(|_| { diff --git a/diesel_tests/tests/annotations.rs b/diesel_tests/tests/annotations.rs index d614af850d2e..7eb2caebc67b 100644 --- a/diesel_tests/tests/annotations.rs +++ b/diesel_tests/tests/annotations.rs @@ -50,9 +50,10 @@ fn association_where_parent_and_child_have_underscores() { } impl SpecialPost { + #[allow(clippy::new_ret_no_self)] fn new(user_id: i32, title: &str) -> NewSpecialPost { NewSpecialPost { - user_id: user_id, + user_id, title: title.to_owned(), } } @@ -66,10 +67,9 @@ fn association_where_parent_and_child_have_underscores() { } impl SpecialComment { + #[allow(clippy::new_ret_no_self)] fn new(special_post_id: i32) -> NewSpecialComment { - NewSpecialComment { - special_post_id: special_post_id, - } + NewSpecialComment { special_post_id } } } diff --git a/diesel_tests/tests/boxed_queries.rs b/diesel_tests/tests/boxed_queries.rs index 1f5f838bc796..2805342dc95d 100644 --- a/diesel_tests/tests/boxed_queries.rs +++ b/diesel_tests/tests/boxed_queries.rs @@ -54,11 +54,11 @@ fn boxed_queries_can_differ_conditionally() { assert_eq!(Ok(expected_data), all); let ordered = source(Query::Ordered).load(connection); - let expected_data = vec![tess.clone(), sean.clone(), jim.clone()]; + let expected_data = vec![tess, sean.clone(), jim]; assert_eq!(Ok(expected_data), ordered); let one = source(Query::One).load(connection); - let expected_data = vec![sean.clone()]; + let expected_data = vec![sean]; assert_eq!(Ok(expected_data), one); } diff --git a/diesel_tests/tests/errors.rs b/diesel_tests/tests/errors.rs index fb3ab6fb5a7c..5379099b9db6 100644 --- a/diesel_tests/tests/errors.rs +++ b/diesel_tests/tests/errors.rs @@ -106,6 +106,8 @@ fn foreign_key_violation_correct_constraint_name() { #[test] #[cfg(feature = "postgres")] +// This is a false positive as there is a side effect of this collect (spawning threads) +#[allow(clippy::needless_collect)] fn isolation_errors_are_detected() { use diesel::result::DatabaseErrorKind::SerializationFailure; use diesel::result::Error::{CommitTransactionFailed, DatabaseError}; diff --git a/diesel_tests/tests/expressions/ops.rs b/diesel_tests/tests/expressions/ops.rs index 3019466344f6..781dfd713662 100644 --- a/diesel_tests/tests/expressions/ops.rs +++ b/diesel_tests/tests/expressions/ops.rs @@ -205,8 +205,8 @@ fn precedence_with_parens_is_maintained() { fn test_adding_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); - connection - .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + .execute(connection) .unwrap(); let expected_data = vec![2, 3]; @@ -223,8 +223,8 @@ fn test_adding_unsigned() { fn test_subtracting_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); - connection - .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + .execute(connection) .unwrap(); let expected_data = vec![0, 1]; @@ -241,8 +241,8 @@ fn test_subtracting_unsigned() { fn test_multiplying_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); - connection - .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + .execute(connection) .unwrap(); let expected_data = vec![1, 2]; @@ -259,8 +259,8 @@ fn test_multiplying_unsigned() { fn test_dividing_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); - connection - .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + .execute(connection) .unwrap(); let expected_data = vec![1, 2]; @@ -277,8 +277,8 @@ fn test_dividing_unsigned() { fn test_multiple_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); - connection - .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)") + .execute(connection) .unwrap(); let expected_data = vec![1, 1]; diff --git a/diesel_tests/tests/internal_details.rs b/diesel_tests/tests/internal_details.rs index 80f3cc33d7d0..6df380ded81c 100644 --- a/diesel_tests/tests/internal_details.rs +++ b/diesel_tests/tests/internal_details.rs @@ -62,6 +62,6 @@ fn ensure_sqlite_does_not_access_dropped_buffers() { let mut iter = Connection::load(connection, query).unwrap(); - assert_eq!(iter.next().is_some(), true); - assert_eq!(iter.next().is_none(), true); + assert!(iter.next().is_some()); + assert!(iter.next().is_none()); } diff --git a/diesel_tests/tests/joins.rs b/diesel_tests/tests/joins.rs index 70f4fe73e114..bc4a447c480d 100644 --- a/diesel_tests/tests/joins.rs +++ b/diesel_tests/tests/joins.rs @@ -301,6 +301,7 @@ fn select_right_side_with_nullable_column_first() { } #[test] +#[allow(clippy::type_complexity)] fn select_left_join_right_side_with_non_null_inside() { let connection = &mut connection_with_sean_and_tess_in_users_table(); @@ -467,7 +468,7 @@ fn selecting_parent_child_grandchild() { (sean.clone(), (posts[0].clone(), comments[2].clone())), (sean.clone(), (posts[2].clone(), comments[1].clone())), ]; - assert_eq!(Ok(expected.clone()), data); + assert_eq!(Ok(expected), data); let data = users::table .inner_join( @@ -523,8 +524,8 @@ fn selecting_parent_child_grandchild() { let expected = vec![ (sean.clone(), Some((posts[0].clone(), comments[0].clone()))), (sean.clone(), Some((posts[0].clone(), comments[2].clone()))), - (sean.clone(), Some((posts[2].clone(), comments[1].clone()))), - (tess.clone(), None), + (sean, Some((posts[2].clone(), comments[1].clone()))), + (tess, None), ]; assert_eq!(Ok(expected), data); } @@ -546,7 +547,7 @@ fn selecting_grandchild_child_parent() { let expected = vec![ (comments[0].clone(), (posts[0].clone(), sean.clone())), (comments[2].clone(), (posts[0].clone(), sean.clone())), - (comments[1].clone(), (posts[2].clone(), sean.clone())), + (comments[1].clone(), (posts[2].clone(), sean)), ]; assert_eq!(Ok(expected), data); } @@ -568,7 +569,7 @@ fn selecting_four_tables_deep() { .load(&mut connection); let expected = vec![( sean.clone(), - (posts[0].clone(), (comments[0].clone(), likes[0].clone())), + (posts[0].clone(), (comments[0].clone(), likes[0])), )]; assert_eq!(Ok(expected), data); @@ -579,19 +580,13 @@ fn selecting_four_tables_deep() { let expected = vec![ ( sean.clone(), - ( - posts[0].clone(), - (comments[0].clone(), Some(likes[0].clone())), - ), + (posts[0].clone(), (comments[0].clone(), Some(likes[0]))), ), ( sean.clone(), (posts[0].clone(), (comments[2].clone(), None)), ), - ( - sean.clone(), - (posts[2].clone(), (comments[1].clone(), None)), - ), + (sean, (posts[2].clone(), (comments[1].clone(), None))), ]; assert_eq!(Ok(expected), data); } @@ -611,7 +606,7 @@ fn selecting_parent_child_sibling() { .inner_join(posts::table) .inner_join(likes::table) .load(&mut connection); - let expected = vec![(tess.clone(), posts[1].clone(), likes[0].clone())]; + let expected = vec![(tess.clone(), posts[1].clone(), likes[0])]; assert_eq!(Ok(expected), data); let data = users::table @@ -621,8 +616,8 @@ fn selecting_parent_child_sibling() { .load(&mut connection); let expected = vec![ (sean.clone(), posts[0].clone(), None), - (sean.clone(), posts[2].clone(), None), - (tess.clone(), posts[1].clone(), Some(likes[0].clone())), + (sean, posts[2].clone(), None), + (tess, posts[1].clone(), Some(likes[0])), ]; assert_eq!(Ok(expected), data); } @@ -653,7 +648,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), ( posts[0].clone(), - Some((comments[0].clone(), Some(likes[0].clone()))), + Some((comments[0].clone(), Some(likes[0]))), None, ), ), @@ -665,10 +660,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), (posts[2].clone(), Some((comments[1].clone(), None)), None), ), - ( - tess.clone(), - (posts[1].clone(), None, Some(followings[0].clone())), - ), + (tess.clone(), (posts[1].clone(), None, Some(followings[0]))), ]; assert_eq!(Ok(expected), data); @@ -682,7 +674,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), ( posts[0].clone(), - Some((comments[0].clone(), Some(likes[0].clone()))), + Some((comments[0].clone(), Some(likes[0]))), ), Some(followings[0]), ), @@ -692,11 +684,11 @@ fn selecting_crazy_nested_joins() { Some(followings[0]), ), ( - sean.clone(), + sean, (posts[2].clone(), Some((comments[1].clone(), None))), Some(followings[0]), ), - (tess.clone(), (posts[1].clone(), None), None), + (tess, (posts[1].clone(), None), None), ]; assert_eq!(Ok(expected), data); } diff --git a/diesel_tests/tests/schema/backend_specifics.rs b/diesel_tests/tests/schema/backend_specifics.rs index 224e81882bee..4ef331bc25a7 100644 --- a/diesel_tests/tests/schema/backend_specifics.rs +++ b/diesel_tests/tests/schema/backend_specifics.rs @@ -15,8 +15,8 @@ pub struct Post { impl Post { pub fn new(id: i32, user_id: i32, title: &str, body: Option<&str>) -> Self { Post { - id: id, - user_id: user_id, + id, + user_id, title: title.to_string(), body: body.map(|s| s.to_string()), } diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs index 1533b52034b0..2c0d2068accf 100644 --- a/diesel_tests/tests/schema/mod.rs +++ b/diesel_tests/tests/schema/mod.rs @@ -32,7 +32,7 @@ pub struct User { impl User { pub fn new(id: i32, name: &str) -> Self { User { - id: id, + id, name: name.to_string(), hair_color: None, } @@ -40,7 +40,7 @@ impl User { pub fn with_hair_color(id: i32, name: &str, hair_color: &str) -> Self { User { - id: id, + id, name: name.to_string(), hair_color: Some(hair_color.to_string()), } @@ -72,8 +72,8 @@ pub struct Comment { impl Comment { pub fn new(id: i32, post_id: i32, text: &str) -> Self { Comment { - id: id, - post_id: post_id, + id, + post_id, text: text.into(), } } @@ -142,7 +142,7 @@ pub struct NewPost { impl NewPost { pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self { NewPost { - user_id: user_id, + user_id, title: title.into(), body: body.map(|b| b.into()), } @@ -165,10 +165,7 @@ pub struct FkTest { impl FkTest { pub fn new(id: i32, fk_id: i32) -> Self { - FkTest { - id: id, - fk_id: fk_id, - } + FkTest { id, fk_id } } } diff --git a/diesel_tests/tests/schema/postgres_specific_schema.rs b/diesel_tests/tests/schema/postgres_specific_schema.rs index 2d9152e6eedd..cbf812a949ff 100644 --- a/diesel_tests/tests/schema/postgres_specific_schema.rs +++ b/diesel_tests/tests/schema/postgres_specific_schema.rs @@ -16,8 +16,8 @@ pub struct Post { impl Post { pub fn new(id: i32, user_id: i32, title: &str, body: Option<&str>) -> Self { Post { - id: id, - user_id: user_id, + id, + user_id, title: title.to_string(), body: body.map(|s| s.to_string()), tags: Vec::new(), diff --git a/diesel_tests/tests/schema_dsl/structures.rs b/diesel_tests/tests/schema_dsl/structures.rs index ddd8b2e8bf55..2a629508373a 100644 --- a/diesel_tests/tests/schema_dsl/structures.rs +++ b/diesel_tests/tests/schema_dsl/structures.rs @@ -8,10 +8,7 @@ pub struct CreateTable<'a, Cols> { impl<'a, Cols> CreateTable<'a, Cols> { pub fn new(name: &'a str, columns: Cols) -> Self { - CreateTable { - name: name, - columns: columns, - } + CreateTable { name, columns } } } @@ -26,8 +23,8 @@ pub struct Column<'a, T> { impl<'a, T> Column<'a, T> { pub fn new(name: &'a str, type_name: &'a str) -> Self { Column { - name: name, - type_name: type_name, + name, + type_name, _marker: PhantomData, } } diff --git a/diesel_tests/tests/schema_inference.rs b/diesel_tests/tests/schema_inference.rs index 151ccd6eca02..37d255dadf9d 100644 --- a/diesel_tests/tests/schema_inference.rs +++ b/diesel_tests/tests/schema_inference.rs @@ -171,7 +171,7 @@ mod sqlite { let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); let inferred_datetime_types = InferredDatetimeTypes { - dt: dt, + dt, date: dt.date(), time: dt.time(), timestamp: dt, diff --git a/diesel_tests/tests/select.rs b/diesel_tests/tests/select.rs index eced99460a69..ad0e3683fac1 100644 --- a/diesel_tests/tests/select.rs +++ b/diesel_tests/tests/select.rs @@ -64,7 +64,7 @@ fn with_select_sql() { .execute(connection) .unwrap(); - assert_eq!(Ok(3), select_count.clone().first(connection)); + assert_eq!(Ok(3), select_count.first(connection)); } #[test] diff --git a/diesel_tests/tests/select_by.rs b/diesel_tests/tests/select_by.rs index b695ca31b4be..ce5886474507 100644 --- a/diesel_tests/tests/select_by.rs +++ b/diesel_tests/tests/select_by.rs @@ -245,7 +245,7 @@ fn selecting_parent_child_grandchild() { (sean.clone(), (posts[0].clone(), comments[2].clone())), (sean.clone(), (posts[2].clone(), comments[1].clone())), ]; - assert_eq!(Ok(expected.clone()), data); + assert_eq!(Ok(expected), data); let data = users::table .inner_join( @@ -305,8 +305,8 @@ fn selecting_parent_child_grandchild() { let expected = vec![ (sean.clone(), Some((posts[0].clone(), comments[0].clone()))), (sean.clone(), Some((posts[0].clone(), comments[2].clone()))), - (sean.clone(), Some((posts[2].clone(), comments[1].clone()))), - (tess.clone(), None), + (sean, Some((posts[2].clone(), comments[1].clone()))), + (tess, None), ]; assert_eq!(Ok(expected), data); } @@ -389,7 +389,7 @@ fn selecting_parent_child_grandchild_nested() { }, }, ]; - assert_eq!(Ok(expected.clone()), data); + assert_eq!(Ok(expected), data); #[derive(Queryable, Selectable, Clone, Debug, PartialEq)] #[diesel(table_name = users)] @@ -601,7 +601,7 @@ fn selecting_parent_child_grandchild_nested() { User4 { id: sean.id, name: sean.name.clone(), - hair_color: sean.hair_color.clone(), + hair_color: sean.hair_color, post: Some(Post4 { id: posts[2].id, user_id: posts[2].user_id, @@ -613,7 +613,7 @@ fn selecting_parent_child_grandchild_nested() { User4 { id: tess.id, name: tess.name.clone(), - hair_color: tess.hair_color.clone(), + hair_color: tess.hair_color, post: None, }, ]; @@ -640,7 +640,7 @@ fn selecting_grandchild_child_parent() { let expected = vec![ (comments[0].clone(), (posts[0].clone(), sean.clone())), (comments[2].clone(), (posts[0].clone(), sean.clone())), - (comments[1].clone(), (posts[2].clone(), sean.clone())), + (comments[1].clone(), (posts[2].clone(), sean)), ]; assert_eq!(Ok(expected), data); } @@ -677,7 +677,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), ( posts[0].clone(), - Some((comments[0].clone(), Some(likes[0].clone()))), + Some((comments[0].clone(), Some(likes[0]))), None, ), ), @@ -689,10 +689,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), (posts[2].clone(), Some((comments[1].clone(), None)), None), ), - ( - tess.clone(), - (posts[1].clone(), None, Some(followings[0].clone())), - ), + (tess.clone(), (posts[1].clone(), None, Some(followings[0]))), ]; assert_eq!(Ok(expected), data); @@ -711,7 +708,7 @@ fn selecting_crazy_nested_joins() { sean.clone(), ( posts[0].clone(), - Some((comments[0].clone(), Some(likes[0].clone()))), + Some((comments[0].clone(), Some(likes[0]))), ), Some(followings[0]), ), @@ -721,11 +718,11 @@ fn selecting_crazy_nested_joins() { Some(followings[0]), ), ( - sean.clone(), + sean, (posts[2].clone(), Some((comments[1].clone(), None))), Some(followings[0]), ), - (tess.clone(), (posts[1].clone(), None), None), + (tess, (posts[1].clone(), None), None), ]; assert_eq!(Ok(expected), data); } diff --git a/diesel_tests/tests/transactions.rs b/diesel_tests/tests/transactions.rs index 11330b92cc93..7bcc8cc531a8 100644 --- a/diesel_tests/tests/transactions.rs +++ b/diesel_tests/tests/transactions.rs @@ -5,7 +5,7 @@ use diesel::*; #[test] #[cfg(not(feature = "sqlite"))] // FIXME: This test is only valid when operating on a file and not :memory: fn transaction_executes_fn_in_a_sql_transaction() { - const TEST_NAME: &'static str = "transaction_executes_fn_in_a_sql_transaction"; + const TEST_NAME: &str = "transaction_executes_fn_in_a_sql_transaction"; let conn1 = &mut connection_without_transaction(); let conn2 = &mut connection_without_transaction(); setup_test_table(conn1, TEST_NAME); @@ -98,7 +98,7 @@ fn transaction_rollback_returns_error() { #[test] fn transactions_can_be_nested() { let connection = &mut connection_without_transaction(); - const TEST_NAME: &'static str = "transactions_can_be_nested"; + const TEST_NAME: &str = "transactions_can_be_nested"; setup_test_table(connection, TEST_NAME); fn get_count(connection: &mut TestConnection) -> i64 { count_test_table(connection, TEST_NAME) diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index bc752aaa9467..9528b4b51876 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -69,6 +69,7 @@ macro_rules! test_round_trip { }; ($test_name:ident, $sql_type:ty, $tpe:ty, $map_fn:ident, $cmp: expr) => { #[test] + #[allow(clippy::type_complexity)] fn $test_name() { use diesel::sql_types::*; @@ -228,6 +229,7 @@ mod pg_types { test_round_trip!(json_roundtrips, Json, SerdeWrapper, mk_serde_json); test_round_trip!(jsonb_roundtrips, Jsonb, SerdeWrapper, mk_serde_json); + #[allow(clippy::type_complexity)] fn mk_uuid(data: (u32, u16, u16, (u8, u8, u8, u8, u8, u8, u8, u8))) -> self::uuid::Uuid { let a = data.3; let b = [a.0, a.1, a.2, a.3, a.4, a.5, a.6, a.7]; @@ -300,12 +302,7 @@ mod pg_types { if r < earliest_pg_date { let diff = earliest_pg_date - r; r = earliest_pg_date + diff; - } - /*else if r > latest_pg_date { - let diff = r - latest_pg_date; - r = earliest_pg_date + diff; - }*/ - else { + } else { break; } } @@ -457,7 +454,7 @@ mod mysql_types { pub fn mk_naive_timestamp((mut seconds, nanos): (i64, u32)) -> NaiveDateTime { // https://dev.mysql.com/doc/refman/8.0/en/datetime.html let earliest_mysql_date = NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 1); - let latest_mysql_date = NaiveDate::from_ymd(2038, 1, 19).and_hms(03, 14, 7); + let latest_mysql_date = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 7); if seconds != 0 { seconds = earliest_mysql_date.timestamp() @@ -600,7 +597,7 @@ pub fn mk_naive_date(days: u32) -> NaiveDate { #[cfg(feature = "mysql")] pub fn mk_naive_date(days: u32) -> NaiveDate { - let earliest_mysql_date = NaiveDate::from_ymd(1000, 01, 01); + let earliest_mysql_date = NaiveDate::from_ymd(1000, 1, 1); let latest_mysql_date = NaiveDate::from_ymd(9999, 12, 31); let num_days_representable = latest_mysql_date .signed_duration_since(earliest_mysql_date) diff --git a/diesel_tests/tests/update.rs b/diesel_tests/tests/update.rs index 35c0aa3fede8..229ae6130c0d 100644 --- a/diesel_tests/tests/update.rs +++ b/diesel_tests/tests/update.rs @@ -206,7 +206,7 @@ fn sql_syntax_is_correct_when_option_field_comes_mixed_with_non_option() { .first::(connection) .unwrap(); - let expected_post = Post::new(post.id, sean.id, "Hello".into(), Some("earth".into())); + let expected_post = Post::new(post.id, sean.id, "Hello", Some("earth")); assert_eq!(expected_post, post); } From a4c4c1d52684c3e9ea3f26b100e83eeaa03f652a Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 23 May 2022 15:44:10 +0200 Subject: [PATCH 031/107] Minor fixes --- .github/workflows/ci.yml | 8 +++--- diesel/src/mysql/connection/stmt/iterator.rs | 8 ++++-- diesel/src/mysql/value.rs | 2 +- .../src/infer_schema_internals/inference.rs | 4 +-- .../information_schema.rs | 8 +++--- .../src/infer_schema_internals/sqlite.rs | 6 ++--- diesel_cli/src/main.rs | 2 +- diesel_cli/src/print_schema.rs | 2 ++ diesel_cli/tests/migration_list.rs | 25 ++++++++++--------- diesel_cli/tests/print_schema.rs | 1 + diesel_cli/tests/support/command.rs | 2 +- diesel_cli/tests/support/mod.rs | 3 +-- diesel_cli/tests/support/mysql_database.rs | 3 ++- diesel_cli/tests/support/postgres_database.rs | 3 ++- diesel_cli/tests/support/project_builder.rs | 2 +- diesel_cli/tests/support/sqlite_database.rs | 1 + diesel_derives/tests/as_changeset.rs | 6 ++--- diesel_derives/tests/queryable_by_name.rs | 1 + .../migrations_macros/src/lib.rs | 2 +- 19 files changed, 50 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35ddc95dbb62..271964dd0a48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -377,14 +377,14 @@ jobs: find ~/.cargo/registry -iname "*clippy.toml" -delete - name: Run clippy - run: + run: | cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "postgres diesel/postgres" cargo clippy --tests --manifest-path diesel/Cargo.toml --features "postgres" cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "postgres diesel/postgres" cargo clippy --tests --manifest-path diesel_migrations/migrations_internals/Cargo.toml cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "postgres diesel/postgres" cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres" - cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres" cargo clippy --tests --manifest-path examples/postgres/getting_started_step1/Cargo.toml cargo clippy --tests --manifest-path examples/postgres/getting_started_step2/Cargo.toml @@ -399,7 +399,7 @@ jobs: cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "sqlite diesel/sqlite" cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "sqlite diesel/sqlite" cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite" - cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite" cargo clippy --tests --manifest-path examples/sqlite/getting_started_step1/Cargo.toml cargo clippy --tests --manifest-path examples/sqlite/getting_started_step2/Cargo.toml @@ -411,7 +411,7 @@ jobs: cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "mysql diesel/mysql" cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "mysql diesel/mysql" cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql" - cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" + cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql" cargo clippy --tests --manifest-path examples/mysql/getting_started_step1/Cargo.toml cargo clippy --tests --manifest-path examples/mysql/getting_started_step2/Cargo.toml diff --git a/diesel/src/mysql/connection/stmt/iterator.rs b/diesel/src/mysql/connection/stmt/iterator.rs index eba7f8ae3ba8..ed3b89ece8bf 100644 --- a/diesel/src/mysql/connection/stmt/iterator.rs +++ b/diesel/src/mysql/connection/stmt/iterator.rs @@ -301,20 +301,24 @@ fn fun_with_row_iters() { Row::get(&first_row, 0).unwrap(), Row::get(&first_row, 1).unwrap(), ); - let _first_values = (first_fields.0.value(), first_fields.1.value()); + let first_values = (first_fields.0.value(), first_fields.1.value()); assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_values); assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_fields); let second_row = row_iter.next().unwrap().unwrap(); let second_fields = ( Row::get(&second_row, 0).unwrap(), Row::get(&second_row, 1).unwrap(), ); - let _second_values = (second_fields.0.value(), second_fields.1.value()); + let second_values = (second_fields.0.value(), second_fields.1.value()); assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_values); assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(second_fields); assert!(row_iter.next().is_none()); diff --git a/diesel/src/mysql/value.rs b/diesel/src/mysql/value.rs index 8053c2c99634..cc0d4cf5335e 100644 --- a/diesel/src/mysql/value.rs +++ b/diesel/src/mysql/value.rs @@ -4,7 +4,7 @@ use crate::deserialize; use std::error::Error; /// Raw mysql value as received from the database -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct MysqlValue<'a> { raw: &'a [u8], tpe: MysqlType, diff --git a/diesel_cli/src/infer_schema_internals/inference.rs b/diesel_cli/src/infer_schema_internals/inference.rs index ae74e0147999..4b6b5da313ff 100644 --- a/diesel_cli/src/infer_schema_internals/inference.rs +++ b/diesel_cli/src/infer_schema_internals/inference.rs @@ -97,7 +97,7 @@ fn get_column_information( } }; if let Err(NotFound) = column_info { - Err(format!("no table exists named {}", table.to_string()).into()) + Err(format!("no table exists named {}", table).into()) } else { column_info.map_err(Into::into) } @@ -137,7 +137,7 @@ pub(crate) fn get_primary_keys( Err(format!( "Diesel only supports tables with primary keys. \ Table {} has no primary key", - table.to_string() + table, ) .into()) } else { diff --git a/diesel_cli/src/infer_schema_internals/information_schema.rs b/diesel_cli/src/infer_schema_internals/information_schema.rs index 0587164bca9b..51f999f7c637 100644 --- a/diesel_cli/src/infer_schema_internals/information_schema.rs +++ b/diesel_cli/src/infer_schema_internals/information_schema.rs @@ -559,7 +559,7 @@ mod tests { let id = ColumnInformation::new("id", "int4", pg_catalog.clone(), false); let text_col = ColumnInformation::new("text_col", "varchar", pg_catalog.clone(), true); let not_null = ColumnInformation::new("not_null", "text", pg_catalog.clone(), false); - let array_col = ColumnInformation::new("array_col", "_varchar", pg_catalog.clone(), false); + let array_col = ColumnInformation::new("array_col", "_varchar", pg_catalog, false); assert_eq!( Ok(vec![id, text_col, not_null]), get_table_data(&mut connection, &table_1, &ColumnSorting::OrdinalPosition) @@ -594,14 +594,14 @@ mod tests { let table_3 = TableName::new("table_3", "test_schema"); let fk_one = ForeignKeyConstraint { child_table: table_2.clone(), - parent_table: table_1.clone(), + parent_table: table_1, foreign_key: "fk_one".into(), foreign_key_rust_name: "fk_one".into(), primary_key: "id".into(), }; let fk_two = ForeignKeyConstraint { - child_table: table_3.clone(), - parent_table: table_2.clone(), + child_table: table_3, + parent_table: table_2, foreign_key: "fk_two".into(), foreign_key_rust_name: "fk_two".into(), primary_key: "id".into(), diff --git a/diesel_cli/src/infer_schema_internals/sqlite.rs b/diesel_cli/src/infer_schema_internals/sqlite.rs index 49e8636d9522..3db89e26a933 100644 --- a/diesel_cli/src/infer_schema_internals/sqlite.rs +++ b/diesel_cli/src/infer_schema_internals/sqlite.rs @@ -368,14 +368,14 @@ fn load_foreign_key_constraints_loads_foreign_keys() { let table_3 = TableName::from_name("table_3"); let fk_one = ForeignKeyConstraint { child_table: table_2.clone(), - parent_table: table_1.clone(), + parent_table: table_1, foreign_key: "fk_one".into(), foreign_key_rust_name: "fk_one".into(), primary_key: "id".into(), }; let fk_two = ForeignKeyConstraint { - child_table: table_3.clone(), - parent_table: table_2.clone(), + child_table: table_3, + parent_table: table_2, foreign_key: "fk_two".into(), foreign_key_rust_name: "fk_two".into(), primary_key: "id".into(), diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs index 0e2346ddea21..f56362b1d670 100644 --- a/diesel_cli/src/main.rs +++ b/diesel_cli/src/main.rs @@ -11,7 +11,7 @@ clippy::used_underscore_binding, missing_copy_implementations )] -#![cfg_attr(test, allow(clippy::result_unwrap_used))] +#![cfg_attr(test, allow(clippy::unwrap_used))] mod config; diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index a4b5a9694015..f9ba0ff393c0 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -289,6 +289,7 @@ impl Display for CustomTypeList { Ok(()) } #[cfg(feature = "sqlite")] + #[allow(clippy::print_in_format_impl)] Backend::Sqlite => { let _ = (&f, self.with_docs); for t in &self.types_sorted { @@ -302,6 +303,7 @@ impl Display for CustomTypeList { ) } #[cfg(feature = "mysql")] + #[allow(clippy::print_in_format_impl)] Backend::Mysql => { let _ = (&f, self.with_docs); for t in &self.types_sorted { diff --git a/diesel_cli/tests/migration_list.rs b/diesel_cli/tests/migration_list.rs index bc4c94e23f65..c52a5c61e55c 100644 --- a/diesel_cli/tests/migration_list.rs +++ b/diesel_cli/tests/migration_list.rs @@ -1,3 +1,4 @@ +#![allow(clippy::expect_fun_call)] use chrono::Utc; use std::thread::sleep; use std::time::Duration; @@ -95,10 +96,10 @@ fn migration_list_orders_unknown_timestamps_last() { p.create_migration(&tag1, "", ""); let tag4 = "abc_migration4"; - p.create_migration(&tag4, "", ""); + p.create_migration(tag4, "", ""); let tag5 = "zzz_migration5"; - p.create_migration(&tag5, "", ""); + p.create_migration(tag5, "", ""); sleep(Duration::from_millis(1100)); @@ -113,7 +114,7 @@ fn migration_list_orders_unknown_timestamps_last() { let result = p.command("migration").arg("list").run(); assert!(result.is_success(), "Result was unsuccessful {:?}", result); let output = result.stdout(); - assert_tags_in_order(output, &[&tag1, &tag2, &tag3, &tag4, &tag5]); + assert_tags_in_order(output, &[&tag1, &tag2, &tag3, tag4, tag5]); } #[test] @@ -125,19 +126,19 @@ fn migration_list_orders_nontimestamp_versions_alphabetically() { p.command("setup").run(); let tag4 = "a_migration"; - p.create_migration(&tag4, "", ""); + p.create_migration(tag4, "", ""); let tag6 = "bc_migration"; - p.create_migration(&tag6, "", ""); + p.create_migration(tag6, "", ""); let tag5 = "aa_migration"; - p.create_migration(&tag5, "", ""); + p.create_migration(tag5, "", ""); let tag1 = "!wow_migration"; - p.create_migration(&tag1, "", ""); + p.create_migration(tag1, "", ""); let tag3 = "7letters"; - p.create_migration(&tag3, "", ""); + p.create_migration(tag3, "", ""); let tag2 = format!("{}_stamped_migration", Utc::now().format(TIMESTAMP_FORMAT)); p.create_migration(&tag2, "", ""); @@ -145,7 +146,7 @@ fn migration_list_orders_nontimestamp_versions_alphabetically() { let result = p.command("migration").arg("list").run(); assert!(result.is_success(), "Result was unsuccessful {:?}", result); let output = result.stdout(); - assert_tags_in_order(output, &[&tag1, &tag2, &tag3, &tag4, &tag5, &tag6]); + assert_tags_in_order(output, &[tag1, &tag2, tag3, tag4, tag5, tag6]); } #[test] @@ -157,15 +158,15 @@ fn migration_list_orders_old_and_new_timestamp_forms_mixed_correctly() { p.command("setup").run(); let tag1 = "20170505070309_migration"; - p.create_migration(&tag1, "", ""); + p.create_migration(tag1, "", ""); let tag2 = "2017-11-23-064836_migration"; - p.create_migration(&tag2, "", ""); + p.create_migration(tag2, "", ""); let result = p.command("migration").arg("list").run(); assert!(result.is_success(), "Result was unsuccessful {:?}", result); let output = result.stdout(); - assert_tags_in_order(output, &[&tag1, &tag2]); + assert_tags_in_order(output, &[tag1, tag2]); } #[test] diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs index fdaa90f9b72b..86cf134040e2 100644 --- a/diesel_cli/tests/print_schema.rs +++ b/diesel_cli/tests/print_schema.rs @@ -1,3 +1,4 @@ +#![allow(clippy::expect_fun_call)] use std::fs::File; use std::io::prelude::*; use std::path::{Path, PathBuf}; diff --git a/diesel_cli/tests/support/command.rs b/diesel_cli/tests/support/command.rs index 08abac881ecd..e2aac56c5ba4 100644 --- a/diesel_cli/tests/support/command.rs +++ b/diesel_cli/tests/support/command.rs @@ -46,7 +46,7 @@ impl TestCommand { .build_command() .output() .expect("failed to execute process"); - CommandResult { output: output } + CommandResult { output } } fn build_command(&self) -> Command { diff --git a/diesel_cli/tests/support/mod.rs b/diesel_cli/tests/support/mod.rs index 6c6e5cd5b674..56f407bf9cce 100644 --- a/diesel_cli/tests/support/mod.rs +++ b/diesel_cli/tests/support/mod.rs @@ -4,9 +4,8 @@ macro_rules! try_drop { match $e { Ok(x) => x, Err(e) => { - use std::io::{stderr, Write}; if ::std::thread::panicking() { - write!(stderr(), "{}: {:?}", $msg, e).unwrap(); + eprintln!("{}: {:?}", $msg, e); return; } else { panic!("{}: {:?}", $msg, e); diff --git a/diesel_cli/tests/support/mysql_database.rs b/diesel_cli/tests/support/mysql_database.rs index 93ac35423d21..9618876f22c1 100644 --- a/diesel_cli/tests/support/mysql_database.rs +++ b/diesel_cli/tests/support/mysql_database.rs @@ -1,3 +1,4 @@ +#![allow(clippy::expect_fun_call)] use diesel::connection::SimpleConnection; use diesel::dsl::sql; use diesel::sql_types::Bool; @@ -50,7 +51,7 @@ impl Database { } fn split_url(&self) -> (String, String) { - let mut split: Vec<&str> = self.url.split("/").collect(); + let mut split: Vec<&str> = self.url.split('/').collect(); let database = split.pop().unwrap(); let mysql_url = format!("{}/{}", split.join("/"), "information_schema"); (database.into(), mysql_url) diff --git a/diesel_cli/tests/support/postgres_database.rs b/diesel_cli/tests/support/postgres_database.rs index e3d1b074dc2b..e2eede17b389 100644 --- a/diesel_cli/tests/support/postgres_database.rs +++ b/diesel_cli/tests/support/postgres_database.rs @@ -1,3 +1,4 @@ +#![allow(clippy::expect_fun_call)] use diesel::connection::SimpleConnection; use diesel::dsl::sql; use diesel::sql_types::Bool; @@ -49,7 +50,7 @@ impl Database { } fn split_url(&self) -> (String, String) { - let mut split: Vec<&str> = self.url.split("/").collect(); + let mut split: Vec<&str> = self.url.split('/').collect(); let database = split.pop().unwrap(); let postgres_url = format!("{}/{}", split.join("/"), "postgres"); (database.into(), postgres_url) diff --git a/diesel_cli/tests/support/project_builder.rs b/diesel_cli/tests/support/project_builder.rs index b502d482f5cb..c9271ab1a298 100644 --- a/diesel_cli/tests/support/project_builder.rs +++ b/diesel_cli/tests/support/project_builder.rs @@ -84,7 +84,7 @@ impl Project { .read_dir() .expect("Error reading directory") .map(|e| Migration { - path: e.expect("error reading entry").path().into(), + path: e.expect("error reading entry").path(), }) .collect() } diff --git a/diesel_cli/tests/support/sqlite_database.rs b/diesel_cli/tests/support/sqlite_database.rs index fe18bf822e94..f039aa8242b5 100644 --- a/diesel_cli/tests/support/sqlite_database.rs +++ b/diesel_cli/tests/support/sqlite_database.rs @@ -1,3 +1,4 @@ +#![allow(clippy::expect_fun_call)] use diesel::connection::SimpleConnection; use diesel::dsl::sql; use diesel::sql_types::Bool; diff --git a/diesel_derives/tests/as_changeset.rs b/diesel_derives/tests/as_changeset.rs index cd68ef01ed52..e366863a933e 100644 --- a/diesel_derives/tests/as_changeset.rs +++ b/diesel_derives/tests/as_changeset.rs @@ -226,9 +226,9 @@ fn with_serialize_as() { #[diesel(sql_type = sql_types::Text)] struct UppercaseString(pub String); - impl Into for String { - fn into(self) -> UppercaseString { - UppercaseString(self.to_uppercase()) + impl From for UppercaseString { + fn from(val: String) -> Self { + UppercaseString(val.to_uppercase()) } } diff --git a/diesel_derives/tests/queryable_by_name.rs b/diesel_derives/tests/queryable_by_name.rs index e070e3a5ae24..9ccecffca622 100644 --- a/diesel_derives/tests/queryable_by_name.rs +++ b/diesel_derives/tests/queryable_by_name.rs @@ -1,3 +1,4 @@ +#![allow(clippy::blacklisted_name)] use diesel::sql_types::Integer; use diesel::*; diff --git a/diesel_migrations/migrations_macros/src/lib.rs b/diesel_migrations/migrations_macros/src/lib.rs index 7a0223d1acff..8fac4329c09d 100644 --- a/diesel_migrations/migrations_macros/src/lib.rs +++ b/diesel_migrations/migrations_macros/src/lib.rs @@ -20,7 +20,7 @@ missing_debug_implementations, missing_copy_implementations )] -#![cfg_attr(test, allow(clippy::option_unwrap_used, clippy::result_unwrap_used))] +#![cfg_attr(test, allow(clippy::unwrap_used))] extern crate proc_macro; mod embed_migrations; From ecd62944b45c9df34701eb89dab9b4dfe2a5d0ae Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 23 May 2022 17:16:47 +0200 Subject: [PATCH 032/107] Minor fixes --- .github/workflows/ci.yml | 23 ++++++++++++-------- diesel/src/mysql/connection/stmt/iterator.rs | 2 +- diesel_tests/Cargo.toml | 2 +- diesel_tests/tests/associations.rs | 2 +- diesel_tests/tests/expressions/ops.rs | 10 +++++++++ diesel_tests/tests/types.rs | 5 +++++ diesel_tests/tests/types_roundtrip.rs | 4 +++- examples/mysql/all_about_inserts/src/lib.rs | 20 ++++++++--------- examples/sqlite/all_about_inserts/src/lib.rs | 14 ++++++------ 9 files changed, 52 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 271964dd0a48..d8209944a2f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -369,6 +369,11 @@ jobs: run: | sudo apt-get update sudo apt-get -y install libsqlite3-dev libpq-dev libmysqlclient-dev + - name: Set environment variables + shell: bash + run: | + echo "RUSTFLAGS=-D warnings" >> $GITHUB_ENV + echo "RUSTDOCFLAGS=-D warnings" >> $GITHUB_ENV - name: Remove potential newer clippy.toml from dependencies run: | @@ -386,9 +391,9 @@ jobs: cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres" cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres" - cargo clippy --tests --manifest-path examples/postgres/getting_started_step1/Cargo.toml - cargo clippy --tests --manifest-path examples/postgres/getting_started_step2/Cargo.toml - cargo clippy --tests --manifest-path examples/postgres/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/getting_started_step_1/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/getting_started_step_2/Cargo.toml + cargo clippy --tests --manifest-path examples/postgres/getting_started_step_3/Cargo.toml cargo clippy --tests --manifest-path examples/postgres/advanced-blog-cli/Cargo.toml cargo clippy --tests --manifest-path examples/postgres/all_about_inserts/Cargo.toml cargo clippy --tests --manifest-path examples/postgres/all_about_updates/Cargo.toml @@ -401,9 +406,9 @@ jobs: cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite" cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite" - cargo clippy --tests --manifest-path examples/sqlite/getting_started_step1/Cargo.toml - cargo clippy --tests --manifest-path examples/sqlite/getting_started_step2/Cargo.toml - cargo clippy --tests --manifest-path examples/sqlite/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_1/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_2/Cargo.toml + cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_3/Cargo.toml cargo clippy --tests --manifest-path examples/sqlite/all_about_inserts/Cargo.toml cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "mysql diesel/mysql" @@ -413,9 +418,9 @@ jobs: cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql" cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" --no-default-features cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql" - cargo clippy --tests --manifest-path examples/mysql/getting_started_step1/Cargo.toml - cargo clippy --tests --manifest-path examples/mysql/getting_started_step2/Cargo.toml - cargo clippy --tests --manifest-path examples/mysql/getting_started_step3/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/getting_started_step_1/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/getting_started_step_2/Cargo.toml + cargo clippy --tests --manifest-path examples/mysql/getting_started_step_3/Cargo.toml cargo clippy --tests --manifest-path examples/mysql/all_about_inserts/Cargo.toml - name: Check formating diff --git a/diesel/src/mysql/connection/stmt/iterator.rs b/diesel/src/mysql/connection/stmt/iterator.rs index ed3b89ece8bf..63f7feef39fc 100644 --- a/diesel/src/mysql/connection/stmt/iterator.rs +++ b/diesel/src/mysql/connection/stmt/iterator.rs @@ -316,7 +316,7 @@ fn fun_with_row_iters() { let second_values = (second_fields.0.value(), second_fields.1.value()); assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_values); + std::mem::drop(second_values); assert!(row_iter.next().unwrap().is_err()); std::mem::drop(second_fields); diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 588225e428ae..1a8610bf1007 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -14,7 +14,7 @@ diesel = { path = "../diesel", default-features = false, features = ["quickcheck diesel_migrations = { path = "../diesel_migrations" } dotenvy = "0.15" quickcheck = "1.0.3" -uuid = { version = ">=0.7.0, <2.0.0" } +uuid = { version = "1.0.0" } serde_json = { version=">=0.9, <2.0" } ipnetwork = ">=0.12.2, <0.19.0" bigdecimal = ">= 0.0.13, < 0.4.0" diff --git a/diesel_tests/tests/associations.rs b/diesel_tests/tests/associations.rs index 4079f63d446c..fa204ce0ec8d 100644 --- a/diesel_tests/tests/associations.rs +++ b/diesel_tests/tests/associations.rs @@ -134,7 +134,7 @@ fn grouping_associations_maintains_ordering() { assert_eq!(expected_data, users_and_posts); // Test when sorted manually - let users = vec![sean.clone(), tess.clone()]; + let users = vec![sean, tess]; let mut posts = Post::belonging_to(&users) .load::(&mut connection) .unwrap(); diff --git a/diesel_tests/tests/expressions/ops.rs b/diesel_tests/tests/expressions/ops.rs index 781dfd713662..3a82564c6826 100644 --- a/diesel_tests/tests/expressions/ops.rs +++ b/diesel_tests/tests/expressions/ops.rs @@ -116,6 +116,8 @@ fn test_adding_nullables() { } #[test] +#[allow(clippy::eq_op)] +// As this creates a sql expression clippy is wrong here fn test_subtracting_nullables() { use crate::schema::nullable_table::dsl::*; let connection = &mut connection_with_nullable_table_data(); @@ -156,6 +158,8 @@ fn test_multiplying_nullables() { } #[test] +#[allow(clippy::eq_op)] +// As this creates a sql expression clippy is wrong here fn test_dividing_nullables() { use crate::schema::nullable_table::dsl::*; let connection = &mut connection_with_nullable_table_data(); @@ -220,6 +224,8 @@ fn test_adding_unsigned() { #[test] #[cfg(feature = "mysql")] +#[allow(clippy::eq_op)] +// As this creates a sql expression clippy is wrong here fn test_subtracting_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); @@ -238,6 +244,8 @@ fn test_subtracting_unsigned() { #[test] #[cfg(feature = "mysql")] +#[allow(clippy::identity_op)] +// As this creates a sql expression clippy is wrong here fn test_multiplying_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); @@ -256,6 +264,8 @@ fn test_multiplying_unsigned() { #[test] #[cfg(feature = "mysql")] +#[allow(clippy::identity_op, clippy::eq_op)] +// As this creates a sql expression clippy is wrong here fn test_dividing_unsigned() { use crate::schema::unsigned_table::dsl::*; let connection = &mut connection(); diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index 01250036d61c..91224a04efc1 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -381,6 +381,7 @@ use std::{f32, f64}; #[test] #[cfg(feature = "postgres")] +#[allow(clippy::float_cmp)] fn f32_from_sql() { assert_eq!(0.0, query_single_value::("0.0::real")); assert_eq!(0.5, query_single_value::("0.5::real")); @@ -398,6 +399,7 @@ fn f32_from_sql() { #[test] #[cfg(any(feature = "mysql", feature = "sqlite"))] +#[allow(clippy::float_cmp)] fn f32_from_sql() { assert_eq!(0.0, query_single_value::("0.0")); assert_eq!(0.5, query_single_value::("0.5")); @@ -412,6 +414,7 @@ fn f32_from_sql() { #[test] #[cfg(feature = "postgres")] +#[allow(clippy::float_cmp)] fn f32_to_sql() { assert!(query_to_sql_equality::("0.0::real", 0.0)); assert!(query_to_sql_equality::("0.5::real", 0.5)); @@ -458,6 +461,7 @@ fn f32_to_sql() { #[test] #[cfg(feature = "postgres")] +#[allow(clippy::float_cmp)] fn f64_from_sql() { assert_eq!( 0.0, @@ -481,6 +485,7 @@ fn f64_from_sql() { #[test] #[cfg(any(feature = "mysql", feature = "sqlite"))] +#[allow(clippy::float_cmp)] fn f64_from_sql() { assert_eq!(0.0, query_single_value::("0.0")); assert_eq!(0.5, query_single_value::("0.5")); diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index 9528b4b51876..de5ea95737bb 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -92,6 +92,7 @@ macro_rules! test_round_trip { }; } +#[allow(clippy::float_cmp)] pub fn f32_ne(a: &f32, b: &f32) -> bool { if a.is_nan() && b.is_nan() { false @@ -100,6 +101,7 @@ pub fn f32_ne(a: &f32, b: &f32) -> bool { } } +#[allow(clippy::float_cmp)] pub fn f64_ne(a: &f64, b: &f64) -> bool { if a.is_nan() && b.is_nan() { false @@ -233,7 +235,7 @@ mod pg_types { fn mk_uuid(data: (u32, u16, u16, (u8, u8, u8, u8, u8, u8, u8, u8))) -> self::uuid::Uuid { let a = data.3; let b = [a.0, a.1, a.2, a.3, a.4, a.5, a.6, a.7]; - uuid::Uuid::from_fields(data.0, data.1, data.2, &b).unwrap() + uuid::Uuid::from_fields(data.0, data.1, data.2, &b) } fn mk_macaddr(data: (u8, u8, u8, u8, u8, u8)) -> [u8; 6] { diff --git a/examples/mysql/all_about_inserts/src/lib.rs b/examples/mysql/all_about_inserts/src/lib.rs index f00d6d11a7b7..39ba19f7cd89 100644 --- a/examples/mysql/all_about_inserts/src/lib.rs +++ b/examples/mysql/all_about_inserts/src/lib.rs @@ -258,24 +258,24 @@ fn insert_get_results_batch() { use diesel::result::Error; let conn = &mut establish_connection(); - conn.test_transaction::<_, Error, _>(|| { + conn.test_transaction::<_, Error, _>(|conn| { use diesel::select; use schema::users::dsl::*; - let now = select(diesel::dsl::now).get_result::(&conn)?; + let now = select(diesel::dsl::now).get_result::(conn)?; - let inserted_users = conn.transaction::<_, Error, _>(|| { + let inserted_users = conn.transaction::<_, Error, _>(|conn| { let inserted_count = insert_into(users) .values(&vec![ (id.eq(1), name.eq("Sean")), (id.eq(2), name.eq("Tess")), ]) - .execute(&conn)?; + .execute(conn)?; Ok(users .order(id.desc()) .limit(inserted_count as i64) - .load(&conn)? + .load(conn)? .into_iter() .rev() .collect::>()) @@ -330,18 +330,18 @@ fn insert_get_result() { use diesel::result::Error; let conn = &mut establish_connection(); - conn.test_transaction::<_, Error, _>(|| { + conn.test_transaction::<_, Error, _>(|conn| { use diesel::select; use schema::users::dsl::*; - let now = select(diesel::dsl::now).get_result::(&conn)?; + let now = select(diesel::dsl::now).get_result::(conn)?; - let inserted_user = conn.transaction::<_, Error, _>(|| { + let inserted_user = conn.transaction::<_, Error, _>(|conn| { insert_into(users) .values((id.eq(3), name.eq("Ruby"))) - .execute(&conn)?; + .execute(conn)?; - users.order(id.desc()).first(&conn) + users.order(id.desc()).first(conn) })?; let expected_user = User { diff --git a/examples/sqlite/all_about_inserts/src/lib.rs b/examples/sqlite/all_about_inserts/src/lib.rs index 78b23447cc6d..3a29eef3ae68 100644 --- a/examples/sqlite/all_about_inserts/src/lib.rs +++ b/examples/sqlite/all_about_inserts/src/lib.rs @@ -273,24 +273,24 @@ fn insert_get_results_batch() { use diesel::result::Error; let conn = &mut establish_connection(); - conn.test_transaction::<_, Error, _>(|| { + conn.test_transaction::<_, Error, _>(|conn| { use diesel::select; use schema::users::dsl::*; - let now = select(diesel::dsl::now).get_result::(&conn)?; + let now = select(diesel::dsl::now).get_result::(conn)?; - let inserted_users = conn.transaction::<_, Error, _>(|| { + let inserted_users = conn.transaction::<_, Error, _>(|conn| { let inserted_count = insert_into(users) .values(&vec![ (id.eq(1), name.eq("Sean")), (id.eq(2), name.eq("Tess")), ]) - .execute(&conn)?; + .execute(conn)?; Ok(users .order(id.desc()) .limit(inserted_count as i64) - .load(&conn)? + .load(conn)? .into_iter() .rev() .collect::>()) @@ -346,13 +346,13 @@ fn examine_sql_from_insert_get_results_batch() { // use diesel::result::Error; // let conn = &mut establish_connection(); -// conn.test_transaction::<_, Error, _>(|| { +// conn.test_transaction::<_, Error, _>(|conn| { // use diesel::select; // use schema::users::dsl::*; // let now = select(diesel::dsl::now).get_result::(&conn)?; -// let inserted_user = conn.transaction::<_, Error, _>(|| { +// let inserted_user = conn.transaction::<_, Error, _>(|conn| { // insert_into(users) // .values((id.eq(3), name.eq("Ruby"))) // .execute(&conn)?; From 5282adbdc76087f1cc5538319bec0e1e77fea397 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 24 May 2022 23:20:20 +0200 Subject: [PATCH 033/107] Allow mysql schemas that contain either a json or a datatime field Unfortunately we cannot add a test for json, as the behaviour there diverges between mariadb and mysql. --- diesel_cli/src/print_schema.rs | 2 ++ diesel_cli/tests/print_schema.rs | 6 +++++ .../diesel.toml | 3 +++ .../mysql/expected.rs | 27 +++++++++++++++++++ .../mysql/schema.sql | 5 ++++ 5 files changed, 43 insertions(+) create mode 100644 diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml create mode 100644 diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs create mode 100644 diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index a4b5a9694015..0e59f4846069 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -144,6 +144,8 @@ fn mysql_diesel_types() -> HashSet<&'static str> { types.insert("TinyInt"); types.insert("Tinyint"); + types.insert("Datetime"); + types.insert("Json"); types } diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs index fdaa90f9b72b..34c98aa9f980 100644 --- a/diesel_cli/tests/print_schema.rs +++ b/diesel_cli/tests/print_schema.rs @@ -123,6 +123,12 @@ fn print_schema_unsigned() { test_print_schema("print_schema_unsigned", vec!["--with-docs"]); } +#[test] +#[cfg(feature = "mysql")] +fn print_schema_datetime_for_mysql() { + test_print_schema("print_schema_datetime_for_mysql", vec!["--with-docs"]); +} + #[test] #[cfg(not(windows))] fn print_schema_patch_file() { diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml new file mode 100644 index 000000000000..750e5ba85830 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml @@ -0,0 +1,3 @@ +[print_schema] +file = "src/schema.rs" +with_docs = true diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs new file mode 100644 index 000000000000..3d8b74e74a4c --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs @@ -0,0 +1,27 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + /// Representation of the `users` table. + /// + /// (Automatically generated by Diesel.) + users (id) { + /// The `id` column of the `users` table. + /// + /// Its SQL type is `Integer`. + /// + /// (Automatically generated by Diesel.) + id -> Integer, + /// The `datetime` column of the `users` table. + /// + /// Its SQL type is `Datetime`. + /// + /// (Automatically generated by Diesel.) + datetime -> Datetime, + /// The `nullable_datetime` column of the `users` table. + /// + /// Its SQL type is `Nullable`. + /// + /// (Automatically generated by Diesel.) + nullable_datetime -> Nullable, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql new file mode 100644 index 000000000000..0b6f2d2e5e38 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + datetime DATETIME NOT NULL, + nullable_datetime DATETIME +); From e01025fcb93f18fe27e447b7bba2c045b543c105 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 26 May 2022 17:02:27 +0200 Subject: [PATCH 034/107] Make rustdoc JSON not cause ICE --- diesel/src/expression/mod.rs | 4 ++-- diesel/src/query_builder/mod.rs | 9 --------- diesel/src/query_dsl/load_dsl.rs | 4 +++- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/diesel/src/expression/mod.rs b/diesel/src/expression/mod.rs index b2c026631be6..0f6fefc6f953 100644 --- a/diesel/src/expression/mod.rs +++ b/diesel/src/expression/mod.rs @@ -212,9 +212,9 @@ where T: Expression, ST: SqlType + TypedExpressionType, { - type Expression = Self; + type Expression = T; - fn as_expression(self) -> Self { + fn as_expression(self) -> T { self } } diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs index 7cbad028dff2..b14cc82848e5 100644 --- a/diesel/src/query_builder/mod.rs +++ b/diesel/src/query_builder/mod.rs @@ -332,15 +332,6 @@ pub trait AsQuery { fn as_query(self) -> Self::Query; } -impl AsQuery for T { - type SqlType = ::SqlType; - type Query = Self; - - fn as_query(self) -> Self::Query { - self - } -} - /// Takes a query `QueryFragment` expression as an argument and returns a type /// that implements `fmt::Display` and `fmt::Debug` to show the query. /// diff --git a/diesel/src/query_dsl/load_dsl.rs b/diesel/src/query_dsl/load_dsl.rs index d03ffefe7575..843df18802ea 100644 --- a/diesel/src/query_dsl/load_dsl.rs +++ b/diesel/src/query_dsl/load_dsl.rs @@ -90,13 +90,15 @@ pub trait ExecuteDsl, DB: Backend = QueryResult; } +use crate::result::Error; + impl ExecuteDsl for T where Conn: Connection, DB: Backend, T: QueryFragment + QueryId, { - fn execute(query: Self, conn: &mut Conn) -> QueryResult { + fn execute(query: T, conn: &mut Conn) -> Result { conn.execute_returning_count(&query) } } From 510cad632c6419292f35eb63987a1fe8f22380fd Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 27 May 2022 19:17:44 +0200 Subject: [PATCH 035/107] Also replace `Self` with `T` for `impl AsQuery for T` --- diesel/src/query_builder/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs index b14cc82848e5..77be2dcba067 100644 --- a/diesel/src/query_builder/mod.rs +++ b/diesel/src/query_builder/mod.rs @@ -332,6 +332,15 @@ pub trait AsQuery { fn as_query(self) -> Self::Query; } +impl AsQuery for T { + type SqlType = ::SqlType; + type Query = T; + + fn as_query(self) -> ::Query { + self + } +} + /// Takes a query `QueryFragment` expression as an argument and returns a type /// that implements `fmt::Display` and `fmt::Debug` to show the query. /// From 3783c1cd2c0ba0989dc9b1351dbf38b905ae6f78 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 27 May 2022 21:21:15 +0200 Subject: [PATCH 036/107] Fix three rustdoc::broken_intra_doc_links Step-by-step: 1. `cargo +nightly doc --manifest-path diesel/Cargo.toml` Expected result: No warnings Actual result: Three warnings --- diesel/src/macros/mod.rs | 7 ++++--- diesel/src/query_source/aliasing/alias.rs | 2 +- diesel/src/query_source/aliasing/aliased_field.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/diesel/src/macros/mod.rs b/diesel/src/macros/mod.rs index 57f8b44c856f..989be81ebe4c 100644 --- a/diesel/src/macros/mod.rs +++ b/diesel/src/macros/mod.rs @@ -1129,9 +1129,10 @@ macro_rules! __diesel_table_generate_static_query_fragment_for_table { /// /// The generated `ON` clause will always join to the primary key of the parent /// table. This macro removes the need to call [`.on`] explicitly, you will -/// still need to invoke [`allow_tables_to_appear_in_same_query!`] for these two tables to -/// be able to use the resulting query, unless you are using `diesel print-schema` -/// which will generate it for you. +/// still need to invoke +/// [`allow_tables_to_appear_in_same_query!`](crate::allow_tables_to_appear_in_same_query) +/// for these two tables to be able to use the resulting query, unless you are +/// using `diesel print-schema` which will generate it for you. /// /// If you are using `diesel print-schema`, an invocation of this macro /// will be generated for every foreign key in your database unless diff --git a/diesel/src/query_source/aliasing/alias.rs b/diesel/src/query_source/aliasing/alias.rs index 1b256ec25a64..7167dbd59093 100644 --- a/diesel/src/query_source/aliasing/alias.rs +++ b/diesel/src/query_source/aliasing/alias.rs @@ -13,7 +13,7 @@ use std::marker::PhantomData; #[derive(Debug, Clone, Copy, Default)] /// Represents an alias within diesel's query builder /// -/// See [alias!] for more details. +/// See [`alias!`](crate::alias) for more details. pub struct Alias { pub(crate) source: S, } diff --git a/diesel/src/query_source/aliasing/aliased_field.rs b/diesel/src/query_source/aliasing/aliased_field.rs index 0058885b5bbd..b8dc1c34b04f 100644 --- a/diesel/src/query_source/aliasing/aliased_field.rs +++ b/diesel/src/query_source/aliasing/aliased_field.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] /// Represents an aliased field (column) within diesel's query builder /// -/// See [alias!] for more details. +/// See [`alias!`](crate::alias) for more details. pub struct AliasedField { pub(super) _alias_source: PhantomData, pub(super) _field: F, From 8154bfe9fe8ea575db4e9c0d10e2b5ff25a3a78a Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 31 May 2022 15:56:05 +0200 Subject: [PATCH 037/107] Add a note about automatic rebuilds to the documentation of `embed_migrations!` (Addresses #3119) --- diesel_migrations/migrations_macros/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/diesel_migrations/migrations_macros/src/lib.rs b/diesel_migrations/migrations_macros/src/lib.rs index 8fac4329c09d..d23af25cc09d 100644 --- a/diesel_migrations/migrations_macros/src/lib.rs +++ b/diesel_migrations/migrations_macros/src/lib.rs @@ -95,6 +95,24 @@ use proc_macro::TokenStream; /// Ok(()) /// } /// ``` +/// +/// # Automatic rebuilds +/// +/// Due to limitations in rusts proc-macro API there is currently no +/// way to signal that a specific proc macro should be rerun if some +/// external file changes/is added. This implies that `embed_migrations!` +/// cannot regenerate the list of embedded migrations if **only** the +/// migrations are changed. This limitation can be solved by adding a +/// custom `build.rs` file to your crate, such that the crate is rebuild +/// if the migration directory changes. +/// +/// Add the following `build.rs` file to your project to fix the problem +/// +/// ``` +/// fn main() { +/// println!("cargo:rerun-if-changed=path/to/your/migration/dir/reletive/to/your/Cargo.toml"); +/// } +/// ``` #[proc_macro] pub fn embed_migrations(input: TokenStream) -> TokenStream { embed_migrations::expand(input.to_string()) From 640b3992639da8b92419241ece34cd7843b69df6 Mon Sep 17 00:00:00 2001 From: Jean SIMARD Date: Tue, 31 May 2022 17:51:48 +0200 Subject: [PATCH 038/107] docs: typos in lib.rs --- diesel/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs index 8e736809d142..356d78126395 100644 --- a/diesel/src/lib.rs +++ b/diesel/src/lib.rs @@ -130,8 +130,8 @@ //! - `i-implement-a-third-party-backend-and-opt-into-breaking-changes`: This feature opens up some otherwise //! private API, that can be useful to implement a third party [`Backend`](crate::backend::Backend) //! or write a custom [`Connection`](crate::connection::Connection) implementation. **Do not use this feature for -//! any other usecase**. By enabling this feature you explicitly opt out diesel stability gurantees. We explicitly -//! reserve us the right to break API's exported under this feature flag in any upcomming minor version release. +//! any other usecase**. By enabling this feature you explicitly opt out diesel stability guarantees. We explicitly +//! reserve us the right to break API's exported under this feature flag in any upcoming minor version release. //! If you publish a crate depending on this feature flag consider to restrict the supported diesel version to the //! currently released minor version. //! - `serde_json`: This feature flag enables support for (de)serializing json values from the database using @@ -148,9 +148,9 @@ //! - `extras`: This feature enables the feature flaged support for any third party crate. This implies the //! following feature flags: `serde_json`, `chrono`, `uuid`, `network-address`, `numeric`, `r2d2` //! - `with-deprecated`: This feature enables items marked as `#[deprecated]`. It is enabled by default. -//! disabling this feature explicitly opts out diesels stability gurantee. +//! disabling this feature explicitly opts out diesels stability guarantee. //! - `without-deprecated`: This feature disables any item marked as `#[deprecated]`. Enabling this feature -//! explicitly opts out the stability gurantee given by diesel. This feature overrides the `with-deprecated`. +//! explicitly opts out the stability guarantee given by diesel. This feature overrides the `with-deprecated`. //! Note that this may also remove items that are not shown as `#[deprecated]` in our documentation, due to //! various bugs in rustdoc. It can be used to check if you depend on any such hidden `#[deprecated]` item. //! From 48cae3c6120e7023f6ad71e85dc2389b77ebd765 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 31 May 2022 18:59:54 +0000 Subject: [PATCH 039/107] Update diesel_migrations/migrations_macros/src/lib.rs Co-authored-by: Mingun --- diesel_migrations/migrations_macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel_migrations/migrations_macros/src/lib.rs b/diesel_migrations/migrations_macros/src/lib.rs index d23af25cc09d..2e1495fe1b1a 100644 --- a/diesel_migrations/migrations_macros/src/lib.rs +++ b/diesel_migrations/migrations_macros/src/lib.rs @@ -110,7 +110,7 @@ use proc_macro::TokenStream; /// /// ``` /// fn main() { -/// println!("cargo:rerun-if-changed=path/to/your/migration/dir/reletive/to/your/Cargo.toml"); +/// println!("cargo:rerun-if-changed=path/to/your/migration/dir/relative/to/your/Cargo.toml"); /// } /// ``` #[proc_macro] From dc1965b081d3d7f1b9a3283a8aa461aa8d9ada37 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 2 Jun 2022 12:49:27 +0200 Subject: [PATCH 040/107] Put the `backend::sql_dialect` module behind the `i-implement-a-third-party-backend-and-opt-into-breaking-changes` This will allow us to change some of the associated types on existing `SqlDialect` impls in later diesel versions. We might want to do this for the following reasons: * The backend gained support for previously unsupported SQL operations * The backend fixed/introduced a bug that requires special handling * We got some edge case wrong with sharing the implementation between backends Additionally this commit fixes a few types in type and module names in the `sql_dialect` module. --- diesel/src/backend.rs | 180 +++++++++++++++++----- diesel/src/expression/array_comparison.rs | 31 ++-- diesel/src/mysql/backend.rs | 2 +- diesel/src/pg/backend.rs | 2 +- diesel/src/sqlite/backend.rs | 8 +- 5 files changed, 166 insertions(+), 57 deletions(-) diff --git a/diesel/src/backend.rs b/diesel/src/backend.rs index 07efb81f700e..3b09428294b3 100644 --- a/diesel/src/backend.rs +++ b/diesel/src/backend.rs @@ -142,7 +142,10 @@ pub type BindCollector<'a, DB> = >::BindCollector; /// a custom `QueryFragment` implementation /// to specialize on generic `QueryFragment` implementations. /// -/// See the [`sql_dialect`] module for options provided by diesel out of the box. +#[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See the [`sql_dialect`] module for options provided by diesel out of the box." +)] pub trait SqlDialect: self::private::TrustedBackend { /// Configures how this backends supports `RETURNING` clauses /// @@ -157,13 +160,19 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementation for `ReturningClause`" )] /// - /// See [`sql_dialect::returning_clause`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::returning_clause`] for provided default implementations" + )] type ReturningClause; /// Configures how this backend supports `ON CONFLICT` clauses /// /// This allows backends to opt in `ON CONFLICT` clause support /// - /// See [`sql_dialect::on_conflict_clause`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::on_conflict_clause`] for provided default implementations" + )] type OnConflictClause; /// Configures how this backend handles the bare `DEFAULT` keyword for /// inserting the default value in a `INSERT INTO` `VALUES` clause @@ -171,7 +180,10 @@ pub trait SqlDialect: self::private::TrustedBackend { /// This allows backends to opt in support for `DEFAULT` value expressions /// for insert statements /// - /// See [`sql_dialect::default_keyword_for_insert`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::default_keyword_for_insert`] for provided default implementations" + )] type InsertWithDefaultKeyword; /// Configures how this backend handles Batch insert statements /// @@ -185,7 +197,10 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementation for `BatchInsert`" )] /// - /// See [`sql_dialect::batch_insert_support`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::batch_insert_support`] for provided default implementations" + )] type BatchInsertSupport; /// Configures how this backend handles the `DEFAULT VALUES` clause for /// insert statements. @@ -200,7 +215,10 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementation for `DefaultValues`" )] /// - /// See [`sql_dialect::default_value_clause`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::default_value_clause`] for provided default implementations" + )] type DefaultValueClauseForInsert; /// Configures how this backend handles empty `FROM` clauses for select statements. /// @@ -214,7 +232,10 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementation for `NoFromClause`" )] /// - /// See [`sql_dialect::from_clause_syntax`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::from_clause_syntax`] for provided default implementations" + )] type EmptyFromClauseSyntax; /// Configures how this backend handles `EXISTS()` expressions. /// @@ -228,7 +249,10 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementation for `Exists`" )] /// - /// See [`sql_dialect::exists_syntax`] for provided default implementations + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::exists_syntax`] for provided default implementations" + )] type ExistsSyntax; /// Configures how this backend handles `IN()` and `NOT IN()` expressions. @@ -245,54 +269,94 @@ pub trait SqlDialect: self::private::TrustedBackend { doc = "implementations for `In`, `NotIn` and `Many`" )] /// - /// See `[sql_dialect::array_comparison`] for provided default implementations - type ArrayComparision; + #[cfg_attr( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes", + doc = "See [`sql_dialect::array_comparison`] for provided default implementations" + )] + type ArrayComparison; } /// This module contains all options provided by diesel to configure the [`SqlDialect`] trait. -pub mod sql_dialect { +// This module is only public behind the unstable feature flag, as we may want to change SqlDialect +// implementations of existing backends because of: +// * The backend gained support for previously unsupported SQL operations +// * The backend fixed/introduced a bug that requires special handling +// * We got some edge case wrong with sharing the implementation between backends +// +// By not exposing these types publically we are able to change the exact definitions later on +// as users cannot write trait bounds that ensure that a specific type is used in place of +// an existing associated type. +#[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" +)] +pub(crate) mod sql_dialect { #[cfg(doc)] use super::SqlDialect; /// This module contains all diesel provided reusable options to /// configure [`SqlDialect::OnConflictClause`] - pub mod on_conflict_clause { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod on_conflict_clause { /// A marker trait indicating if a `ON CONFLICT` clause is supported or not /// /// If you use a custom type to specify specialized support for `ON CONFLICT` clauses /// implementing this trait opts into reusing diesels existing `ON CONFLICT` /// `QueryFragment` implementations - pub trait SupportsOnConflictClause {} + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + + pub(crate) trait SupportsOnConflictClause {} /// This marker type indicates that `ON CONFLICT` clauses are not supported for this backend #[derive(Debug, Copy, Clone)] - pub struct DoesNotSupportOnConflictClause; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct DoesNotSupportOnConflictClause; } /// This module contains all reusable options to configure /// [`SqlDialect::ReturningClause`] - pub mod returning_clause { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod returning_clause { /// A marker trait indicating if a `RETURNING` clause is supported or not /// /// If you use custom type to specify specialized support for `RETURNING` clauses /// implementing this trait opts in supporting `RETURNING` clause syntax - pub trait SupportsReturningClause {} + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) trait SupportsReturningClause {} /// Indicates that a backend provides support for `RETURNING` clauses /// using the postgresql `RETURNING` syntax #[derive(Debug, Copy, Clone)] - pub struct PgLikeReturningClause; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct PgLikeReturningClause; /// Indicates that a backend does not support `RETURNING` clauses #[derive(Debug, Copy, Clone)] - pub struct DoesNotSupportReturningClause; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct DoesNotSupportReturningClause; impl SupportsReturningClause for PgLikeReturningClause {} } /// This module contains all reusable options to configure /// [`SqlDialect::InsertWithDefaultKeyword`] - pub mod default_keyword_for_insert { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod default_keyword_for_insert { /// A marker trait indicating if a `DEFAULT` like expression /// is supported as part of `INSERT INTO` clauses to indicate /// that a default value should be inserted at a specific position @@ -301,86 +365,132 @@ pub mod sql_dialect { /// expressions implementing this trait opts in support for `DEFAULT` /// value expressions for inserts. Otherwise diesel will emulate this /// behaviour. - pub trait SupportsDefaultKeyword {} + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) trait SupportsDefaultKeyword {} /// Indicates that a backend support `DEFAULT` value expressions /// for `INSERT INTO` statements based on the ISO SQL standard #[derive(Debug, Copy, Clone)] - pub struct IsoSqlDefaultKeyword; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct IsoSqlDefaultKeyword; /// Indicates that a backend does not support `DEFAULT` value /// expressions0for `INSERT INTO` statements #[derive(Debug, Copy, Clone)] - pub struct DoesNotSupportDefaultKeyword; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct DoesNotSupportDefaultKeyword; impl SupportsDefaultKeyword for IsoSqlDefaultKeyword {} } /// This module contains all reusable options to configure /// [`SqlDialect::BatchInsertSupport`] - pub mod batch_insert_support { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod batch_insert_support { /// A marker trait indicating if batch insert statements /// are supported for this backend or not - pub trait SupportsBatchInsert {} + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) trait SupportsBatchInsert {} /// Indicates that this backend does not support batch /// insert statements. /// In this case diesel will emulate batch insert support /// by inserting each row on it's own #[derive(Debug, Copy, Clone)] - pub struct DoesNotSupportBatchInsert; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct DoesNotSupportBatchInsert; /// Indicates that this backend supports postgres style /// batch insert statements to insert multiple rows using one /// insert statement #[derive(Debug, Copy, Clone)] - pub struct PostgresLikeBatchInsertSupport; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + + pub(crate) struct PostgresLikeBatchInsertSupport; impl SupportsBatchInsert for PostgresLikeBatchInsertSupport {} } /// This module contains all reusable options to configure /// [`SqlDialect::DefaultValueClauseForInsert`] - pub mod default_value_clause { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod default_value_clause { /// Indicates that this backend uses the /// `DEFAULT VALUES` syntax to specify /// that a row consisting only of default /// values should be inserted #[derive(Debug, Clone, Copy)] - pub struct AnsiDefaultValueClause; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct AnsiDefaultValueClause; } /// This module contains all reusable options to configure /// [`SqlDialect::EmptyFromClauseSyntax`] - pub mod from_clause_syntax { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod from_clause_syntax { /// Indicates that this backend skips /// the `FROM` clause in `SELECT` statements /// if no table/view is queried #[derive(Debug, Copy, Clone)] - pub struct AnsiSqlFromClauseSyntax; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct AnsiSqlFromClauseSyntax; } /// This module contains all reusable options to configure /// [`SqlDialect::ExistsSyntax`] - pub mod exists_syntax { + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod exists_syntax { /// Indicates that this backend /// treats `EXIST()` as function /// like expression #[derive(Debug, Copy, Clone)] - pub struct AnsiSqlExistsSyntax; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct AnsiSqlExistsSyntax; } /// This module contains all reusable options to configure - /// [`SqlDialect::ArrayComparision`] - pub mod array_comparision { + /// [`SqlDialect::ArrayComparison`] + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) mod array_comparison { /// Indicates that this backend requires a single bind /// per array element in `IN()` and `NOT IN()` expression #[derive(Debug, Copy, Clone)] - pub struct AnsiSqlArrayComparison; + #[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" + )] + pub(crate) struct AnsiSqlArrayComparison; } } diff --git a/diesel/src/expression/array_comparison.rs b/diesel/src/expression/array_comparison.rs index 9b10a48994e1..9b914d96c9cd 100644 --- a/diesel/src/expression/array_comparison.rs +++ b/diesel/src/expression/array_comparison.rs @@ -23,7 +23,7 @@ use std::marker::PhantomData; /// /// Third party backend can customize the [`QueryFragment`] /// implementation of this query dsl node via -/// [`SqlDialect::ArrayComparision`]. A customized implementation +/// [`SqlDialect::ArrayComparison`]. A customized implementation /// is expected to provide the same sematics as a ANSI SQL /// `IN` expression. /// @@ -43,7 +43,7 @@ pub struct In { /// /// Third party backend can customize the [`QueryFragment`] /// implementation of this query dsl node via -/// [`SqlDialect::ArrayComparision`]. A customized implementation +/// [`SqlDialect::ArrayComparison`]. A customized implementation /// is expected to provide the same sematics as a ANSI SQL /// `NOT IN` expression.0 /// @@ -89,18 +89,17 @@ where impl QueryFragment for In where DB: Backend, - Self: QueryFragment, + Self: QueryFragment, { fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> { - >::walk_ast(self, pass) + >::walk_ast(self, pass) } } -impl QueryFragment - for In +impl QueryFragment for In where DB: Backend - + SqlDialect, + + SqlDialect, T: QueryFragment, U: QueryFragment + MaybeEmpty, { @@ -120,18 +119,18 @@ where impl QueryFragment for NotIn where DB: Backend, - Self: QueryFragment, + Self: QueryFragment, { fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> { - >::walk_ast(self, pass) + >::walk_ast(self, pass) } } -impl QueryFragment +impl QueryFragment for NotIn where DB: Backend - + SqlDialect, + + SqlDialect, T: QueryFragment, U: QueryFragment + MaybeEmpty, { @@ -234,7 +233,7 @@ where /// /// Third party backend can customize the [`QueryFragment`] /// implementation of this query dsl node via -/// [`SqlDialect::ArrayComparision`]. The default +/// [`SqlDialect::ArrayComparison`]. The default /// implementation does generate one bind per value /// in the `values` field. /// @@ -290,20 +289,20 @@ where impl QueryFragment for Many where - Self: QueryFragment, + Self: QueryFragment, DB: Backend, { fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> { - >::walk_ast(self, pass) + >::walk_ast(self, pass) } } -impl QueryFragment +impl QueryFragment for Many where DB: Backend + HasSqlType - + SqlDialect, + + SqlDialect, ST: SingleValue, I: ToSql, { diff --git a/diesel/src/mysql/backend.rs b/diesel/src/mysql/backend.rs index 7645cc6c2354..e04537e4efe8 100644 --- a/diesel/src/mysql/backend.rs +++ b/diesel/src/mysql/backend.rs @@ -89,7 +89,7 @@ impl SqlDialect for Mysql { type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax; type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax; - type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison; + type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison; } impl DieselReserveSpecialization for Mysql {} diff --git a/diesel/src/pg/backend.rs b/diesel/src/pg/backend.rs index 79f833a898b6..ec56e04a76ec 100644 --- a/diesel/src/pg/backend.rs +++ b/diesel/src/pg/backend.rs @@ -140,7 +140,7 @@ impl SqlDialect for Pg { type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax; type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax; - type ArrayComparision = PgStyleArrayComparision; + type ArrayComparison = PgStyleArrayComparision; } impl DieselReserveSpecialization for Pg {} diff --git a/diesel/src/sqlite/backend.rs b/diesel/src/sqlite/backend.rs index 0e9014a6855f..ded379658bb7 100644 --- a/diesel/src/sqlite/backend.rs +++ b/diesel/src/sqlite/backend.rs @@ -59,7 +59,7 @@ impl SqlDialect for Sqlite { #[cfg(feature = "returning_clauses_for_sqlite_3_35")] type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause; - type OnConflictClause = SqliteOnConflictClaues; + type OnConflictClause = SqliteOnConflictClause; type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword; @@ -68,16 +68,16 @@ impl SqlDialect for Sqlite { type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax; type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax; - type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison; + type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison; } impl DieselReserveSpecialization for Sqlite {} impl TrustedBackend for Sqlite {} #[derive(Debug, Copy, Clone)] -pub struct SqliteOnConflictClaues; +pub struct SqliteOnConflictClause; -impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClaues {} +impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClause {} #[derive(Debug, Copy, Clone)] pub struct SqliteBatchInsert; From a4bfc82969c0bf8f6f257bb3097cab9b7a87395a Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Thu, 2 Jun 2022 09:29:14 -0400 Subject: [PATCH 041/107] Update CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b31193b4632..a5a7d125af45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ Increasing the minimal supported Rust version will always be coupled at least wi ## Unreleased +### Added + +* Adds an `ipnet-address` feature flag, allowing support (de)serializing IP + values from the database using types provided by `ipnet`. This feature + may be enabled concurrently with the previously existing `network-address` + feature. + ## [2.0.0 Rc0] 2022-04-22 ### Added From 95f92ff260177a71a33bbf594bf56ef41f536ede Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 3 Jun 2022 08:22:32 +0200 Subject: [PATCH 042/107] Fix CI errors --- diesel/src/backend.rs | 84 ++++++++++++------------------------------- 1 file changed, 22 insertions(+), 62 deletions(-) diff --git a/diesel/src/backend.rs b/diesel/src/backend.rs index 3b09428294b3..93e4bdc2e90d 100644 --- a/diesel/src/backend.rs +++ b/diesel/src/backend.rs @@ -290,6 +290,13 @@ pub trait SqlDialect: self::private::TrustedBackend { feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" )] pub(crate) mod sql_dialect { + #![cfg_attr( + not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"), + // Otherwise there are false positives + // because the lint seems to believe that these pub statements + // are not required, but they are required through the various backend impls + allow(unreachable_pub) + )] #[cfg(doc)] use super::SqlDialect; @@ -304,18 +311,11 @@ pub(crate) mod sql_dialect { /// If you use a custom type to specify specialized support for `ON CONFLICT` clauses /// implementing this trait opts into reusing diesels existing `ON CONFLICT` /// `QueryFragment` implementations - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - - pub(crate) trait SupportsOnConflictClause {} + pub trait SupportsOnConflictClause {} /// This marker type indicates that `ON CONFLICT` clauses are not supported for this backend #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct DoesNotSupportOnConflictClause; + pub struct DoesNotSupportOnConflictClause; } /// This module contains all reusable options to configure @@ -328,25 +328,16 @@ pub(crate) mod sql_dialect { /// /// If you use custom type to specify specialized support for `RETURNING` clauses /// implementing this trait opts in supporting `RETURNING` clause syntax - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) trait SupportsReturningClause {} + pub trait SupportsReturningClause {} /// Indicates that a backend provides support for `RETURNING` clauses /// using the postgresql `RETURNING` syntax #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct PgLikeReturningClause; + pub struct PgLikeReturningClause; /// Indicates that a backend does not support `RETURNING` clauses #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct DoesNotSupportReturningClause; + pub struct DoesNotSupportReturningClause; impl SupportsReturningClause for PgLikeReturningClause {} } @@ -365,26 +356,17 @@ pub(crate) mod sql_dialect { /// expressions implementing this trait opts in support for `DEFAULT` /// value expressions for inserts. Otherwise diesel will emulate this /// behaviour. - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) trait SupportsDefaultKeyword {} + pub trait SupportsDefaultKeyword {} /// Indicates that a backend support `DEFAULT` value expressions /// for `INSERT INTO` statements based on the ISO SQL standard #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct IsoSqlDefaultKeyword; + pub struct IsoSqlDefaultKeyword; /// Indicates that a backend does not support `DEFAULT` value /// expressions0for `INSERT INTO` statements #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct DoesNotSupportDefaultKeyword; + pub struct DoesNotSupportDefaultKeyword; impl SupportsDefaultKeyword for IsoSqlDefaultKeyword {} } @@ -397,30 +379,20 @@ pub(crate) mod sql_dialect { pub(crate) mod batch_insert_support { /// A marker trait indicating if batch insert statements /// are supported for this backend or not - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) trait SupportsBatchInsert {} + pub trait SupportsBatchInsert {} /// Indicates that this backend does not support batch /// insert statements. /// In this case diesel will emulate batch insert support /// by inserting each row on it's own #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct DoesNotSupportBatchInsert; + pub struct DoesNotSupportBatchInsert; /// Indicates that this backend supports postgres style /// batch insert statements to insert multiple rows using one /// insert statement #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - - pub(crate) struct PostgresLikeBatchInsertSupport; + pub struct PostgresLikeBatchInsertSupport; impl SupportsBatchInsert for PostgresLikeBatchInsertSupport {} } @@ -437,10 +409,7 @@ pub(crate) mod sql_dialect { /// that a row consisting only of default /// values should be inserted #[derive(Debug, Clone, Copy)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct AnsiDefaultValueClause; + pub struct AnsiDefaultValueClause; } /// This module contains all reusable options to configure @@ -454,10 +423,7 @@ pub(crate) mod sql_dialect { /// the `FROM` clause in `SELECT` statements /// if no table/view is queried #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct AnsiSqlFromClauseSyntax; + pub struct AnsiSqlFromClauseSyntax; } /// This module contains all reusable options to configure @@ -471,10 +437,7 @@ pub(crate) mod sql_dialect { /// treats `EXIST()` as function /// like expression #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct AnsiSqlExistsSyntax; + pub struct AnsiSqlExistsSyntax; } /// This module contains all reusable options to configure @@ -487,10 +450,7 @@ pub(crate) mod sql_dialect { /// Indicates that this backend requires a single bind /// per array element in `IN()` and `NOT IN()` expression #[derive(Debug, Copy, Clone)] - #[diesel_derives::__diesel_public_if( - feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" - )] - pub(crate) struct AnsiSqlArrayComparison; + pub struct AnsiSqlArrayComparison; } } From 2db5464efd15f2fe19f46d9a61c90fac8b1dd86c Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 3 Jun 2022 10:14:03 +0200 Subject: [PATCH 043/107] Update compile test output --- ...es_not_support_returning_methods_on_sqlite.stderr | 12 ++++++------ ...es_not_support_returning_methods_on_sqlite.stderr | 12 ++++++------ ...es_not_support_returning_methods_on_sqlite.stderr | 12 ++++++------ ...th_multiple_values_not_supported_on_sqlite.stderr | 6 +++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr index 9604ad2cfb46..b8220d5e2105 100644 --- a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -1,25 +1,25 @@ -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied --> tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.rs:17:10 | 17 | .get_result(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `DeleteStatement>>>, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>` = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, _>` for `DeleteStatement>>>>` -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied --> tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.rs:21:10 | 21 | .get_result(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden diff --git a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr index 78e8b8b44416..b4c4bca3903e 100644 --- a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -1,25 +1,25 @@ -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied --> tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs:29:10 | 29 | .get_result::(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `InsertStatement>>,), users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>` = note: required because of the requirements on the impl of `LoadQuery<'_, SqliteConnection, User>` for `InsertStatement>>,), users::table>>` -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied --> tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs:34:10 | 34 | .get_result::(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden diff --git a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr index 6651a5a4fdd3..6551673da076 100644 --- a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -1,25 +1,25 @@ -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment` is not satisfied --> tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.rs:18:10 | 18 | .get_result(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `UpdateStatement>>>, diesel::query_builder::update_statement::changeset::Assign, diesel::internal::derives::as_expression::Bound>, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>` = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, _>` for `UpdateStatement>>>, diesel::query_builder::update_statement::changeset::Assign, diesel::internal::derives::as_expression::Bound>>` -error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied +error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause: QueryFragment` is not satisfied --> tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.rs:23:10 | 23 | .get_result(&mut connection); - | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` + | ^^^^^^^^^^ the trait `QueryFragment` is not implemented for `diesel::query_builder::returning_clause::ReturningClause` | = help: the following implementations were found: - as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden diff --git a/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr b/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr index 45ccbcfbc5fd..d2a4fd7f0d4f 100644 --- a/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr @@ -6,17 +6,17 @@ error[E0277]: the trait bound `diesel::query_builder::insert_statement::batch_in | = help: the following implementations were found: as QueryFragment> - >, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment> + >, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::insert_statement::batch_insert::BatchInsert>, users::table>>, users::table, (), false>` = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `InsertStatement>, users::table>>, users::table, (), false>, diesel::query_builder::upsert::on_conflict_target::NoConflictTarget, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>` = note: required because of the requirements on the impl of `ExecuteDsl` for `InsertStatement>, users::table>>, users::table, (), false>, diesel::query_builder::upsert::on_conflict_target::NoConflictTarget, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>` -error[E0271]: type mismatch resolving `::InsertWithDefaultKeyword == IsoSqlDefaultKeyword` +error[E0271]: type mismatch resolving `::InsertWithDefaultKeyword == backend::sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword` --> tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.rs:17:10 | 17 | .execute(&mut connection); - | ^^^^^^^ expected struct `DoesNotSupportDefaultKeyword`, found struct `IsoSqlDefaultKeyword` + | ^^^^^^^ expected struct `backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword`, found struct `backend::sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword` | = note: required because of the requirements on the impl of `CanInsertInSingleQuery` for `diesel::query_builder::insert_statement::batch_insert::BatchInsert>, users::table>>, users::table, (), false>` = note: 1 redundant requirements hidden From efdc9786e28682f510beb4bef20c98394c397eed Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Fri, 3 Jun 2022 10:21:08 -0400 Subject: [PATCH 044/107] Add ipnet dep --- diesel_tests/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 67db35ba1109..28eb0cfcd3af 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -16,6 +16,7 @@ dotenvy = "0.15" quickcheck = "1.0.3" uuid = { version = "1.0.0" } serde_json = { version=">=0.9, <2.0" } +ipnet = { version = "2.5.0" } ipnetwork = ">=0.12.2, <0.19.0" bigdecimal = ">= 0.0.13, < 0.4.0" rand = "0.8.4" From 3e91966bc47f8aaa08654432782db2d9f33651a6 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Fri, 3 Jun 2022 14:48:48 -0400 Subject: [PATCH 045/107] Use windows 2019 instead of windows latest --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8209944a2f9..5941122da21f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: matrix: rust: ["stable", "beta", "nightly"] backend: ["postgres", "sqlite", "mysql"] - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-2019] runs-on: ${{ matrix.os }} steps: - name: Checkout sources From 0006b43a23be909d5771008ea60ad68349272fd3 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sun, 5 Jun 2022 09:46:31 -0400 Subject: [PATCH 046/107] Revert "Fix vs2022 path" This reverts commit d9d46ad11b2d37c4ee43b123a77241c2a06a584d. --- .github/workflows/ci.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5941122da21f..7b725b9f1dc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,13 +153,7 @@ jobs: run: | choco install sqlite cd /D C:\ProgramData\chocolatey\lib\SQLite\tools - dir "C:\Program Files\Microsoft Visual Studio" - dir "C:\Program Files\Microsoft Visual Studio\2022" - dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" - dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC" - dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary" - dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build" - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" lib /machine:x64 /def:sqlite3.def /out:sqlite3.lib - name: Set variables for sqlite (Windows) From bd392afa116201fd32b7acc2280b118e649077bd Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sun, 5 Jun 2022 09:58:51 -0400 Subject: [PATCH 047/107] Revert "Update visual studio path to 2022" This reverts commit e38d8477058461743dcb5e4041a788fd3f1499ac. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b725b9f1dc6..1b46515c2a25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,7 +153,7 @@ jobs: run: | choco install sqlite cd /D C:\ProgramData\chocolatey\lib\SQLite\tools - call "C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat" lib /machine:x64 /def:sqlite3.def /out:sqlite3.lib - name: Set variables for sqlite (Windows) From 857a69f78ce39f87145e32503b7020c1c0352d54 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Tue, 17 May 2022 15:08:00 -0400 Subject: [PATCH 048/107] Add AstPassToSqlOptions --- diesel/src/macros/mod.rs | 18 ++++++---- diesel/src/query_builder/ast_pass.rs | 52 +++++++++++++++++++++++----- diesel/src/query_builder/mod.rs | 7 ++-- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/diesel/src/macros/mod.rs b/diesel/src/macros/mod.rs index 989be81ebe4c..910b21f3eca9 100644 --- a/diesel/src/macros/mod.rs +++ b/diesel/src/macros/mod.rs @@ -115,10 +115,12 @@ macro_rules! __diesel_column { #[allow(non_snake_case)] fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { - const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); + if !__diesel_internal_out.should_skip_from() { + const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); - FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; - __diesel_internal_out.push_sql("."); + FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; + __diesel_internal_out.push_sql("."); + } __diesel_internal_out.push_identifier($sql_name) } } @@ -1018,10 +1020,14 @@ macro_rules! __diesel_table_impl { fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> { use $crate::QuerySource; - const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); - FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; - __diesel_internal_out.push_sql(".*"); + if !__diesel_internal_out.should_skip_from() { + const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance
= $crate::internal::table_macro::StaticQueryFragmentInstance::new(); + + FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?; + __diesel_internal_out.push_sql("."); + } + __diesel_internal_out.push_sql("*"); Ok(()) } } diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index 1d45c61bb28b..136546ba729d 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -38,9 +38,13 @@ where DB: Backend, 'b: 'a, { - pub(crate) fn to_sql(query_builder: &'a mut DB::QueryBuilder, backend: &'b DB) -> Self { + pub(crate) fn to_sql( + query_builder: &'a mut DB::QueryBuilder, + options: &'a mut AstPassToSqlOptions, + backend: &'b DB, + ) -> Self { AstPass { - internals: AstPassInternals::ToSql(query_builder), + internals: AstPassInternals::ToSql(query_builder, options), backend, } } @@ -84,6 +88,12 @@ where } } + pub(crate) fn skip_from(&mut self) { + if let AstPassInternals::ToSql(_, ref mut options) = self.internals { + options.skip_from = false + } + } + /// Call this method whenever you pass an instance of `AstPass` by value. /// /// Effectively copies `self`, with a narrower lifetime. When passing a @@ -95,7 +105,9 @@ where /// implicitly if you were passing a mutable reference pub fn reborrow(&'_ mut self) -> AstPass<'_, 'b, DB> { let internals = match self.internals { - AstPassInternals::ToSql(ref mut builder) => AstPassInternals::ToSql(&mut **builder), + AstPassInternals::ToSql(ref mut builder, ref mut options) => { + AstPassInternals::ToSql(&mut **builder, &mut **options) + } AstPassInternals::CollectBinds { ref mut collector, ref mut metadata_lookup, @@ -167,7 +179,7 @@ where /// ``` pub fn push_sql(&mut self, sql: &str) { match self.internals { - AstPassInternals::ToSql(ref mut builder) => builder.push_sql(sql), + AstPassInternals::ToSql(ref mut builder, _) => builder.push_sql(sql), AstPassInternals::IsNoop(ref mut result) => **result = false, _ => {} } @@ -179,7 +191,7 @@ where /// the query is being constructed for. pub fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> { match self.internals { - AstPassInternals::ToSql(ref mut builder) => builder.push_identifier(identifier)?, + AstPassInternals::ToSql(ref mut builder, _) => builder.push_identifier(identifier)?, AstPassInternals::IsNoop(ref mut result) => **result = false, _ => {} } @@ -197,7 +209,7 @@ where U: ToSql, { match self.internals { - AstPassInternals::ToSql(ref mut out) => out.push_bind_param(), + AstPassInternals::ToSql(ref mut out, _) => out.push_bind_param(), AstPassInternals::CollectBinds { ref mut collector, ref mut metadata_lookup, @@ -220,7 +232,7 @@ where AstPassInternals::CollectBinds { .. } | AstPassInternals::DebugBinds(..) => { self.push_bind_param(bind)? } - AstPassInternals::ToSql(ref mut out) => { + AstPassInternals::ToSql(ref mut out, _) => { out.push_bind_param_value_only(); } _ => {} @@ -240,6 +252,22 @@ where pub fn backend(&self) -> &DB { self.backend } + + #[cfg_attr( + not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"), + doc(hidden) + )] // This is used by the `sql_function` macro + #[cfg_attr( + doc_cfg, + doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")) + )] + pub fn should_skip_from(&self) -> &bool { + if let AstPassInternals::ToSql(_, ref options) = self.internals { + &options.skip_from + } else { + &false + } + } } #[allow(missing_debug_implementations)] @@ -255,7 +283,7 @@ where DB::MetadataLookup: 'a, 'b: 'a, { - ToSql(&'a mut DB::QueryBuilder), + ToSql(&'a mut DB::QueryBuilder, &'a mut AstPassToSqlOptions), CollectBinds { collector: &'a mut >::BindCollector, metadata_lookup: &'a mut DB::MetadataLookup, @@ -264,3 +292,11 @@ where DebugBinds(&'a mut Vec<&'b dyn fmt::Debug>), IsNoop(&'a mut bool), } + +#[allow(missing_debug_implementations)] +#[derive(Default)] +/// This is used to pass down additional settings to the `AstPass` +/// when rendering the sql string. +pub struct AstPassToSqlOptions { + skip_from: bool, +} diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs index 77be2dcba067..747e3aa2cbbe 100644 --- a/diesel/src/query_builder/mod.rs +++ b/diesel/src/query_builder/mod.rs @@ -26,7 +26,7 @@ pub(crate) mod locking_clause; pub(crate) mod nodes; pub(crate) mod offset_clause; pub(crate) mod order_clause; -mod returning_clause; +pub(crate) mod returning_clause; pub(crate) mod select_clause; pub(crate) mod select_statement; mod sql_query; @@ -35,7 +35,7 @@ pub(crate) mod upsert; mod where_clause; #[doc(inline)] -pub use self::ast_pass::AstPass; +pub use self::ast_pass::{AstPass, AstPassToSqlOptions}; #[doc(inline)] pub use self::bind_collector::BindCollector; #[doc(inline)] @@ -203,7 +203,8 @@ pub trait QueryFragment { feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" )] fn to_sql(&self, out: &mut DB::QueryBuilder, backend: &DB) -> QueryResult<()> { - self.walk_ast(AstPass::to_sql(out, backend)) + let mut options = AstPassToSqlOptions::default(); + self.walk_ast(AstPass::to_sql(out, &mut options, backend)) } /// Serializes all bind parameters in this query. From 0a80534cefdf94dde4c4c0dbb818a40b2468859f Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Tue, 17 May 2022 15:08:15 -0400 Subject: [PATCH 049/107] Add SqliteReturningClause --- diesel/src/sqlite/backend.rs | 7 ++++++- diesel/src/sqlite/query_builder/mod.rs | 1 + diesel/src/sqlite/query_builder/returning.rs | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 diesel/src/sqlite/query_builder/returning.rs diff --git a/diesel/src/sqlite/backend.rs b/diesel/src/sqlite/backend.rs index ded379658bb7..97fe2b6b795d 100644 --- a/diesel/src/sqlite/backend.rs +++ b/diesel/src/sqlite/backend.rs @@ -57,7 +57,7 @@ impl SqlDialect for Sqlite { #[cfg(not(feature = "returning_clauses_for_sqlite_3_35"))] type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause; #[cfg(feature = "returning_clauses_for_sqlite_3_35")] - type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause; + type ReturningClause = sql_dialect::returning_clause::SqliteReturningClause; type OnConflictClause = SqliteOnConflictClause; @@ -81,3 +81,8 @@ impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConfl #[derive(Debug, Copy, Clone)] pub struct SqliteBatchInsert; + +#[derive(Debug, Copy, Clone)] +pub struct SqliteReturningClause; + +impl sql_dialect::returning_clause::SupportsReturningClause for SqliteReturningClause {} diff --git a/diesel/src/sqlite/query_builder/mod.rs b/diesel/src/sqlite/query_builder/mod.rs index eea121a95c2a..dc0f522175ac 100644 --- a/diesel/src/sqlite/query_builder/mod.rs +++ b/diesel/src/sqlite/query_builder/mod.rs @@ -5,6 +5,7 @@ use crate::query_builder::QueryBuilder; use crate::result::QueryResult; mod limit_offset; +mod returning; /// Constructs SQL queries for use with the SQLite backend #[allow(missing_debug_implementations)] diff --git a/diesel/src/sqlite/query_builder/returning.rs b/diesel/src/sqlite/query_builder/returning.rs new file mode 100644 index 000000000000..cc2d8d280918 --- /dev/null +++ b/diesel/src/sqlite/query_builder/returning.rs @@ -0,0 +1,18 @@ +use crate::backend::Backend; +use crate::query_builder::returning_clause::ReturningClause; +use crate::query_builder::{AstPass, QueryFragment}; +use crate::result::QueryResult; +use crate::sqlite::backend::SqliteReturningClause; + +impl QueryFragment for ReturningClause +where + DB: Backend, + Expr: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> { + out.skip_from(); + out.push_sql(" RETURNING "); + self.0.walk_ast(out.reborrow())?; + Ok(()) + } +} From 1a4770eef40af239023cf9647a68419525d65e0e Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 18 May 2022 15:46:29 -0400 Subject: [PATCH 050/107] Fix AstPass options warnings --- diesel/src/pg/query_builder/mod.rs | 5 +++-- diesel/src/query_builder/ast_pass.rs | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/diesel/src/pg/query_builder/mod.rs b/diesel/src/pg/query_builder/mod.rs index 0d088630e051..0889fe6283f7 100644 --- a/diesel/src/pg/query_builder/mod.rs +++ b/diesel/src/pg/query_builder/mod.rs @@ -55,7 +55,7 @@ impl QueryBuilder for PgQueryBuilder { #[test] fn check_sql_query_increments_bind_count() { - use crate::query_builder::{AstPass, QueryFragment}; + use crate::query_builder::{AstPass, AstPassToSqlOptions, QueryFragment}; use crate::sql_types::*; let query = crate::sql_query("SELECT $1, $2, $3") @@ -66,7 +66,8 @@ fn check_sql_query_increments_bind_count() { let mut query_builder = PgQueryBuilder::default(); { - let ast_pass = AstPass::::to_sql(&mut query_builder, &Pg); + let mut options = AstPassToSqlOptions::default(); + let ast_pass = AstPass::::to_sql(&mut query_builder, &mut options, &Pg); query.walk_ast(ast_pass).unwrap(); } diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index 136546ba729d..7d3993608120 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -88,6 +88,7 @@ where } } + #[allow(dead_code)] pub(crate) fn skip_from(&mut self) { if let AstPassInternals::ToSql(_, ref mut options) = self.internals { options.skip_from = false @@ -261,11 +262,11 @@ where doc_cfg, doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")) )] - pub fn should_skip_from(&self) -> &bool { + pub fn should_skip_from(&self) -> bool { if let AstPassInternals::ToSql(_, ref options) = self.internals { - &options.skip_from + options.skip_from } else { - &false + false } } } @@ -294,6 +295,7 @@ where } #[allow(missing_debug_implementations)] +#[allow(missing_copy_implementations)] #[derive(Default)] /// This is used to pass down additional settings to the `AstPass` /// when rendering the sql string. From b90bbfc9d6a23d42a9c089bcf18fc8a407bbb6f5 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 18 May 2022 16:46:07 -0400 Subject: [PATCH 051/107] Fix bad returning clause import and bad astpass option value --- diesel/src/query_builder/ast_pass.rs | 2 +- diesel/src/sqlite/backend.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index 7d3993608120..f49f5e95a493 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -91,7 +91,7 @@ where #[allow(dead_code)] pub(crate) fn skip_from(&mut self) { if let AstPassInternals::ToSql(_, ref mut options) = self.internals { - options.skip_from = false + options.skip_from = true } } diff --git a/diesel/src/sqlite/backend.rs b/diesel/src/sqlite/backend.rs index 97fe2b6b795d..f2550de61aae 100644 --- a/diesel/src/sqlite/backend.rs +++ b/diesel/src/sqlite/backend.rs @@ -57,7 +57,7 @@ impl SqlDialect for Sqlite { #[cfg(not(feature = "returning_clauses_for_sqlite_3_35"))] type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause; #[cfg(feature = "returning_clauses_for_sqlite_3_35")] - type ReturningClause = sql_dialect::returning_clause::SqliteReturningClause; + type ReturningClause = SqliteReturningClause; type OnConflictClause = SqliteOnConflictClause; From d30d6e5c1e7137e7bfb78fd2b68251f9af33a932 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 18 May 2022 16:46:32 -0400 Subject: [PATCH 052/107] Add test for returning with an external sqlite database --- diesel_tests/tests/insert.rs | 26 +++++++++++++++++++ diesel_tests/tests/schema/mod.rs | 3 +++ diesel_tests/tests/schema/sqlite_schema.rs | 7 +++++ .../down.sql | 1 + .../up.sql | 4 +++ 5 files changed, 41 insertions(+) create mode 100644 migrations/sqlite/2022-05-18-155625_create_external_table/down.sql create mode 100644 migrations/sqlite/2022-05-18-155625_create_external_table/up.sql diff --git a/diesel_tests/tests/insert.rs b/diesel_tests/tests/insert.rs index 68a5a8d5d05f..e234aad2ec2b 100644 --- a/diesel_tests/tests/insert.rs +++ b/diesel_tests/tests/insert.rs @@ -171,6 +171,32 @@ fn insert_record_using_returning_clause() { assert_eq!(expected_user, inserted_user); } +#[test] +#[cfg(all(feature = "sqlite", feature = "returning_clauses_for_sqlite_3_35"))] +fn insert_record_attached_database_using_returning_clause() { + use crate::schema::external_table; + + #[derive(Queryable, Debug, PartialEq)] + #[diesel(table_name = external_table)] + struct ExternalEntity { + id: i32, + data: String, + } + + let connection = &mut connection(); + + let inserted_entity = insert_into(external_table::table) + .values(external_table::data.eq("test".to_string())) + .get_result::(connection) + .unwrap(); + let expected_entity = ExternalEntity { + id: inserted_entity.id, + data: "test".to_string(), + }; + + assert_eq!(expected_entity, inserted_entity); +} + #[test] #[cfg(not(any(feature = "sqlite", feature = "mysql")))] fn insert_records_using_returning_clause() { diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs index 2c0d2068accf..c01ec09a03cc 100644 --- a/diesel_tests/tests/schema/mod.rs +++ b/diesel_tests/tests/schema/mod.rs @@ -272,6 +272,9 @@ pub fn backend_specific_connection() -> TestConnection { diesel::sql_query("PRAGMA foreign_keys = ON") .execute(&mut conn) .unwrap(); + diesel::sql_query("ATTACH DATABASE ':memory:' AS external") + .execute(&mut conn) + .unwrap(); conn } diff --git a/diesel_tests/tests/schema/sqlite_schema.rs b/diesel_tests/tests/schema/sqlite_schema.rs index 99f88f5ffdb9..47b29bd1b54a 100644 --- a/diesel_tests/tests/schema/sqlite_schema.rs +++ b/diesel_tests/tests/schema/sqlite_schema.rs @@ -236,6 +236,13 @@ table! { } } +table! { + external.external_table (id) { + id -> Integer, + data -> Text, + } +} + joinable!(comments -> posts (post_id)); joinable!(fk_tests -> fk_inits (fk_id)); joinable!(followings -> posts (post_id)); diff --git a/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql b/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql new file mode 100644 index 000000000000..14bfc3a35095 --- /dev/null +++ b/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql @@ -0,0 +1 @@ +DROP TABLE external.external_table; diff --git a/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql b/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql new file mode 100644 index 000000000000..ca9f978085b1 --- /dev/null +++ b/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql @@ -0,0 +1,4 @@ +CREATE TABLE external.external_table ( + id integer PRIMARY KEY AUTOINCREMENT NOT NULL, + data text NOT NULL +); From f2867d29362542384163139c0cc2e1c2ba185cb2 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 25 May 2022 13:10:13 -0400 Subject: [PATCH 053/107] Refactor skip from --- diesel/Cargo.toml | 3 ++- diesel/src/query_builder/ast_pass.rs | 28 ++++++++++++++------ diesel/src/query_builder/mod.rs | 8 +++++- diesel/src/sqlite/query_builder/returning.rs | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index fbff1fd65e38..3156ba406242 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -54,7 +54,7 @@ huge-tables = ["64-column-tables"] 64-column-tables = ["32-column-tables", "diesel_derives/64-column-tables"] 128-column-tables = ["64-column-tables", "diesel_derives/128-column-tables"] postgres = ["pq-sys", "postgres_backend"] -sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"] +sqlite = ["libsqlite3-sys", "diesel_derives/sqlite", "skip-from"] mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backend"] without-deprecated = ["diesel_derives/without-deprecated"] with-deprecated = ["diesel_derives/with-deprecated"] @@ -64,6 +64,7 @@ numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"] postgres_backend = ["diesel_derives/postgres", "bitflags", "byteorder", "itoa"] mysql_backend = ["diesel_derives/mysql", "byteorder"] returning_clauses_for_sqlite_3_35 = [] +skip-from = [] i-implement-a-third-party-backend-and-opt-into-breaking-changes = [] [package.metadata.docs.rs] diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index f49f5e95a493..ef7c335d1f50 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -88,10 +88,10 @@ where } } - #[allow(dead_code)] - pub(crate) fn skip_from(&mut self) { + #[cfg(feature = "skip-from")] + pub(crate) fn skip_from(&mut self, value: bool) { if let AstPassInternals::ToSql(_, ref mut options) = self.internals { - options.skip_from = true + options.skip_from = value } } @@ -254,18 +254,27 @@ where self.backend } + /// Get if the query should be rendered with from clauses or not #[cfg_attr( not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"), doc(hidden) - )] // This is used by the `sql_function` macro + )] // This is used by the `__diesel_column` macro #[cfg_attr( doc_cfg, doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")) )] pub fn should_skip_from(&self) -> bool { - if let AstPassInternals::ToSql(_, ref options) = self.internals { - options.skip_from - } else { + #[cfg(feature = "skip-from")] + { + if let AstPassInternals::ToSql(_, ref options) = self.internals { + options.skip_from + } else { + false + } + } + + #[cfg(not(feature = "skip-from"))] + { false } } @@ -294,11 +303,14 @@ where IsNoop(&'a mut bool), } +#[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" +)] #[allow(missing_debug_implementations)] #[allow(missing_copy_implementations)] #[derive(Default)] /// This is used to pass down additional settings to the `AstPass` /// when rendering the sql string. -pub struct AstPassToSqlOptions { +pub(crate) struct AstPassToSqlOptions { skip_from: bool, } diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs index 747e3aa2cbbe..456e3fe279c3 100644 --- a/diesel/src/query_builder/mod.rs +++ b/diesel/src/query_builder/mod.rs @@ -35,7 +35,7 @@ pub(crate) mod upsert; mod where_clause; #[doc(inline)] -pub use self::ast_pass::{AstPass, AstPassToSqlOptions}; +pub use self::ast_pass::AstPass; #[doc(inline)] pub use self::bind_collector::BindCollector; #[doc(inline)] @@ -86,6 +86,12 @@ pub use self::insert_statement::DefaultValues; #[doc(inline)] pub use self::returning_clause::ReturningClause; +#[doc(inline)] +#[diesel_derives::__diesel_public_if( + feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" +)] +pub(crate) use self::ast_pass::AstPassToSqlOptions; + #[doc(inline)] #[diesel_derives::__diesel_public_if( feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes" diff --git a/diesel/src/sqlite/query_builder/returning.rs b/diesel/src/sqlite/query_builder/returning.rs index cc2d8d280918..fa626f840d14 100644 --- a/diesel/src/sqlite/query_builder/returning.rs +++ b/diesel/src/sqlite/query_builder/returning.rs @@ -10,7 +10,7 @@ where Expr: QueryFragment, { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> { - out.skip_from(); + out.skip_from(true); out.push_sql(" RETURNING "); self.0.walk_ast(out.reborrow())?; Ok(()) From a5363ae5ed1d56e873ee5ddf3b1d08aff55d469e Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 25 May 2022 13:44:26 -0400 Subject: [PATCH 054/107] Refactor external database tests --- diesel_tests/Cargo.toml | 2 +- diesel_tests/tests/insert.rs | 25 +++++++++++++++++-- diesel_tests/tests/schema/mod.rs | 3 --- diesel_tests/tests/schema/sqlite_schema.rs | 7 ------ .../down.sql | 1 - .../up.sql | 4 --- 6 files changed, 24 insertions(+), 18 deletions(-) delete mode 100644 migrations/sqlite/2022-05-18-155625_create_external_table/down.sql delete mode 100644 migrations/sqlite/2022-05-18-155625_create_external_table/up.sql diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 28eb0cfcd3af..ba23cb0eb2e1 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -23,7 +23,7 @@ rand = "0.8.4" libsqlite3-sys = { version = "0.24", optional = true } [features] -default = [] +default = ["sqlite", "returning_clauses_for_sqlite_3_35"] unstable = ["diesel/unstable"] postgres = ["diesel/postgres"] sqlite = ["diesel/sqlite"] diff --git a/diesel_tests/tests/insert.rs b/diesel_tests/tests/insert.rs index e234aad2ec2b..5c842801436e 100644 --- a/diesel_tests/tests/insert.rs +++ b/diesel_tests/tests/insert.rs @@ -174,7 +174,12 @@ fn insert_record_using_returning_clause() { #[test] #[cfg(all(feature = "sqlite", feature = "returning_clauses_for_sqlite_3_35"))] fn insert_record_attached_database_using_returning_clause() { - use crate::schema::external_table; + table! { + external.external_table (id) { + id -> Integer, + data -> Text, + } + } #[derive(Queryable, Debug, PartialEq)] #[diesel(table_name = external_table)] @@ -183,8 +188,24 @@ fn insert_record_attached_database_using_returning_clause() { data: String, } - let connection = &mut connection(); + let connection = &mut connection_without_transaction(); + + // Create external table + diesel::sql_query("ATTACH DATABASE ':memory:' AS external") + .execute(connection) + .unwrap(); + diesel::sql_query( + r#" + CREATE TABLE external.external_table ( + id integer PRIMARY KEY AUTOINCREMENT NOT NULL, + data text NOT NULL + ) + "#, + ) + .execute(connection) + .unwrap(); + // Insert entity and fetch with the returning clause let inserted_entity = insert_into(external_table::table) .values(external_table::data.eq("test".to_string())) .get_result::(connection) diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs index c01ec09a03cc..2c0d2068accf 100644 --- a/diesel_tests/tests/schema/mod.rs +++ b/diesel_tests/tests/schema/mod.rs @@ -272,9 +272,6 @@ pub fn backend_specific_connection() -> TestConnection { diesel::sql_query("PRAGMA foreign_keys = ON") .execute(&mut conn) .unwrap(); - diesel::sql_query("ATTACH DATABASE ':memory:' AS external") - .execute(&mut conn) - .unwrap(); conn } diff --git a/diesel_tests/tests/schema/sqlite_schema.rs b/diesel_tests/tests/schema/sqlite_schema.rs index 47b29bd1b54a..99f88f5ffdb9 100644 --- a/diesel_tests/tests/schema/sqlite_schema.rs +++ b/diesel_tests/tests/schema/sqlite_schema.rs @@ -236,13 +236,6 @@ table! { } } -table! { - external.external_table (id) { - id -> Integer, - data -> Text, - } -} - joinable!(comments -> posts (post_id)); joinable!(fk_tests -> fk_inits (fk_id)); joinable!(followings -> posts (post_id)); diff --git a/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql b/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql deleted file mode 100644 index 14bfc3a35095..000000000000 --- a/migrations/sqlite/2022-05-18-155625_create_external_table/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE external.external_table; diff --git a/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql b/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql deleted file mode 100644 index ca9f978085b1..000000000000 --- a/migrations/sqlite/2022-05-18-155625_create_external_table/up.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE external.external_table ( - id integer PRIMARY KEY AUTOINCREMENT NOT NULL, - data text NOT NULL -); From 8d85dbdd665ffb10d8aecfaefff6cb5913095ee2 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 25 May 2022 13:49:14 -0400 Subject: [PATCH 055/107] Mark skip_from field only for corresponding feature --- diesel/src/query_builder/ast_pass.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index ef7c335d1f50..7734eae4e978 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -312,5 +312,6 @@ where /// This is used to pass down additional settings to the `AstPass` /// when rendering the sql string. pub(crate) struct AstPassToSqlOptions { + #[cfg(feature = "skip-from")] skip_from: bool, } From 8b8d2a9aac26e1519e76424dfc2d79320aebf87f Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Wed, 25 May 2022 13:56:37 -0400 Subject: [PATCH 056/107] Fix bad default features in cargo tests --- diesel_tests/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index ba23cb0eb2e1..28eb0cfcd3af 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -23,7 +23,7 @@ rand = "0.8.4" libsqlite3-sys = { version = "0.24", optional = true } [features] -default = ["sqlite", "returning_clauses_for_sqlite_3_35"] +default = [] unstable = ["diesel/unstable"] postgres = ["diesel/postgres"] sqlite = ["diesel/sqlite"] From d3ced3bf81e2f66d8336ed4d7dd51578ab99a329 Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sun, 5 Jun 2022 09:52:55 -0400 Subject: [PATCH 057/107] Remove skip-from flag --- diesel/Cargo.toml | 3 +-- diesel/src/query_builder/ast_pass.rs | 17 ++++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 3156ba406242..fbff1fd65e38 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -54,7 +54,7 @@ huge-tables = ["64-column-tables"] 64-column-tables = ["32-column-tables", "diesel_derives/64-column-tables"] 128-column-tables = ["64-column-tables", "diesel_derives/128-column-tables"] postgres = ["pq-sys", "postgres_backend"] -sqlite = ["libsqlite3-sys", "diesel_derives/sqlite", "skip-from"] +sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"] mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backend"] without-deprecated = ["diesel_derives/without-deprecated"] with-deprecated = ["diesel_derives/with-deprecated"] @@ -64,7 +64,6 @@ numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"] postgres_backend = ["diesel_derives/postgres", "bitflags", "byteorder", "itoa"] mysql_backend = ["diesel_derives/mysql", "byteorder"] returning_clauses_for_sqlite_3_35 = [] -skip-from = [] i-implement-a-third-party-backend-and-opt-into-breaking-changes = [] [package.metadata.docs.rs] diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs index 7734eae4e978..a67fb350d0ec 100644 --- a/diesel/src/query_builder/ast_pass.rs +++ b/diesel/src/query_builder/ast_pass.rs @@ -88,7 +88,7 @@ where } } - #[cfg(feature = "skip-from")] + #[cfg(feature = "sqlite")] pub(crate) fn skip_from(&mut self, value: bool) { if let AstPassInternals::ToSql(_, ref mut options) = self.internals { options.skip_from = value @@ -264,17 +264,9 @@ where doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")) )] pub fn should_skip_from(&self) -> bool { - #[cfg(feature = "skip-from")] - { - if let AstPassInternals::ToSql(_, ref options) = self.internals { - options.skip_from - } else { - false - } - } - - #[cfg(not(feature = "skip-from"))] - { + if let AstPassInternals::ToSql(_, ref options) = self.internals { + options.skip_from + } else { false } } @@ -312,6 +304,5 @@ where /// This is used to pass down additional settings to the `AstPass` /// when rendering the sql string. pub(crate) struct AstPassToSqlOptions { - #[cfg(feature = "skip-from")] skip_from: bool, } From 3e5f1ade9565156d0549f20bad50d23e9c859152 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Jun 2022 10:12:01 +0200 Subject: [PATCH 058/107] Update compile test output --- .../tests/fail/array_expressions_must_be_same_type.stderr | 2 +- ...tatement_does_not_support_returning_methods_on_sqlite.stderr | 2 ++ ...tatement_does_not_support_returning_methods_on_sqlite.stderr | 2 ++ ...tatement_does_not_support_returning_methods_on_sqlite.stderr | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr index a66a24b4540e..a5159cd2876b 100644 --- a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr +++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr @@ -189,7 +189,7 @@ error[E0277]: the trait bound `{integer}: QueryFragment` is not satisfied <() as QueryFragment> <(T0, T1) as QueryFragment<__DB>> <(T0, T1, T2) as QueryFragment<__DB>> - and 272 others + and 273 others = note: required because of the requirements on the impl of `QueryFragment` for `({integer}, diesel::internal::derives::as_expression::Bound)` = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `QueryFragment` for `SelectStatement), diesel::sql_types::Double>>>` diff --git a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr index b8220d5e2105..5eec2fe1e01f 100644 --- a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -6,6 +6,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden @@ -20,6 +21,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden diff --git a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr index b4c4bca3903e..24b19eff4876 100644 --- a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -6,6 +6,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden @@ -20,6 +21,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden diff --git a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr index 6551673da076..064735246522 100644 --- a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr +++ b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr @@ -6,6 +6,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>` = note: 1 redundant requirements hidden @@ -20,6 +21,7 @@ error[E0277]: the trait bound `diesel::query_builder::returning_clause::Returnin | = help: the following implementations were found: as QueryFragment> + as QueryFragment> as QueryFragment> = note: required because of the requirements on the impl of `QueryFragment` for `diesel::query_builder::returning_clause::ReturningClause` = note: 1 redundant requirements hidden From a83360cdb11862a8765c0430e61a742c98bbcea2 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Jun 2022 22:48:44 +0200 Subject: [PATCH 059/107] Explictly sort migrations on migration redo to ensure that we revert them from newest to oldest, but apply them in the revers order --- diesel_cli/src/main.rs | 4 +++- diesel_cli/tests/migration_redo.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs index f56362b1d670..3cade95adf82 100644 --- a/diesel_cli/src/main.rs +++ b/diesel_cli/src/main.rs @@ -438,7 +438,7 @@ fn redo_migrations( .map(|m| (m.name().version().as_owned(), m)) .collect::>(); - let migrations = reverted_versions + let mut migrations = reverted_versions .into_iter() .map(|v| { migrations @@ -446,6 +446,8 @@ fn redo_migrations( .ok_or_else(|| MigrationError::UnknownMigrationVersion(v.as_owned())) }) .collect::, _>>()?; + // Sort the migrations by version to apply them in order. + migrations.sort_by_key(|m| m.name().version().as_owned()); harness.run_migrations(&migrations)?; diff --git a/diesel_cli/tests/migration_redo.rs b/diesel_cli/tests/migration_redo.rs index 1e2b54c36ddf..d78bc0d98bdb 100644 --- a/diesel_cli/tests/migration_redo.rs +++ b/diesel_cli/tests/migration_redo.rs @@ -69,8 +69,8 @@ fn migration_redo_runs_the_last_two_migrations_down_and_up() { result.stdout() == "Rolling back migration 2017-09-12-210424_create_bills\n\ Rolling back migration 2017-09-03-210424_create_contracts\n\ - Running migration 2017-09-12-210424_create_bills\n\ - Running migration 2017-09-03-210424_create_contracts\n", + Running migration 2017-09-03-210424_create_contracts\n\ + Running migration 2017-09-12-210424_create_bills\n", "Unexpected stdout : {}", result.stdout() ); @@ -247,9 +247,9 @@ fn migration_redo_all_runs_all_migrations_down_and_up() { == "Rolling back migration 2017-09-12-210424_create_bills\n\ Rolling back migration 2017-09-03-210424_create_contracts\n\ Rolling back migration 2017-08-31-210424_create_customers\n\ - Running migration 2017-09-12-210424_create_bills\n\ + Running migration 2017-08-31-210424_create_customers\n\ Running migration 2017-09-03-210424_create_contracts\n\ - Running migration 2017-08-31-210424_create_customers\n", + Running migration 2017-09-12-210424_create_bills\n", "Unexpected stdout : {}", result.stdout() ); @@ -305,9 +305,9 @@ fn migration_redo_with_more_than_max_should_redo_all() { == "Rolling back migration 2017-09-12-210424_create_bills\n\ Rolling back migration 2017-09-03-210424_create_contracts\n\ Rolling back migration 2017-08-31-210424_create_customers\n\ - Running migration 2017-09-12-210424_create_bills\n\ + Running migration 2017-08-31-210424_create_customers\n\ Running migration 2017-09-03-210424_create_contracts\n\ - Running migration 2017-08-31-210424_create_customers\n", + Running migration 2017-09-12-210424_create_bills\n", "Unexpected stdout : {}", result.stdout() ); From d061159b9bb7b7bfa91604bca8a2b8a682f702f7 Mon Sep 17 00:00:00 2001 From: Iban Eguia Moraza Date: Sat, 14 May 2022 12:34:57 +0200 Subject: [PATCH 060/107] Updated ipnetwork to 0.19 --- diesel/Cargo.toml | 4 ++-- diesel_tests/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index fbff1fd65e38..e97bb75f8d81 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -24,7 +24,7 @@ serde_json = { version = ">=0.8.0, <2.0", optional = true } url = { version = "2.1.0", optional = true } percent-encoding = { version = "2.1.0", optional = true } uuid = { version = ">=0.7.0, <2.0.0", optional = true } -ipnetwork = { version = ">=0.12.2, <0.19.0", optional = true } +ipnetwork = { version = ">=0.12.2, <0.20.0", optional = true } ipnet = { version = "2.5.0", optional = true } num-bigint = { version = ">=0.2.0, <0.5.0", optional = true } num-traits = { version = "0.2.0", optional = true } @@ -41,7 +41,7 @@ path = "../diesel_derives" [dev-dependencies] cfg-if = "1" dotenvy = "0.15" -ipnetwork = ">=0.12.2, <0.19.0" +ipnetwork = ">=0.12.2, <0.20.0" quickcheck = "1.0.3" [features] diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 28eb0cfcd3af..aec38e864256 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -17,7 +17,7 @@ quickcheck = "1.0.3" uuid = { version = "1.0.0" } serde_json = { version=">=0.9, <2.0" } ipnet = { version = "2.5.0" } -ipnetwork = ">=0.12.2, <0.19.0" +ipnetwork = ">=0.12.2, <0.20.0" bigdecimal = ">= 0.0.13, < 0.4.0" rand = "0.8.4" libsqlite3-sys = { version = "0.24", optional = true } From 74996c839ab5a2158c2ac183dd90908dd3160e71 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Jun 2022 23:22:20 +0200 Subject: [PATCH 061/107] Bump MSRV to 1.56 --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 2 +- ...ion_requires_column_from_same_table.stderr | 88 ++++++++++-- ...ectable_if_inner_expr_is_selectable.stderr | 22 ++- ...ay_expressions_must_be_correct_type.stderr | 38 +++--- ...array_expressions_must_be_same_type.stderr | 78 +++++++---- .../fail/boxed_queries_and_group_by.stderr | 4 +- ...re_selectable_expression_for_filter.stderr | 24 +++- ...ire_selectable_expression_for_order.stderr | 12 +- ...aggregate_and_non_aggregate_selects.stderr | 7 +- ...th_methods_other_than_filter_called.stderr | 28 +++- .../columns_cannot_be_rhs_of_insert.stderr | 13 +- ...ning_requires_selectable_expression.stderr | 24 +++- ...inct_on_allows_only_fields_of_table.stderr | 24 +++- ...ison_for_columns_from_another_table.stderr | 48 ++++++- ...aving_cant_be_used_without_group_by.stderr | 26 +++- ...n_requires_valid_boolean_expression.stderr | 11 +- ...der_requires_column_from_same_table.stderr | 11 +- .../ordering_functions_require_ord.stderr | 16 +-- ...ert_do_update_requires_valid_update.stderr | 24 +++- ...side_of_left_join_requires_nullable.stderr | 95 ++++++++++--- ...e_cannot_be_mixed_with_some_clauses.stderr | 40 +++--- .../tests/fail/selectable.stderr | 125 ++++++++++-------- ...s_all_must_be_from_selectable_table.stderr | 52 +++++++- ...lect_cannot_reference_random_tables.stderr | 33 ++++- ..._requires_column_be_from_same_table.stderr | 24 +++- .../update_requires_valid_where_clause.stderr | 54 ++++++-- ...nctions_follow_same_selection_rules.stderr | 24 +++- rust-toolchain | 2 +- 29 files changed, 753 insertions(+), 200 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b46515c2a25..a11875f4c909 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -347,7 +347,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.54.0 + toolchain: 1.56.0 profile: minimal components: clippy, rustfmt override: true @@ -468,7 +468,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.54.0 + toolchain: 1.56.0 profile: minimal override: true - name: Cache cargo registry diff --git a/CHANGELOG.md b/CHANGELOG.md index a5a7d125af45..74c6f0a5d56e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,7 +116,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi ### Changed -* The minimal officially supported rustc version is now 1.54.0 +* The minimal officially supported rustc version is now 1.56.0 * Interacting with a database requires a mutable connection. diff --git a/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr b/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr index 73872513c64d..dfa8bdcd30b3 100644 --- a/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr +++ b/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr @@ -19,11 +19,20 @@ error[E0271]: type mismatch resolving `` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_folding::sum::sum` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_folding::sum::sum` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `users::table: TableNotEqual` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:19:31 @@ -32,11 +41,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual` is not | ^^^^^^ the trait `TableNotEqual` is not implemented for `users::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `users::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_folding::sum::sum` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_folding::sum::sum` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:20:38 @@ -59,11 +77,20 @@ error[E0271]: type mismatch resolving `` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_folding::avg::avg` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_folding::avg::avg` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `users::table: TableNotEqual` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:20:31 @@ -72,11 +99,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual` is not | ^^^^^^ the trait `TableNotEqual` is not implemented for `users::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `users::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_folding::avg::avg` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_folding::avg::avg` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:21:38 @@ -99,11 +135,20 @@ error[E0271]: type mismatch resolving `` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_ordering::max::max` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_ordering::max::max` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `users::table: TableNotEqual` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:21:31 @@ -112,11 +157,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual` is not | ^^^^^^ the trait `TableNotEqual` is not implemented for `users::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `users::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_ordering::max::max` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_ordering::max::max` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:22:38 @@ -139,11 +193,20 @@ error[E0271]: type mismatch resolving `` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_ordering::min::min` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_ordering::min::min` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `users::table: TableNotEqual` is not satisfied --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:22:31 @@ -152,8 +215,17 @@ error[E0277]: the trait bound `users::table: TableNotEqual` is not | ^^^^^^ the trait `TableNotEqual` is not implemented for `users::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `users::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::id` + --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1 + | +11 | / table! { +12 | | posts { +13 | | id -> Integer, +14 | | } +15 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::functions::aggregate_ordering::min::min` = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::expression::functions::aggregate_ordering::min::min` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr b/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr index c20de9bd9205..19f3aa1e64fe 100644 --- a/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr +++ b/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr @@ -12,12 +12,21 @@ error[E0271]: type mismatch resolving `` for `more_stuff::columns::names` +note: required because of the requirements on the impl of `AppearsOnTable` for `more_stuff::columns::names` + --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:13:1 + | +13 | / table! { +14 | | more_stuff (names) { +15 | | names -> Array, +16 | | } +17 | | } + | |_^ = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::grouped::Grouped>>` = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause>` for `diesel::query_builder::where_clause::WhereClause>>>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` = note: required because of the requirements on the impl of `LoadQuery<'_, _, _>` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `stuff::table: TableNotEqual` is not satisfied --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:31:10 @@ -26,9 +35,18 @@ error[E0277]: the trait bound `stuff::table: TableNotEqual` i | ^^^^ the trait `TableNotEqual` is not implemented for `stuff::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `stuff::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `more_stuff::columns::names` +note: required because of the requirements on the impl of `AppearsOnTable` for `more_stuff::columns::names` + --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:13:1 + | +13 | / table! { +14 | | more_stuff (names) { +15 | | names -> Array, +16 | | } +17 | | } + | |_^ = note: 3 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::grouped::Grouped>>` = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause>` for `diesel::query_builder::where_clause::WhereClause>>>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` = note: required because of the requirements on the impl of `LoadQuery<'_, _, _>` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr index a236f053739f..07be69b27394 100644 --- a/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr +++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr @@ -4,17 +4,17 @@ error[E0277]: the trait bound `f64: SelectableExpression` is not s 9 | select(array((1f64, 3f64))).get_result::>(&mut connection); | ^^^^^^ the trait `SelectableExpression` is not implemented for `f64` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = note: required because of the requirements on the impl of `SelectableExpression` for `(f64, f64)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression` for `diesel::query_builder::select_clause::SelectClause>` = note: required because of the requirements on the impl of `Query` for `SelectStatement>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied --> tests/fail/array_expressions_must_be_correct_type.rs:9:5 @@ -22,16 +22,16 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied 9 | select(array((1f64, 3f64))).get_result::>(&mut connection); | ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64, f64)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `Query` for `SelectStatement>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `f64: SelectableExpression` is not satisfied --> tests/fail/array_expressions_must_be_correct_type.rs:9:33 @@ -86,10 +86,18 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied 9 | select(array((1f64, 3f64))).get_result::>(&mut connection); | ^^^^^ the trait `diesel::Expression` is not implemented for `f64` | - ::: $DIESEL/src/pg/expression/array.rs - | - | T: AsExpressionList, - | -------------------- required by this bound in `diesel::dsl::array` - | = note: required because of the requirements on the impl of `AsExpression` for `f64` = note: required because of the requirements on the impl of `AsExpressionList` for `(f64, f64)` +note: required by a bound in `diesel::dsl::array` + --> $DIESEL/src/pg/expression/array.rs + | + | T: AsExpressionList, + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array` + +error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied + --> tests/fail/array_expressions_must_be_correct_type.rs:9:12 + | +9 | select(array((1f64, 3f64))).get_result::>(&mut connection); + | ^^^^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `f64` + | + = note: required because of the requirements on the impl of `AsExpression` for `f64` diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr index a5159cd2876b..bb87fbccf054 100644 --- a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr +++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr @@ -4,17 +4,17 @@ error[E0277]: the trait bound `f64: SelectableExpression` is not s 11 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^^ the trait `SelectableExpression` is not implemented for `f64` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = note: required because of the requirements on the impl of `SelectableExpression` for `(diesel::internal::derives::as_expression::Bound, f64)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `SelectableExpression` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression` for `diesel::query_builder::select_clause::SelectClause, f64), diesel::sql_types::Integer>>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, f64), diesel::sql_types::Integer>>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement, f64), diesel::sql_types::Integer>>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied --> tests/fail/array_expressions_must_be_same_type.rs:11:5 @@ -22,16 +22,16 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied 11 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64,)` = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound, f64), diesel::sql_types::Integer>` = note: required because of the requirements on the impl of `Query` for `SelectStatement, f64), diesel::sql_types::Integer>>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement, f64), diesel::sql_types::Integer>>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `f64: SelectableExpression` is not satisfied --> tests/fail/array_expressions_must_be_same_type.rs:11:30 @@ -86,13 +86,13 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied 11 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^ the trait `diesel::Expression` is not implemented for `f64` | - ::: $DIESEL/src/pg/expression/array.rs - | - | T: AsExpressionList, - | -------------------- required by this bound in `diesel::dsl::array` - | = note: required because of the requirements on the impl of `AsExpression` for `f64` = note: required because of the requirements on the impl of `AsExpressionList` for `(i32, f64)` +note: required by a bound in `diesel::dsl::array` + --> $DIESEL/src/pg/expression/array.rs + | + | T: AsExpressionList, + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array` error[E0277]: the trait bound `{integer}: SelectableExpression` is not satisfied --> tests/fail/array_expressions_must_be_same_type.rs:12:5 @@ -100,11 +100,6 @@ error[E0277]: the trait bound `{integer}: SelectableExpression` is 12 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^^ the trait `SelectableExpression` is not implemented for `{integer}` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = help: the following implementations were found: <&'a T as SelectableExpression> <(T0, T1) as SelectableExpression> @@ -117,6 +112,11 @@ error[E0277]: the trait bound `{integer}: SelectableExpression` is = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression` for `diesel::query_builder::select_clause::SelectClause), diesel::sql_types::Double>>` = note: required because of the requirements on the impl of `Query` for `SelectStatement), diesel::sql_types::Double>>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement), diesel::sql_types::Double>>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied --> tests/fail/array_expressions_must_be_same_type.rs:12:5 @@ -124,11 +124,6 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied 12 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `{integer}` | - ::: $DIESEL/src/query_builder/functions.rs - | - | crate::dsl::BareSelect: AsQuery, - | ------- required by this bound in `diesel::select` - | = help: the following implementations were found: <&'a T as ValidGrouping> <(T0, T1) as ValidGrouping<__GroupByClause>> @@ -140,6 +135,11 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound), diesel::sql_types::Double>` = note: required because of the requirements on the impl of `Query` for `SelectStatement), diesel::sql_types::Double>>>` = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement), diesel::sql_types::Double>>>` +note: required by a bound in `diesel::select` + --> $DIESEL/src/query_builder/functions.rs + | + | crate::dsl::BareSelect: AsQuery, + | ^^^^^^^ required by this bound in `diesel::select` error[E0277]: the trait bound `{integer}: SelectableExpression` is not satisfied --> tests/fail/array_expressions_must_be_same_type.rs:12:30 @@ -218,10 +218,33 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied 12 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); | ^^^^^ the trait `diesel::Expression` is not implemented for `{integer}` | - ::: $DIESEL/src/pg/expression/array.rs + = help: the following implementations were found: + <&'a T as diesel::Expression> + <(T0, T1) as diesel::Expression> + <(T0, T1, T2) as diesel::Expression> + <(T0, T1, T2, T3) as diesel::Expression> + and 123 others + = note: required because of the requirements on the impl of `AsExpression` for `{integer}` + = note: required because of the requirements on the impl of `AsExpressionList` for `({integer}, f64)` +note: required by a bound in `diesel::dsl::array` + --> $DIESEL/src/pg/expression/array.rs | | T: AsExpressionList, - | -------------------- required by this bound in `diesel::dsl::array` + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array` + +error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied + --> tests/fail/array_expressions_must_be_same_type.rs:11:12 + | +11 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); + | ^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `f64` + | + = note: required because of the requirements on the impl of `AsExpression` for `f64` + +error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied + --> tests/fail/array_expressions_must_be_same_type.rs:12:12 + | +12 | select(array((1, 3f64))).get_result::>(&mut connection).unwrap(); + | ^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `{integer}` | = help: the following implementations were found: <&'a T as diesel::Expression> @@ -230,4 +253,3 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied <(T0, T1, T2, T3) as diesel::Expression> and 123 others = note: required because of the requirements on the impl of `AsExpression` for `{integer}` - = note: required because of the requirements on the impl of `AsExpressionList` for `({integer}, f64)` diff --git a/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr b/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr index d578f4302194..a4f9483ecb75 100644 --- a/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr +++ b/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr @@ -69,8 +69,8 @@ error[E0271]: type mismatch resolving `, _>` - found struct `SelectStatement, _>>>` + = note: expected struct `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, _>` + found struct `SelectStatement, _>>>` = note: required because of the requirements on the impl of `GroupByDsl<_>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, _>` error[E0277]: the trait bound `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, _>: Table` is not satisfied diff --git a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr index 3b0a284fe965..2a3a608fe729 100644 --- a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr +++ b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr @@ -4,10 +4,20 @@ error[E0271]: type mismatch resolving `().filter(posts::title.eq("Hello")); | ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` | - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::title` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::title` + --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:13:1 + | +13 | / table! { +14 | | posts { +15 | | id -> Integer, +16 | | title -> VarChar, +17 | | } +18 | | } + | |_^ = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::grouped::Grouped>>` = note: required because of the requirements on the impl of `FilterDsl>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, Pg>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `users::table: TableNotEqual` is not satisfied --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:21:37 @@ -16,7 +26,17 @@ error[E0277]: the trait bound `users::table: TableNotEqual` is not | ^^^^^^ the trait `TableNotEqual` is not implemented for `users::table` | = note: required because of the requirements on the impl of `AppearsInFromClause` for `users::table` - = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::title` +note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::title` + --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:13:1 + | +13 | / table! { +14 | | posts { +15 | | id -> Integer, +16 | | title -> VarChar, +17 | | } +18 | | } + | |_^ = note: 2 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::grouped::Grouped>>` = note: required because of the requirements on the impl of `FilterDsl>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, Pg>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr index 26186546641b..0a260f68dfb9 100644 --- a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr +++ b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr @@ -6,7 +6,17 @@ error[E0277]: the trait bound `FromClause: AppearsInFromClause as AppearsInFromClause> - = note: required because of the requirements on the impl of `AppearsOnTable>` for `posts::columns::title` +note: required because of the requirements on the impl of `AppearsOnTable>` for `posts::columns::title` + --> tests/fail/boxed_queries_require_selectable_expression_for_order.rs:13:1 + | +13 | / table! { +14 | | posts { +15 | | id -> Integer, +16 | | title -> VarChar, +17 | | } +18 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable>` for `diesel::expression::operators::Desc` = note: required because of the requirements on the impl of `OrderDsl>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, Pg>` + = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr b/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr index 1b0f8ad5b7e9..cccc72b55769 100644 --- a/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr +++ b/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr @@ -31,7 +31,12 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `__Derived, columns::nullable_int_col>>` +note: required because of the requirements on the impl of `ValidGrouping<()>` for `__Derived, columns::nullable_int_col>>` + --> tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.rs:14:1 + | +14 | sql_function!(fn f(x: Nullable, y: Nullable) -> Nullable); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `f::f, columns::nullable_int_col>>` = note: required because of the requirements on the impl of `SelectDsl, columns::nullable_int_col>>>` for `SelectStatement>` + = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr b/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr index 430c6f632f4d..bc887e6805d6 100644 --- a/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr +++ b/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr @@ -4,12 +4,12 @@ error[E0277]: the trait bound `SelectStatement, diesel: 15 | let command = update(users.select(id)).set(id.eq(1)); | ^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` | - ::: $DIESEL/src/query_builder/functions.rs + = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` +note: required by a bound in `diesel::update` + --> $DIESEL/src/query_builder/functions.rs | | pub fn update(source: T) -> UpdateStatement { - | ---------------- required by this bound in `diesel::update` - | - = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` + | ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update` error[E0277]: the trait bound `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>: Identifiable` is not satisfied --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:16:26 @@ -17,9 +17,25 @@ error[E0277]: the trait bound `SelectStatement, diesel: 16 | let command = update(users.order(id)).set(id.eq(1)); | ^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>` | - ::: $DIESEL/src/query_builder/functions.rs + = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>` +note: required by a bound in `diesel::update` + --> $DIESEL/src/query_builder/functions.rs | | pub fn update(source: T) -> UpdateStatement { - | ---------------- required by this bound in `diesel::update` + | ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update` + +error[E0277]: the trait bound `SelectStatement, diesel::query_builder::select_clause::SelectClause>: Identifiable` is not satisfied + --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:15:19 + | +15 | let command = update(users.select(id)).set(id.eq(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` + | + = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` + +error[E0277]: the trait bound `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>: Identifiable` is not satisfied + --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:16:19 + | +16 | let command = update(users.order(id)).set(id.eq(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>` | = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement, diesel::query_builder::select_clause::DefaultSelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause>` diff --git a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr index ffa9f34f2f80..81511790bd50 100644 --- a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr +++ b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr @@ -4,7 +4,17 @@ error[E0271]: type mismatch resolving `` for `columns::hair_color` +note: required because of the requirements on the impl of `AppearsOnTable` for `columns::hair_color` + --> tests/fail/columns_cannot_be_rhs_of_insert.rs:6:1 + | +6 | / table! { +7 | | users { +8 | | id -> Integer, +9 | | name -> Text, +10 | | hair_color -> Text, +11 | | } +12 | | } + | |_^ = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `AppearsOnTable` for `&columns::hair_color` = note: required because of the requirements on the impl of `InsertValues` for `ColumnInsertValue` @@ -12,3 +22,4 @@ error[E0271]: type mismatch resolving `