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}