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
32 /// .select((species, name))
33 /// .filter(species.eq("ferret").and(name.eq("Jack")))
34 /// .load(connection)?;
35 /// let expected = vec![(String::from("ferret"), Some(String::from("Jack")))];
36 /// assert_eq!(expected, data);
37 /// # Ok(())
38 /// # }
39 /// ```
40 fn and<T, ST>(self, other: T) -> dsl::And<Self, T, ST>
41 where
42 Self::SqlType: SqlType,
43 ST: SqlType + TypedExpressionType + BoolOrNullableBool,
44 T: AsExpression<ST>,
45 And<Self, T::Expression>: Expression,
46 {
47 Grouped(And::new(self, other.as_expression()))
48 }
49
50 /// Creates a SQL `OR` expression
51 ///
52 /// The result will be wrapped in parenthesis, so that precedence matches
53 /// that of your function calls. For example, `false.and(false.or(true))`
54 /// will generate the SQL `FALSE AND (FALSE OR TRUE)`, which returns `false`
55 ///
56 /// # Example
57 ///
58 /// ```
59 /// # include!("../doctest_setup.rs");
60 /// #
61 /// # fn main() {
62 /// # run_test().unwrap();
63 /// # }
64 /// #
65 /// # fn run_test() -> QueryResult<()> {
66 /// # use schema::animals::dsl::*;
67 /// # let connection = &mut establish_connection();
68 /// #
69 /// diesel::insert_into(animals)
70 /// .values(&vec![
71 /// (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
72 /// (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
73 /// ])
74 /// .execute(connection)?;
75 ///
76 /// let data = animals
77 /// .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}