sea_query/extension/postgres/expr.rs
1use super::PgBinOper;
2use crate::{Expr, ExprTrait, IntoLikeExpr};
3
4/// Postgres-specific operator methods for building expressions.
5pub trait PgExpr: ExprTrait {
6 /// Express an postgres concatenate (`||`) expression.
7 ///
8 /// # Examples
9 ///
10 /// ```
11 /// use sea_query::{extension::postgres::PgExpr, tests_cfg::*, *};
12 ///
13 /// let query = Query::select().expr(Expr::val("a").concatenate("b")).take();
14 ///
15 /// assert_eq!(
16 /// query.to_string(PostgresQueryBuilder),
17 /// r#"SELECT 'a' || 'b'"#
18 /// );
19 ///
20 /// #[cfg(feature = "postgres-array")]
21 /// {
22 /// let query = Query::select()
23 /// .expr(Expr::val(vec!["a".to_owned()]).concatenate(vec!["b".to_owned()]))
24 /// .take();
25 ///
26 /// assert_eq!(
27 /// query.to_string(PostgresQueryBuilder),
28 /// r#"SELECT ARRAY ['a'] || ARRAY ['b']"#
29 /// );
30 /// }
31 /// ```
32 fn concatenate<T>(self, right: T) -> Expr
33 where
34 T: Into<Expr>,
35 {
36 self.binary(PgBinOper::Concatenate, right)
37 }
38
39 /// Alias of [`PgExpr::concatenate`]
40 fn concat<T>(self, right: T) -> Expr
41 where
42 T: Into<Expr>,
43 {
44 self.concatenate(right)
45 }
46
47 /// Express an postgres fulltext search matches (`@@`) expression.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use sea_query::{*, tests_cfg::*, extension::postgres::PgExpr};
53 ///
54 /// let query = Query::select()
55 /// .columns([Font::Name, Font::Variant, Font::Language])
56 /// .from(Font::Table)
57 /// .and_where(Expr::val("a & b").matches("a b"))
58 /// .and_where(Expr::col(Font::Name).matches("a b"))
59 /// .to_owned();
60 ///
61 /// assert_eq!(
62 /// query.to_string(PostgresQueryBuilder),
63 /// r#"SELECT "name", "variant", "language" FROM "font" WHERE 'a & b' @@ 'a b' AND "name" @@ 'a b'"#
64 /// );
65 /// ```
66 fn matches<T>(self, expr: T) -> Expr
67 where
68 T: Into<Expr>,
69 {
70 self.binary(PgBinOper::Matches, expr)
71 }
72
73 /// Express an postgres fulltext search contains (`@>`) expression.
74 ///
75 /// # Examples
76 ///
77 /// ```
78 /// use sea_query::{*, tests_cfg::*, extension::postgres::PgExpr};
79 ///
80 /// let query = Query::select()
81 /// .columns([Font::Name, Font::Variant, Font::Language])
82 /// .from(Font::Table)
83 /// .and_where(Expr::val("a & b").contains("a b"))
84 /// .and_where(Expr::col(Font::Name).contains("a b"))
85 /// .to_owned();
86 ///
87 /// assert_eq!(
88 /// query.to_string(PostgresQueryBuilder),
89 /// r#"SELECT "name", "variant", "language" FROM "font" WHERE 'a & b' @> 'a b' AND "name" @> 'a b'"#
90 /// );
91 /// ```
92 fn contains<T>(self, expr: T) -> Expr
93 where
94 T: Into<Expr>,
95 {
96 self.binary(PgBinOper::Contains, expr)
97 }
98
99 /// Express an postgres fulltext search contained (`<@`) expression.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use sea_query::{*, tests_cfg::*, extension::postgres::PgExpr};
105 ///
106 /// let query = Query::select()
107 /// .columns([Font::Name, Font::Variant, Font::Language])
108 /// .from(Font::Table)
109 /// .and_where(Expr::val("a & b").contained("a b"))
110 /// .and_where(Expr::col(Font::Name).contained("a b"))
111 /// .to_owned();
112 ///
113 /// assert_eq!(
114 /// query.to_string(PostgresQueryBuilder),
115 /// r#"SELECT "name", "variant", "language" FROM "font" WHERE 'a & b' <@ 'a b' AND "name" <@ 'a b'"#
116 /// );
117 /// ```
118 fn contained<T>(self, expr: T) -> Expr
119 where
120 T: Into<Expr>,
121 {
122 self.binary(PgBinOper::Contained, expr)
123 }
124
125 /// Express a `ILIKE` expression.
126 ///
127 /// # Examples
128 ///
129 /// ```
130 /// use sea_query::{*, tests_cfg::*, extension::postgres::PgExpr};
131 ///
132 /// let query = Query::select()
133 /// .columns([Char::Character, Char::SizeW, Char::SizeH])
134 /// .from(Char::Table)
135 /// .and_where(Expr::col((Char::Table, Char::Character)).ilike("Ours'%"))
136 /// .to_owned();
137 ///
138 /// assert_eq!(
139 /// query.to_string(PostgresQueryBuilder),
140 /// r#"SELECT "character", "size_w", "size_h" FROM "character" WHERE "character"."character" ILIKE E'Ours\'%'"#
141 /// );
142 /// ```
143 fn ilike<L>(self, like: L) -> Expr
144 where
145 L: IntoLikeExpr,
146 {
147 self.binary(PgBinOper::ILike, like.into_like_expr())
148 }
149
150 /// Express a `NOT ILIKE` expression
151 fn not_ilike<L>(self, like: L) -> Expr
152 where
153 L: IntoLikeExpr,
154 {
155 self.binary(PgBinOper::NotILike, like.into_like_expr())
156 }
157
158 /// Express a postgres retrieves JSON field as JSON value (`->`).
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use sea_query::{extension::postgres::PgExpr, tests_cfg::*, *};
164 ///
165 /// let query = Query::select()
166 /// .column(Font::Variant)
167 /// .from(Font::Table)
168 /// .and_where(Expr::col(Font::Variant).get_json_field("a"))
169 /// .to_owned();
170 ///
171 /// assert_eq!(
172 /// query.to_string(PostgresQueryBuilder),
173 /// r#"SELECT "variant" FROM "font" WHERE "variant" -> 'a'"#
174 /// );
175 /// ```
176 fn get_json_field<T>(self, right: T) -> Expr
177 where
178 T: Into<Expr>,
179 {
180 self.binary(PgBinOper::GetJsonField, right)
181 }
182
183 /// Express a postgres retrieves JSON field and casts it to an appropriate SQL type (`->>`).
184 ///
185 /// # Examples
186 ///
187 /// ```
188 /// use sea_query::{extension::postgres::PgExpr, tests_cfg::*, *};
189 ///
190 /// let query = Query::select()
191 /// .column(Font::Variant)
192 /// .from(Font::Table)
193 /// .and_where(Expr::col(Font::Variant).cast_json_field("a"))
194 /// .to_owned();
195 ///
196 /// assert_eq!(
197 /// query.to_string(PostgresQueryBuilder),
198 /// r#"SELECT "variant" FROM "font" WHERE "variant" ->> 'a'"#
199 /// );
200 /// ```
201 fn cast_json_field<T>(self, right: T) -> Expr
202 where
203 T: Into<Expr>,
204 {
205 self.binary(PgBinOper::CastJsonField, right)
206 }
207}
208
209/// You should be able to use Postgres-specific operators with all types of expressions.
210impl<T> PgExpr for T where T: ExprTrait {}