1use serde_json::Value;
2
3use crate::ast::{
4 Aliasable, Column, Comparable, Compare, ConditionTree, Function, Row, Select, SqlOp, Table,
5 Values,
6};
7
8#[cfg(any(feature = "postgresql", feature = "mysql"))]
9use super::compare::{JsonCompare, JsonType};
10use std::borrow::Cow;
11
12#[derive(Debug, Clone, PartialEq)]
15pub struct Expression<'a> {
16 pub(crate) kind: ExpressionKind<'a>,
17 pub(crate) alias: Option<Cow<'a, str>>,
18}
19
20impl<'a> Expression<'a> {
21 pub fn kind(&self) -> &ExpressionKind<'a> {
23 &self.kind
24 }
25}
26
27#[derive(Debug, Clone, PartialEq)]
29pub enum ExpressionKind<'a> {
30 Parameterized(Value),
32 Raw(&'a str),
34 Column(Box<Column<'a>>),
36 Table(Box<Table<'a>>),
38 Row(Row<'a>),
40 Selection(Box<Select<'a>>),
42 Function(Box<Function<'a>>),
44 Asterisk(Option<Box<Table<'a>>>),
46 Op(Box<SqlOp<'a>>),
48 ConditionTree(ConditionTree<'a>),
50 Compare(Compare<'a>),
52 Value(Box<Expression<'a>>),
54 Values(Values<'a>),
56 Default,
58}
59
60pub fn raw(value: &str) -> Expression<'_> {
62 Expression {
63 kind: ExpressionKind::Raw(value),
64 alias: None,
65 }
66}
67
68pub fn asterisk() -> Expression<'static> {
70 Expression {
71 kind: ExpressionKind::Asterisk(None),
72 alias: None,
73 }
74}
75
76pub fn default_value() -> Expression<'static> {
78 Expression {
79 kind: ExpressionKind::Default,
80 alias: None,
81 }
82}
83
84impl<'a> From<Function<'a>> for Expression<'a> {
85 fn from(f: Function<'a>) -> Self {
86 Expression {
87 kind: ExpressionKind::Function(Box::new(f)),
88 alias: None,
89 }
90 }
91}
92
93impl<'a> From<SqlOp<'a>> for Expression<'a> {
94 fn from(p: SqlOp<'a>) -> Self {
95 Expression {
96 kind: ExpressionKind::Op(Box::new(p)),
97 alias: None,
98 }
99 }
100}
101
102impl<'a> From<Values<'a>> for Expression<'a> {
103 fn from(value: Values<'a>) -> Self {
104 Expression {
105 kind: ExpressionKind::Values(value),
106 alias: None,
107 }
108 }
109}
110
111impl<'a, T> From<T> for Expression<'a>
112where
113 T: Into<Value>,
114{
115 fn from(p: T) -> Self {
116 Expression {
117 kind: ExpressionKind::Parameterized(p.into()),
118 alias: None,
119 }
120 }
121}
122
123impl<'a> From<Row<'a>> for Expression<'a> {
124 fn from(value: Row<'a>) -> Self {
125 Expression {
126 kind: ExpressionKind::Row(value),
127 alias: None,
128 }
129 }
130}
131
132impl<'a> From<Table<'a>> for Expression<'a> {
133 fn from(value: Table<'a>) -> Self {
134 Self {
135 kind: ExpressionKind::Table(Box::new(value)),
136 alias: None,
137 }
138 }
139}
140
141impl<'a> From<ExpressionKind<'a>> for Expression<'a> {
142 fn from(kind: ExpressionKind<'a>) -> Self {
143 Self { kind, alias: None }
144 }
145}
146
147impl<'a> Aliasable<'a> for Expression<'a> {
148 type Target = Expression<'a>;
149
150 fn alias<T>(mut self, alias: T) -> Self::Target
151 where
152 T: Into<Cow<'a, str>>,
153 {
154 self.alias = Some(alias.into());
155 self
156 }
157}
158
159impl<'a> Comparable<'a> for Expression<'a> {
160 fn equals<T>(self, comparison: T) -> Compare<'a>
161 where
162 T: Into<Expression<'a>>,
163 {
164 Compare::Equals(Box::new(self), Box::new(comparison.into()))
165 }
166
167 fn not_equals<T>(self, comparison: T) -> Compare<'a>
168 where
169 T: Into<Expression<'a>>,
170 {
171 Compare::NotEquals(Box::new(self), Box::new(comparison.into()))
172 }
173
174 fn less_than<T>(self, comparison: T) -> Compare<'a>
175 where
176 T: Into<Expression<'a>>,
177 {
178 Compare::LessThan(Box::new(self), Box::new(comparison.into()))
179 }
180
181 fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
182 where
183 T: Into<Expression<'a>>,
184 {
185 Compare::LessThanOrEquals(Box::new(self), Box::new(comparison.into()))
186 }
187
188 fn greater_than<T>(self, comparison: T) -> Compare<'a>
189 where
190 T: Into<Expression<'a>>,
191 {
192 Compare::GreaterThan(Box::new(self), Box::new(comparison.into()))
193 }
194
195 fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
196 where
197 T: Into<Expression<'a>>,
198 {
199 Compare::GreaterThanOrEquals(Box::new(self), Box::new(comparison.into()))
200 }
201
202 fn in_selection<T>(self, selection: T) -> Compare<'a>
203 where
204 T: Into<Expression<'a>>,
205 {
206 Compare::In(Box::new(self), Box::new(selection.into()))
207 }
208
209 fn not_in_selection<T>(self, selection: T) -> Compare<'a>
210 where
211 T: Into<Expression<'a>>,
212 {
213 Compare::NotIn(Box::new(self), Box::new(selection.into()))
214 }
215
216 fn like<T>(self, pattern: T) -> Compare<'a>
217 where
218 T: Into<Expression<'a>>,
219 {
220 Compare::Like(Box::new(self), Box::new(pattern.into()))
221 }
222
223 fn not_like<T>(self, pattern: T) -> Compare<'a>
224 where
225 T: Into<Expression<'a>>,
226 {
227 Compare::NotLike(Box::new(self), Box::new(pattern.into()))
228 }
229
230 #[allow(clippy::wrong_self_convention)]
231 fn is_null(self) -> Compare<'a> {
232 Compare::Null(Box::new(self))
233 }
234
235 #[allow(clippy::wrong_self_convention)]
236 fn is_not_null(self) -> Compare<'a> {
237 Compare::NotNull(Box::new(self))
238 }
239
240 fn between<T, V>(self, left: T, right: V) -> Compare<'a>
241 where
242 T: Into<Expression<'a>>,
243 V: Into<Expression<'a>>,
244 {
245 Compare::Between(
246 Box::new(self),
247 Box::new(left.into()),
248 Box::new(right.into()),
249 )
250 }
251
252 fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
253 where
254 T: Into<Expression<'a>>,
255 V: Into<Expression<'a>>,
256 {
257 Compare::NotBetween(
258 Box::new(self),
259 Box::new(left.into()),
260 Box::new(right.into()),
261 )
262 }
263
264 fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
265 where
266 T: Into<Cow<'a, str>>,
267 V: Into<Expression<'a>>,
268 {
269 Compare::Raw(
270 Box::new(self),
271 raw_comparator.into(),
272 Box::new(right.into()),
273 )
274 }
275
276 #[cfg(all(feature = "postgresql", feature = "mysql"))]
277 fn array_contains<T>(self, item: T) -> Compare<'a>
278 where
279 T: Into<Expression<'a>>,
280 {
281 Compare::JsonCompare(JsonCompare::ArrayContains(
282 Box::new(self),
283 Box::new(item.into()),
284 ))
285 }
286
287 #[cfg(all(feature = "postgresql", feature = "mysql"))]
288 fn array_contained<T>(self, item: T) -> Compare<'a>
289 where
290 T: Into<Expression<'a>>,
291 {
292 Compare::JsonCompare(JsonCompare::ArrayContained(
293 Box::new(self),
294 Box::new(item.into()),
295 ))
296 }
297
298 #[cfg(all(feature = "postgresql", feature = "mysql"))]
299 fn array_overlaps<T>(self, item: T) -> Compare<'a>
300 where
301 T: Into<Expression<'a>>,
302 {
303 Compare::JsonCompare(JsonCompare::ArrayOverlaps(
304 Box::new(self),
305 Box::new(item.into()),
306 ))
307 }
308
309 #[cfg(all(feature = "postgresql", feature = "mysql"))]
310 fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
311 where
312 T: Into<Expression<'a>>,
313 {
314 Compare::JsonCompare(JsonCompare::ArrayNotContains(
315 Box::new(self),
316 Box::new(item.into()),
317 ))
318 }
319
320 #[cfg(all(feature = "postgresql", feature = "mysql"))]
321 fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
322 where
323 T: Into<Expression<'a>>,
324 {
325 let array_starts_with: Expression =
326 super::function::json_extract_first_array_elem(self).into();
327
328 Compare::Equals(Box::new(array_starts_with), Box::new(item.into()))
329 }
330
331 #[cfg(all(feature = "postgresql", feature = "mysql"))]
332 fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
333 where
334 T: Into<Expression<'a>>,
335 {
336 let array_starts_with: Expression =
337 super::function::json_extract_first_array_elem(self).into();
338
339 Compare::NotEquals(Box::new(array_starts_with), Box::new(item.into()))
340 }
341
342 #[cfg(all(feature = "postgresql", feature = "mysql"))]
343 fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
344 where
345 T: Into<Expression<'a>>,
346 {
347 let array_ends_into: Expression =
348 super::function::json_extract_last_array_elem(self).into();
349
350 Compare::Equals(Box::new(array_ends_into), Box::new(item.into()))
351 }
352
353 #[cfg(all(feature = "postgresql", feature = "mysql"))]
354 fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
355 where
356 T: Into<Expression<'a>>,
357 {
358 let array_ends_into: Expression =
359 super::function::json_extract_last_array_elem(self).into();
360
361 Compare::NotEquals(Box::new(array_ends_into), Box::new(item.into()))
362 }
363
364 #[cfg(all(feature = "postgresql", feature = "mysql"))]
365 fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
366 where
367 T: Into<JsonType<'a>>,
368 {
369 Compare::JsonCompare(JsonCompare::TypeEquals(Box::new(self), json_type.into()))
370 }
371
372 #[cfg(all(feature = "postgresql", feature = "mysql"))]
373 fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
374 where
375 T: Into<JsonType<'a>>,
376 {
377 Compare::JsonCompare(JsonCompare::TypeNotEquals(Box::new(self), json_type.into()))
378 }
379
380 #[cfg(feature = "postgresql")]
381 fn any(self) -> Compare<'a> {
382 Compare::Any(Box::new(self))
383 }
384
385 #[cfg(feature = "postgresql")]
386 fn all(self) -> Compare<'a> {
387 Compare::All(Box::new(self))
388 }
389}