diesel/expression_methods/
bool_expression_methods.rs

1use crate::dsl;
2use crate::expression::grouped::Grouped;
3use crate::expression::operators::{And, Or};
4use crate::expression::{AsExpression, Expression, TypedExpressionType};
5use crate::sql_types::{self, BoolOrNullableBool, SqlType};
6
7/// Methods present on boolean expressions
8pub trait BoolExpressionMethods: Expression + Sized {
9    /// Creates a SQL `AND` expression
10    ///
11    /// # Example
12    ///
13    /// ```
14    /// # include!("../doctest_setup.rs");
15    /// #
16    /// # fn main() {
17    /// #     run_test().unwrap();
18    /// # }
19    /// #
20    /// # fn run_test() -> QueryResult<()> {
21    /// #     use schema::animals::dsl::*;
22    /// #     let connection = &mut establish_connection();
23    /// #
24    /// diesel::insert_into(animals)
25    ///     .values(&vec![
26    ///         (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
27    ///         (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
28    ///     ])
29    ///     .execute(connection)?;
30    ///
31    /// let data = animals.select((species, name))
32    ///     .filter(species.eq("ferret").and(name.eq("Jack")))
33    ///     .load(connection)?;
34    /// let expected = vec![
35    ///     (String::from("ferret"), Some(String::from("Jack"))),
36    /// ];
37    /// assert_eq!(expected, data);
38    /// #     Ok(())
39    /// # }
40    /// ```
41    fn and<T, ST>(self, other: T) -> dsl::And<Self, T, ST>
42    where
43        Self::SqlType: SqlType,
44        ST: SqlType + TypedExpressionType + BoolOrNullableBool,
45        T: AsExpression<ST>,
46        And<Self, T::Expression>: Expression,
47    {
48        Grouped(And::new(self, other.as_expression()))
49    }
50
51    /// Creates a SQL `OR` expression
52    ///
53    /// The result will be wrapped in parenthesis, so that precedence matches
54    /// that of your function calls. For example, `false.and(false.or(true))`
55    /// will generate the SQL `FALSE AND (FALSE OR TRUE)`, which returns `false`
56    ///
57    /// # Example
58    ///
59    /// ```
60    /// # include!("../doctest_setup.rs");
61    /// #
62    /// # fn main() {
63    /// #     run_test().unwrap();
64    /// # }
65    /// #
66    /// # fn run_test() -> QueryResult<()> {
67    /// #     use schema::animals::dsl::*;
68    /// #     let connection = &mut establish_connection();
69    /// #
70    /// diesel::insert_into(animals)
71    ///     .values(&vec![
72    ///         (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
73    ///         (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
74    ///     ])
75    ///     .execute(connection)?;
76    ///
77    /// let data = animals.select((species, name))
78    ///     .filter(species.eq("ferret").or(name.eq("Jack")))
79    ///     .load(connection)?;
80    /// let expected = vec![
81    ///     (String::from("dog"), Some(String::from("Jack"))),
82    ///     (String::from("ferret"), Some(String::from("Freddy"))),
83    ///     (String::from("ferret"), Some(String::from("Jack"))),
84    /// ];
85    /// assert_eq!(expected, data);
86    /// #     Ok(())
87    /// # }
88    /// ```
89    fn or<T, ST>(self, other: T) -> dsl::Or<Self, T, ST>
90    where
91        Self::SqlType: SqlType,
92        ST: SqlType + TypedExpressionType + BoolOrNullableBool,
93        T: AsExpression<ST>,
94        Or<Self, T::Expression>: Expression,
95    {
96        Grouped(Or::new(self, other.as_expression()))
97    }
98}
99
100impl<T> BoolExpressionMethods for T
101where
102    T: Expression,
103    T::SqlType: BoolOrNullableBool,
104{
105}
106
107/// Allow ~type inference on [And](crate::helper_types::And) and [Or](crate::helper_types::Or)
108/// helper types
109///
110/// This is used to be statistically correct as last generic parameter of `dsl::And` and `dsl::Or`
111/// without having to specify an additional type parameter.
112///
113/// It works with types that are [Expression]s and have a [`SqlType`](Expression::SqlType) that is
114/// either [`Bool`](sql_types::Bool) or [`Nullable<Bool>`](sql_types::Nullable), and with [`bool`]
115/// (and `Option<bool>` and references to those).
116///
117/// Cases where an additional type parameter would still have to be specified in the helper type
118/// generic parameters are:
119/// - If this trait isn't implemented for the `other` parameter of the expression
120///   (in that case the user (you?) probably wants to implement it)
121/// - If the user actually was using the not-preferred implementation of `AsExpression`
122///   (e.g. towards `Nullable<Bool>` instead of `Bool`)
123pub trait PreferredBoolSqlType {
124    /// The preferred `Bool` SQL type for this AsExpression implementation.
125    ///
126    /// That should be either `Bool` or `Nullable<Bool>`.
127    type PreferredSqlType;
128}
129
130impl<E: Expression> PreferredBoolSqlType for E
131where
132    E::SqlType: BoolOrNullableBool,
133{
134    type PreferredSqlType = <E as Expression>::SqlType;
135}
136
137/// This impl has to live in Diesel because otherwise it would conflict with the blanket impl above
138/// because "diesel might add an implementation of Expression for bool"
139impl PreferredBoolSqlType for bool {
140    type PreferredSqlType = sql_types::Bool;
141}
142
143impl PreferredBoolSqlType for &bool {
144    type PreferredSqlType = sql_types::Bool;
145}
146
147impl PreferredBoolSqlType for &&bool {
148    type PreferredSqlType = sql_types::Bool;
149}
150
151impl PreferredBoolSqlType for Option<bool> {
152    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
153}
154
155impl PreferredBoolSqlType for &Option<bool> {
156    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
157}
158
159impl PreferredBoolSqlType for &&Option<bool> {
160    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
161}