Skip to main content

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