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}