Skip to content

Commit

Permalink
Merge pull request #4354 from Ten0/fix_eq_any_nullability
Browse files Browse the repository at this point in the history
Fix eq_any's nullability
  • Loading branch information
weiznich authored Nov 22, 2024
2 parents 1a37a94 + e945461 commit 75c5846
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi
* Added `diesel::r2d2::TestCustomizer`, which allows users to customize their `diesel::r2d2::Pool`s
in a way that makes the pools suitable for use in parallel tests.
* Added `Json` and `Jsonb` support for the SQLite backend.
* Fixed diesel thinking `a.eq_any(b)` was non-nullable even if `a` and `b` were nullable.

## [2.2.2] 2024-07-19

Expand Down
23 changes: 16 additions & 7 deletions diesel/src/expression/array_comparison.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! This module contains the query dsl node definitions
//! for array comparison operations like `IN` and `NOT IN`

use crate::backend::sql_dialect;
use crate::backend::Backend;
use crate::backend::SqlDialect;
use crate::backend::{sql_dialect, Backend, SqlDialect};
use crate::expression::subselect::Subselect;
use crate::expression::{
AppearsOnTable, AsExpression, Expression, SelectableExpression, TypedExpressionType,
Expand All @@ -15,8 +13,7 @@ use crate::query_builder::{
};
use crate::result::QueryResult;
use crate::serialize::ToSql;
use crate::sql_types::HasSqlType;
use crate::sql_types::{Bool, SingleValue, SqlType};
use crate::sql_types::{self, HasSqlType, SingleValue, SqlType};
use std::marker::PhantomData;

/// Query dsl node that represents a `left IN (values)`
Expand Down Expand Up @@ -75,16 +72,28 @@ impl<T, U> Expression for In<T, U>
where
T: Expression,
U: Expression<SqlType = T::SqlType>,
T::SqlType: SqlType,
sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>:
sql_types::MaybeNullableType<sql_types::Bool>,
{
type SqlType = Bool;
type SqlType = sql_types::is_nullable::MaybeNullable<
sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>,
sql_types::Bool,
>;
}

impl<T, U> Expression for NotIn<T, U>
where
T: Expression,
U: Expression<SqlType = T::SqlType>,
T::SqlType: SqlType,
sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>:
sql_types::MaybeNullableType<sql_types::Bool>,
{
type SqlType = Bool;
type SqlType = sql_types::is_nullable::MaybeNullable<
sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>,
sql_types::Bool,
>;
}

impl<T, U, DB> QueryFragment<DB> for In<T, U>
Expand Down
20 changes: 20 additions & 0 deletions diesel_compile_tests/tests/fail/eq_any_is_nullable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
extern crate diesel;

use diesel::*;

table! {
users{
id -> Integer,
name -> Nullable<Text>,
}
}

fn main() {
let mut conn = PgConnection::establish("").unwrap();
// Should not be allowed because `users::name` is nullable, so the result of `eq_any` is
// nullable as well.
let _: Vec<bool> = users::table
.select(users::name.eq_any(["foo", "bar"]))
.load(&mut conn)
.unwrap();
}
25 changes: 25 additions & 0 deletions diesel_compile_tests/tests/fail/eq_any_is_nullable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0277]: cannot deserialize a value of the database type `diesel::sql_types::Nullable<Bool>` as `bool`
--> tests/fail/eq_any_is_nullable.rs:18:15
|
18 | .load(&mut conn)
| ---- ^^^^^^^^^ the trait `FromSql<diesel::sql_types::Nullable<Bool>, Pg>` is not implemented for `bool`, which is required by `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<diesel::expression::grouped::Grouped<In<columns::name, Many<diesel::sql_types::Nullable<diesel::sql_types::Text>, &str>>>>>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: double check your type mappings via the documentation of `diesel::sql_types::Nullable<Bool>`
= help: the following other types implement trait `FromSql<A, DB>`:
`bool` implements `FromSql<Bool, Mysql>`
`bool` implements `FromSql<Bool, Pg>`
`bool` implements `FromSql<Bool, Sqlite>`
= note: required for `bool` to implement `Queryable<diesel::sql_types::Nullable<Bool>, Pg>`
= note: required for `bool` to implement `FromSqlRow<diesel::sql_types::Nullable<Bool>, Pg>`
= note: required for `diesel::sql_types::Nullable<Bool>` to implement `load_dsl::private::CompatibleType<bool, Pg>`
= note: required for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<diesel::expression::grouped::Grouped<In<columns::name, Many<diesel::sql_types::Nullable<diesel::sql_types::Text>, &str>>>>>` to implement `LoadQuery<'_, diesel::PgConnection, bool>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> $DIESEL/src/query_dsl/mod.rs
|
| fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
| where
| Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`

0 comments on commit 75c5846

Please sign in to comment.