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 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![
54    ///     Some("Greenish".to_string()),
55    ///     None,
56    /// ];
57    /// assert_eq!(Ok(expected_names), names);
58    /// # }
59    /// ```
60    fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
61    where
62        Self::SqlType: SqlType,
63        T: AsExpression<Self::SqlType>,
64    {
65        Grouped(Concat::new(self, other.as_expression()))
66    }
67
68    /// Returns a SQL `LIKE` expression
69    ///
70    /// This method is case insensitive for SQLite and MySQL.
71    /// On PostgreSQL, `LIKE` is case sensitive. You may use
72    /// [`ilike()`](../expression_methods/trait.PgTextExpressionMethods.html#method.ilike)
73    /// for case insensitive comparison on PostgreSQL.
74    ///
75    /// # Examples
76    ///
77    /// ```rust
78    /// # include!("../doctest_setup.rs");
79    /// #
80    /// # fn main() {
81    /// #     run_test().unwrap();
82    /// # }
83    /// #
84    /// # fn run_test() -> QueryResult<()> {
85    /// #     use schema::users::dsl::*;
86    /// #     let connection = &mut establish_connection();
87    /// #
88    /// let starts_with_s = users
89    ///     .select(name)
90    ///     .filter(name.like("S%"))
91    ///     .load::<String>(connection)?;
92    /// assert_eq!(vec!["Sean"], starts_with_s);
93    /// #     Ok(())
94    /// # }
95    /// ```
96    fn like<T>(self, other: T) -> dsl::Like<Self, T>
97    where
98        Self::SqlType: SqlType,
99        T: AsExpression<Self::SqlType>,
100    {
101        Grouped(Like::new(self, other.as_expression()))
102    }
103
104    /// Returns a SQL `NOT LIKE` expression
105    ///
106    /// This method is case insensitive for SQLite and MySQL.
107    /// On PostgreSQL `NOT LIKE` is case sensitive. You may use
108    /// [`not_ilike()`](../expression_methods/trait.PgTextExpressionMethods.html#method.not_ilike)
109    /// for case insensitive comparison on PostgreSQL.
110    ///
111    /// # Examples
112    ///
113    /// ```rust
114    /// # include!("../doctest_setup.rs");
115    /// #
116    /// # fn main() {
117    /// #     run_test().unwrap();
118    /// # }
119    /// #
120    /// # fn run_test() -> QueryResult<()> {
121    /// #     use schema::users::dsl::*;
122    /// #     let connection = &mut establish_connection();
123    /// #
124    /// let doesnt_start_with_s = users
125    ///     .select(name)
126    ///     .filter(name.not_like("S%"))
127    ///     .load::<String>(connection)?;
128    /// assert_eq!(vec!["Tess"], doesnt_start_with_s);
129    /// #     Ok(())
130    /// # }
131    /// ```
132    fn not_like<T>(self, other: T) -> dsl::NotLike<Self, T>
133    where
134        Self::SqlType: SqlType,
135        T: AsExpression<Self::SqlType>,
136    {
137        Grouped(NotLike::new(self, other.as_expression()))
138    }
139}
140
141impl<T> TextExpressionMethods for T
142where
143    T: Expression,
144    T::SqlType: TextOrNullableText,
145{
146}
147
148mod private {
149    use crate::sql_types::{Nullable, Text};
150
151    /// Marker trait used to implement `TextExpressionMethods` on the appropriate
152    /// types. Once coherence takes associated types into account, we can remove
153    /// this trait.
154    pub trait TextOrNullableText {}
155
156    impl TextOrNullableText for Text {}
157    impl TextOrNullableText for Nullable<Text> {}
158}