diesel/sqlite/expression/
expression_methods.rs

1//! Sqlite specific expression methods.
2
3pub(in crate::sqlite) use self::private::{
4    BinaryOrNullableBinary, JsonOrNullableJson, JsonOrNullableJsonOrJsonbOrNullableJsonb,
5    MaybeNullableValue, NotBlob, TextOrNullableText, TextOrNullableTextOrBinaryOrNullableBinary,
6};
7use super::operators::*;
8use crate::dsl;
9use crate::expression::grouped::Grouped;
10use crate::expression::{AsExpression, Expression};
11use crate::sql_types::SqlType;
12
13/// Sqlite specific methods which are present on all expressions.
14#[cfg(feature = "sqlite")]
15pub trait SqliteExpressionMethods: Expression + Sized {
16    /// Creates a Sqlite `IS` expression.
17    ///
18    /// The `IS` operator work like = except when one or both of the operands are NULL.
19    /// In this case, if both operands are NULL, then the `IS` operator evaluates to true.
20    /// If one operand is NULL and the other is not, then the `IS` operator evaluates to false.
21    /// It is not possible for an `IS` expression to evaluate to NULL.
22    ///
23    /// # Example
24    ///
25    /// ```rust
26    /// # include!("../../doctest_setup.rs");
27    /// #
28    /// # fn main() {
29    /// #     run_test().unwrap();
30    /// # }
31    /// #
32    /// # fn run_test() -> QueryResult<()> {
33    /// #     use schema::animals::dsl::*;
34    /// #     let connection = &mut establish_connection();
35    /// let jack_is_a_dog = animals
36    ///     .select(name)
37    ///     .filter(species.is("dog"))
38    ///     .get_results::<Option<String>>(connection)?;
39    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog);
40    /// #     Ok(())
41    /// # }
42    /// ```
43    fn is<T>(self, other: T) -> dsl::Is<Self, T>
44    where
45        Self::SqlType: SqlType,
46        T: AsExpression<Self::SqlType>,
47    {
48        Grouped(Is::new(self, other.as_expression()))
49    }
50
51    /// Creates a Sqlite `IS NOT` expression.
52    ///
53    /// The `IS NOT` operator work like != except when one or both of the operands are NULL.
54    /// In this case, if both operands are NULL, then the `IS NOT` operator evaluates to false.
55    /// If one operand is NULL and the other is not, then the `IS NOT` operator is true.
56    /// It is not possible for an `IS NOT` expression to evaluate to NULL.
57    ///
58    /// # Example
59    ///
60    /// ```rust
61    /// # include!("../../doctest_setup.rs");
62    /// #
63    /// # fn main() {
64    /// #     run_test().unwrap();
65    /// # }
66    /// #
67    /// # fn run_test() -> QueryResult<()> {
68    /// #     use schema::animals::dsl::*;
69    /// #     let connection = &mut establish_connection();
70    /// let jack_is_not_a_spider = animals
71    ///     .select(name)
72    ///     .filter(species.is_not("spider"))
73    ///     .get_results::<Option<String>>(connection)?;
74    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider);
75    /// #     Ok(())
76    /// # }
77    /// ```
78    #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
79    fn is_not<T>(self, other: T) -> dsl::IsNot<Self, T>
80    where
81        Self::SqlType: SqlType,
82        T: AsExpression<Self::SqlType>,
83    {
84        Grouped(IsNot::new(self, other.as_expression()))
85    }
86}
87
88impl<T: Expression> SqliteExpressionMethods for T {}
89
90pub(in crate::sqlite) mod private {
91    use crate::sql_types::{
92        BigInt, Binary, Bool, Date, Double, Float, Integer, Json, Jsonb, MaybeNullableType,
93        Nullable, Numeric, SingleValue, SmallInt, SqlType, Text, Time, Timestamp,
94        TimestamptzSqlite,
95    };
96
97    #[diagnostic::on_unimplemented(
98        message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Nullable<Text>`",
99        note = "try to provide an expression that produces one of the expected sql types"
100    )]
101    pub trait TextOrNullableText {}
102
103    impl TextOrNullableText for Text {}
104    impl TextOrNullableText for Nullable<Text> {}
105
106    #[diagnostic::on_unimplemented(
107        message = "`{Self}` is neither `diesel::sql_types::Binary` nor `diesel::sql_types::Nullable<Binary>`",
108        note = "try to provide an expression that produces one of the expected sql types"
109    )]
110    pub trait BinaryOrNullableBinary {}
111
112    impl BinaryOrNullableBinary for Binary {}
113    impl BinaryOrNullableBinary for Nullable<Binary> {}
114
115    #[diagnostic::on_unimplemented(
116        message = "`{Self}` is neither `diesel::sql_types::Text`, `diesel::sql_types::Nullable<Text>`, `diesel::sql_types::Binary` nor `diesel::sql_types::Nullable<Binary>`",
117        note = "try to provide an expression that produces one of the expected sql types"
118    )]
119    pub trait TextOrNullableTextOrBinaryOrNullableBinary {}
120
121    impl TextOrNullableTextOrBinaryOrNullableBinary for Text {}
122    impl TextOrNullableTextOrBinaryOrNullableBinary for Nullable<Text> {}
123    impl TextOrNullableTextOrBinaryOrNullableBinary for Binary {}
124    impl TextOrNullableTextOrBinaryOrNullableBinary for Nullable<Binary> {}
125
126    #[diagnostic::on_unimplemented(
127        message = "`{Self}` is neither `diesel::sql_types::Json`, `diesel::sql_types::Jsonb`, `diesel::sql_types::Nullable<Json>` nor `diesel::sql_types::Nullable<Jsonb>`",
128        note = "try to provide an expression that produces one of the expected sql types"
129    )]
130    pub trait JsonOrNullableJsonOrJsonbOrNullableJsonb {}
131    impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Json {}
132    impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Json> {}
133    impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Jsonb {}
134    impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Jsonb> {}
135
136    #[diagnostic::on_unimplemented(
137        message = "`{Self}` is neither `diesel::sql_types::Json` nor `diesel::sql_types::Nullable<Json>`",
138        note = "try to provide an expression that produces one of the expected sql types"
139    )]
140    pub trait JsonOrNullableJson {}
141    impl JsonOrNullableJson for Json {}
142    impl JsonOrNullableJson for Nullable<Json> {}
143
144    pub trait MaybeNullableValue<T>: SingleValue {
145        type Out: SingleValue;
146    }
147
148    impl<T, O> MaybeNullableValue<O> for T
149    where
150        T: SingleValue,
151        T::IsNull: MaybeNullableType<O>,
152        <T::IsNull as MaybeNullableType<O>>::Out: SingleValue,
153    {
154        type Out = <T::IsNull as MaybeNullableType<O>>::Out;
155    }
156
157    #[diagnostic::on_unimplemented(
158        message = "`{Self}` is neither any of `diesel::sql_types::{{
159            Text, Float, Double, Numeric,  Bool, Integer, SmallInt, BigInt, 
160            Date, Time, Timestamp, TimestamptzSqlite, Json
161         }}`  nor `diesel::sql_types::Nullable<Any of the above>`",
162        note = "try to provide an expression that produces one of the expected sql types"
163    )]
164    pub trait NotBlob: SqlType + SingleValue {}
165
166    impl<T> NotBlob for Nullable<T> where T: NotBlob {}
167    impl NotBlob for Text {}
168    impl NotBlob for Float {}
169    impl NotBlob for Double {}
170    impl NotBlob for Numeric {}
171    impl NotBlob for Bool {}
172    impl NotBlob for Integer {}
173    impl NotBlob for SmallInt {}
174    impl NotBlob for BigInt {}
175    impl NotBlob for Date {}
176    impl NotBlob for Time {}
177    impl NotBlob for Timestamp {}
178    impl NotBlob for TimestamptzSqlite {}
179    impl NotBlob for Json {}
180}