diff --git a/diesel/src/query_builder/select_statement/boxed.rs b/diesel/src/query_builder/select_statement/boxed.rs index e3dacc0396a2..ad56a7f8cae7 100644 --- a/diesel/src/query_builder/select_statement/boxed.rs +++ b/diesel/src/query_builder/select_statement/boxed.rs @@ -507,8 +507,9 @@ where } impl<'a, ST, QS, DB, GB, Predicate> HavingDsl - for BoxedSelectStatement<'a, ST, QS, DB, GB> + for BoxedSelectStatement<'a, ST, FromClause, DB, GB> where + QS: QuerySource, DB: Backend, GB: Expression, HavingClause: QueryFragment + Send + 'a, diff --git a/diesel/src/query_builder/select_statement/dsl_impls.rs b/diesel/src/query_builder/select_statement/dsl_impls.rs index 8d475dca7aa7..b503264a4288 100644 --- a/diesel/src/query_builder/select_statement/dsl_impls.rs +++ b/diesel/src/query_builder/select_statement/dsl_impls.rs @@ -662,13 +662,15 @@ where } impl HavingDsl - for SelectStatement, H> + for SelectStatement, S, D, W, O, LOf, GroupByClause, H> where + F: QuerySource, Predicate: AppearsOnTable, Predicate: Expression, Predicate::SqlType: BoolOrNullableBool, { - type Output = SelectStatement, HavingClause>; + type Output = + SelectStatement, S, D, W, O, LOf, GroupByClause, HavingClause>; fn having(self, predicate: Predicate) -> Self::Output { SelectStatement::new( diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock index 618c9225cabe..96e4cf9425aa 100644 --- a/diesel_compile_tests/Cargo.lock +++ b/diesel_compile_tests/Cargo.lock @@ -99,7 +99,7 @@ dependencies = [ [[package]] name = "diesel" -version = "2.1.0" +version = "2.1.4" dependencies = [ "bigdecimal", "bitflags 2.2.1", diff --git a/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr b/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr index 36176be02639..caab06846b20 100644 --- a/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr +++ b/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `SelectStatement, diesel: 26 | users::table.select(users::name).having(users::id.gt(1)).load(&mut conn); | ^^^^^^ the trait `HavingDsl<_>` is not implemented for `SelectStatement, diesel::query_builder::select_clause::SelectClause>` | - = help: the trait `HavingDsl` is implemented for `SelectStatement, H>` + = help: the trait `HavingDsl` is implemented for `SelectStatement, S, D, W, O, LOf, diesel::query_builder::group_by_clause::GroupByClause, H>` error[E0277]: the trait bound `(): diesel::Expression` is not satisfied --> tests/fail/having_cant_be_used_without_group_by.rs:28:31 @@ -24,32 +24,32 @@ error[E0277]: the trait bound `(): diesel::Expression` is not satisfied and $N others = note: required for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause, _>` to implement `HavingDsl<_>` -error[E0271]: type mismatch resolving ` as AppearsInFromClause>::Count == Once` +error[E0271]: type mismatch resolving `
>::Count == Once` --> tests/fail/having_cant_be_used_without_group_by.rs:30:58 | 30 | users::table.select(users::name).group_by(users::id).having(posts::id.eq(42)).load(&mut conn); | ^^^^^^ expected `Never`, found `Once` | -note: required for `posts::columns::id` to implement `AppearsOnTable>` +note: required for `posts::columns::id` to implement `AppearsOnTable` --> tests/fail/having_cant_be_used_without_group_by.rs:14:9 | 14 | id -> Integer, | ^^ = note: 2 redundant requirements hidden - = note: required for `Grouped>>` to implement `AppearsOnTable>` + = note: required for `Grouped>>` to implement `AppearsOnTable` = note: required for `SelectStatement, SelectClause, NoDistinctClause, NoWhereClause, ..., ..., ...>` to implement `HavingDsl>>>` -error[E0271]: type mismatch resolving ` as AppearsInFromClause
>::Count == Once` +error[E0271]: type mismatch resolving `
>::Count == Once` --> tests/fail/having_cant_be_used_without_group_by.rs:32:71 | 32 | users::table.select(users::name).group_by(users::id).into_boxed().having(posts::id.eq(42)).load(&mut conn); | ^^^^^^ expected `Never`, found `Once` | -note: required for `posts::columns::id` to implement `AppearsOnTable>` +note: required for `posts::columns::id` to implement `AppearsOnTable` --> tests/fail/having_cant_be_used_without_group_by.rs:14:9 | 14 | id -> Integer, | ^^ = note: 2 redundant requirements hidden - = note: required for `Grouped>>` to implement `AppearsOnTable>` + = note: required for `Grouped>>` to implement `AppearsOnTable` = note: required for `BoxedSelectStatement<'_, diesel::sql_types::Text, FromClause, _, users::columns::id>` to implement `HavingDsl>>>` diff --git a/diesel_tests/tests/boxed_queries.rs b/diesel_tests/tests/boxed_queries.rs index 2805342dc95d..1caf399dc48e 100644 --- a/diesel_tests/tests/boxed_queries.rs +++ b/diesel_tests/tests/boxed_queries.rs @@ -1,4 +1,5 @@ use super::schema::*; +use diesel::expression::is_aggregate; use diesel::*; #[test] @@ -179,3 +180,47 @@ fn can_box_query_with_boxable_expression() { let expected = vec![find_user_by_name("Sean", connection)]; assert_eq!(Ok(expected), data); } + +#[test] +fn can_box_query_having_with_boxable_expression() { + let connection = &mut connection_with_sean_and_tess_in_users_table(); + + let expr: Box< + dyn BoxableExpression< + users::table, + crate::schema::TestBackend, + users::id, + is_aggregate::Yes, + SqlType = _, + >, + > = Box::new(count(users::id).eq(1)) as _; + + use diesel::dsl::count; + + let data = users::table + .select(count(users::id)) + .group_by(users::id) + .having(expr) + .load::(connection) + .expect("db error"); + assert_eq!(data, [1, 1]); + + let expr: Box< + dyn BoxableExpression< + users::table, + crate::schema::TestBackend, + users::id, + is_aggregate::Yes, + SqlType = _, + >, + > = Box::new(count(users::id).eq(1)) as _; + + let data = users::table + .select(count(users::id)) + .group_by(users::id) + .into_boxed() + .having(expr) + .load::(connection) + .expect("db error"); + assert_eq!(data, [1, 1]); +}