diesel/expression_methods/
bool_expression_methods.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use crate::dsl;
use crate::expression::grouped::Grouped;
use crate::expression::operators::{And, Or};
use crate::expression::{AsExpression, Expression, TypedExpressionType};
use crate::sql_types::{self, BoolOrNullableBool, SqlType};

/// Methods present on boolean expressions
pub trait BoolExpressionMethods: Expression + Sized {
    /// Creates a SQL `AND` expression
    ///
    /// # Example
    ///
    /// ```
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// diesel::insert_into(animals)
    ///     .values(&vec![
    ///         (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
    ///         (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
    ///     ])
    ///     .execute(connection)?;
    ///
    /// let data = animals.select((species, name))
    ///     .filter(species.eq("ferret").and(name.eq("Jack")))
    ///     .load(connection)?;
    /// let expected = vec![
    ///     (String::from("ferret"), Some(String::from("Jack"))),
    /// ];
    /// assert_eq!(expected, data);
    /// #     Ok(())
    /// # }
    /// ```
    fn and<T, ST>(self, other: T) -> dsl::And<Self, T, ST>
    where
        Self::SqlType: SqlType,
        ST: SqlType + TypedExpressionType + BoolOrNullableBool,
        T: AsExpression<ST>,
        And<Self, T::Expression>: Expression,
    {
        Grouped(And::new(self, other.as_expression()))
    }

    /// Creates a SQL `OR` expression
    ///
    /// The result will be wrapped in parenthesis, so that precedence matches
    /// that of your function calls. For example, `false.and(false.or(true))`
    /// will generate the SQL `FALSE AND (FALSE OR TRUE)`, which returns `false`
    ///
    /// # Example
    ///
    /// ```
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// diesel::insert_into(animals)
    ///     .values(&vec![
    ///         (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
    ///         (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
    ///     ])
    ///     .execute(connection)?;
    ///
    /// let data = animals.select((species, name))
    ///     .filter(species.eq("ferret").or(name.eq("Jack")))
    ///     .load(connection)?;
    /// let expected = vec![
    ///     (String::from("dog"), Some(String::from("Jack"))),
    ///     (String::from("ferret"), Some(String::from("Freddy"))),
    ///     (String::from("ferret"), Some(String::from("Jack"))),
    /// ];
    /// assert_eq!(expected, data);
    /// #     Ok(())
    /// # }
    /// ```
    fn or<T, ST>(self, other: T) -> dsl::Or<Self, T, ST>
    where
        Self::SqlType: SqlType,
        ST: SqlType + TypedExpressionType + BoolOrNullableBool,
        T: AsExpression<ST>,
        Or<Self, T::Expression>: Expression,
    {
        Grouped(Or::new(self, other.as_expression()))
    }
}

impl<T> BoolExpressionMethods for T
where
    T: Expression,
    T::SqlType: BoolOrNullableBool,
{
}

/// Allow ~type inference on [And](crate::helper_types::And) and [Or](crate::helper_types::Or)
/// helper types
///
/// This is used to be statistically correct as last generic parameter of `dsl::And` and `dsl::Or`
/// without having to specify an additional type parameter.
///
/// It works with types that are [Expression]s and have a [`SqlType`](Expression::SqlType) that is
/// either [`Bool`](sql_types::Bool) or [`Nullable<Bool>`](sql_types::Nullable), and with [`bool`]
/// (and `Option<bool>` and references to those).
///
/// Cases where an additional type parameter would still have to be specified in the helper type
/// generic parameters are:
/// - If this trait isn't implemented for the `other` parameter of the expression
///   (in that case the user (you?) probably wants to implement it)
/// - If the user actually was using the not-preferred implementation of `AsExpression`
///   (e.g. towards `Nullable<Bool>` instead of `Bool`)
pub trait PreferredBoolSqlType {
    /// The preferred `Bool` SQL type for this AsExpression implementation.
    ///
    /// That should be either `Bool` or `Nullable<Bool>`.
    type PreferredSqlType;
}

impl<E: Expression> PreferredBoolSqlType for E
where
    E::SqlType: BoolOrNullableBool,
{
    type PreferredSqlType = <E as Expression>::SqlType;
}

/// This impl has to live in Diesel because otherwise it would conflict with the blanket impl above
/// because "diesel might add an implementation of Expression for bool"
impl PreferredBoolSqlType for bool {
    type PreferredSqlType = sql_types::Bool;
}

impl PreferredBoolSqlType for &bool {
    type PreferredSqlType = sql_types::Bool;
}

impl PreferredBoolSqlType for &&bool {
    type PreferredSqlType = sql_types::Bool;
}

impl PreferredBoolSqlType for Option<bool> {
    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}

impl PreferredBoolSqlType for &Option<bool> {
    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}

impl PreferredBoolSqlType for &&Option<bool> {
    type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}