diesel/expression_methods/
text_expression_methods.rs

1use self::private::TextOrNullableText;
2use crate::dsl;
3use crate::expression::grouped::Grouped;
4use crate::expression::operators::{Concat, Like, NotLike};
5use crate::expression::{AsExpression, Expression};
6use crate::sql_types::SqlType;
7
8/// Methods present on text expressions
9pub trait TextExpressionMethods: Expression + Sized {
10    /// Concatenates two strings using the `||` operator.
11    ///
12    /// # Example
13    ///
14    /// ```rust
15    /// # include!("../doctest_setup.rs");
16    /// #
17    /// # table! {
18    /// #     users {
19    /// #         id -> Integer,
20    /// #         name -> VarChar,
21    /// #         hair_color -> Nullable<Text>,
22    /// #     }
23    /// # }
24    /// #
25    /// # fn main() {
26    /// #     use self::users::dsl::*;
27    /// #     use diesel::insert_into;
28    /// #
29    /// #     let connection = &mut connection_no_data();
30    /// #     diesel::sql_query("CREATE TEMPORARY TABLE users (
31    /// #         id INTEGER PRIMARY KEY,
32    /// #         name VARCHAR(255) NOT NULL,
33    /// #         hair_color VARCHAR(255)
34    /// #     )").execute(connection).unwrap();
35    /// #
36    /// #     insert_into(users)
37    /// #         .values(&vec![
38    /// #             (id.eq(1), name.eq("Sean"), hair_color.eq(Some("Green"))),
39    /// #             (id.eq(2), name.eq("Tess"), hair_color.eq(None)),
40    /// #         ])
41    /// #         .execute(connection)
42    /// #         .unwrap();
43    /// #
44    /// let names = users.select(name.concat(" the Greatest")).load(connection);
45    /// let expected_names = vec![
46    ///     "Sean the Greatest".to_string(),
47    ///     "Tess the Greatest".to_string(),
48    /// ];
49    /// assert_eq!(Ok(expected_names), names);
50    ///
51    /// // If the value is nullable, the output will be nullable
52    /// let names = users.select(hair_color.concat("ish")).load(connection);
53    /// let expected_names = vec![Some("Greenish".to_string()), None];
54    /// assert_eq!(Ok(expected_names), names);
55    /// # }
56    /// ```
57    fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
58    where
59        Self::SqlType: SqlType,
60        T: AsExpression<Self::SqlType>,
61    {
62        Grouped(Concat::new(self, other.as_expression()))
63    }
64
65    /// Returns a SQL `LIKE` expression
66    ///
67    /// This method is case insensitive for SQLite and MySQL.
68    /// On PostgreSQL, `LIKE` is case sensitive. You may use
69    /// [`ilike()`](../expression_methods/trait.PgTextExpressionMethods.html#method.ilike)
70    /// for case insensitive comparison on PostgreSQL.
71    ///
72    /// # Examples
73    ///
74    /// ```rust
75    /// # include!("../doctest_setup.rs");
76    /// #
77    /// # fn main() {
78    /// #     run_test().unwrap();
79    /// # }
80    /// #
81    /// # fn run_test() -> QueryResult<()> {
82    /// #     use schema::users::dsl::*;
83    /// #     let connection = &mut establish_connection();
84    /// #
85    /// let starts_with_s = users
86    ///     .select(name)
87    ///     .filter(name.like("S%"))
88    ///     .load::<String>(connection)?;
89    /// assert_eq!(vec!["Sean"], starts_with_s);
90    /// #     Ok(())
91    /// # }
92    /// ```
93    fn like<T>(self, other: T) -> dsl::Like<Self, T>
94    where
95        Self::SqlType: SqlType,
96        T: AsExpression<Self::SqlType>,
97    {
98        Grouped(Like::new(self, other.as_expression()))
99    }
100
101    /// Returns a SQL `NOT LIKE` expression
102    ///
103    /// This method is case insensitive for SQLite and MySQL.
104    /// On PostgreSQL `NOT LIKE` is case sensitive. You may use
105    /// [`not_ilike()`](../expression_methods/trait.PgTextExpressionMethods.html#method.not_ilike)
106    /// for case insensitive comparison on PostgreSQL.
107    ///
108    /// # Examples
109    ///
110    /// ```rust
111    /// # include!("../doctest_setup.rs");
112    /// #
113    /// # fn main() {
114    /// #     run_test().unwrap();
115    /// # }
116    /// #
117    /// # fn run_test() -> QueryResult<()> {
118    /// #     use schema::users::dsl::*;
119    /// #     let connection = &mut establish_connection();
120    /// #
121    /// let doesnt_start_with_s = users
122    ///     .select(name)
123    ///     .filter(name.not_like("S%"))
124    ///     .load::<String>(connection)?;
125    /// assert_eq!(vec!["Tess"], doesnt_start_with_s);
126    /// #     Ok(())
127    /// # }
128    /// ```
129    fn not_like<T>(self, other: T) -> dsl::NotLike<Self, T>
130    where
131        Self::SqlType: SqlType,
132        T: AsExpression<Self::SqlType>,
133    {
134        Grouped(NotLike::new(self, other.as_expression()))
135    }
136}
137
138impl<T> TextExpressionMethods for T
139where
140    T: Expression,
141    T::SqlType: TextOrNullableText,
142{
143}
144
145mod private {
146    use crate::sql_types::{Nullable, Text};
147
148    /// Marker trait used to implement `TextExpressionMethods` on the appropriate
149    /// types. Once coherence takes associated types into account, we can remove
150    /// this trait.
151    pub trait TextOrNullableText {}
152
153    impl TextOrNullableText for Text {}
154    impl TextOrNullableText for Nullable<Text> {}
155
156    #[cfg(feature = "postgres_backend")]
157    impl TextOrNullableText for crate::pg::sql_types::Citext {}
158    #[cfg(feature = "postgres_backend")]
159    impl TextOrNullableText for Nullable<crate::pg::sql_types::Citext> {}
160}