quaint_forked/ast/
expression.rs

1#[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
2use super::compare::{JsonCompare, JsonType};
3use crate::ast::*;
4use query::SelectQuery;
5use std::borrow::Cow;
6
7/// An expression that can be positioned in a query. Can be a single value or a
8/// statement that is evaluated into a value.
9#[derive(Debug, Clone, PartialEq)]
10pub struct Expression<'a> {
11    pub(crate) kind: ExpressionKind<'a>,
12    pub(crate) alias: Option<Cow<'a, str>>,
13}
14
15impl<'a> Expression<'a> {
16    /// The type of the expression, dictates how it's implemented in the query.
17    pub fn kind(&self) -> &ExpressionKind<'a> {
18        &self.kind
19    }
20
21    /// The name alias of the expression, how it can referred in the query.
22    pub fn alias(&self) -> Option<&str> {
23        self.alias.as_ref().map(|s| s.as_ref())
24    }
25
26    #[allow(dead_code)]
27    pub(crate) fn row(row: Row<'a>) -> Self {
28        Self {
29            kind: ExpressionKind::Row(row),
30            alias: None,
31        }
32    }
33
34    pub(crate) fn union(union: Union<'a>) -> Self {
35        Self::selection(SelectQuery::Union(Box::new(union)))
36    }
37
38    #[allow(dead_code)]
39    pub(crate) fn selection(selection: SelectQuery<'a>) -> Self {
40        Self {
41            kind: ExpressionKind::Selection(selection),
42            alias: None,
43        }
44    }
45
46    #[cfg(feature = "json")]
47    pub(crate) fn is_json_expr(&self) -> bool {
48        match &self.kind {
49            #[cfg(feature = "json")]
50            ExpressionKind::Parameterized(Value::Json(_)) => true,
51            #[cfg(feature = "json")]
52            ExpressionKind::Value(expr) => expr.is_json_value(),
53            #[cfg(feature = "json")]
54            ExpressionKind::Function(fun) => fun.returns_json(),
55            _ => false,
56        }
57    }
58
59    #[allow(dead_code)]
60    #[cfg(feature = "json")]
61    pub(crate) fn is_json_value(&self) -> bool {
62        match &self.kind {
63            #[cfg(feature = "json")]
64            ExpressionKind::Parameterized(Value::Json(_)) => true,
65            #[cfg(feature = "json")]
66            ExpressionKind::Value(expr) => expr.is_json_value(),
67            _ => false,
68        }
69    }
70
71    #[allow(dead_code)]
72    #[cfg(feature = "json")]
73    pub(crate) fn into_json_value(self) -> Option<serde_json::Value> {
74        match self.kind {
75            #[cfg(feature = "json")]
76            ExpressionKind::Parameterized(Value::Json(json_val)) => json_val,
77            #[cfg(feature = "json")]
78            ExpressionKind::Value(expr) => expr.into_json_value(),
79            _ => None,
80        }
81    }
82
83    #[allow(dead_code)]
84    pub(crate) fn is_fun_retuning_json(&self) -> bool {
85        match &self.kind {
86            ExpressionKind::Function(f) => f.returns_json(),
87            _ => false,
88        }
89    }
90
91    #[allow(dead_code)]
92    pub(crate) fn is_xml_value(&self) -> bool {
93        self.kind.is_xml_value()
94    }
95
96    #[allow(dead_code)]
97    pub fn is_asterisk(&self) -> bool {
98        matches!(self.kind, ExpressionKind::Asterisk(_))
99    }
100
101    #[allow(dead_code)]
102    pub(crate) fn is_row(&self) -> bool {
103        matches!(self.kind, ExpressionKind::Row(_))
104    }
105
106    #[allow(dead_code)]
107    pub(crate) fn into_row(self) -> Option<Row<'a>> {
108        match self.kind {
109            ExpressionKind::Row(row) => Some(row),
110            _ => None,
111        }
112    }
113
114    #[allow(dead_code)]
115    pub(crate) fn into_selection(self) -> Option<SelectQuery<'a>> {
116        match self.kind {
117            ExpressionKind::Selection(selection) => Some(selection),
118            _ => None,
119        }
120    }
121
122    #[allow(dead_code)]
123    pub(crate) fn into_column(self) -> Option<Column<'a>> {
124        match self.kind {
125            ExpressionKind::Column(column) => Some(*column),
126            _ => None,
127        }
128    }
129
130    #[allow(dead_code)]
131    pub(crate) fn is_selection(&self) -> bool {
132        matches!(self.kind, ExpressionKind::Selection(_))
133    }
134
135    #[allow(dead_code)]
136    pub(crate) fn is_column(&self) -> bool {
137        matches!(self.kind, ExpressionKind::Column(_))
138    }
139
140    /// Finds all comparisons between a tuple and a selection. If returning some
141    /// CTEs, they should be handled in the calling layer.
142    #[cfg(feature = "mssql")]
143    pub(crate) fn convert_tuple_selects_to_ctes(self, level: &mut usize) -> (Self, Vec<CommonTableExpression<'a>>) {
144        match self.kind {
145            ExpressionKind::Selection(s) => {
146                let (selection, ctes) = s.convert_tuple_selects_to_ctes(level);
147
148                let expr = Expression {
149                    kind: ExpressionKind::Selection(selection),
150                    alias: self.alias,
151                };
152
153                (expr, ctes)
154            }
155            ExpressionKind::Compare(compare) => match compare.convert_tuple_select_to_cte(level) {
156                // No conversion
157                either::Either::Left(compare) => {
158                    let expr = Expression {
159                        kind: ExpressionKind::Compare(compare),
160                        alias: self.alias,
161                    };
162
163                    (expr, Vec::new())
164                }
165                // Conversion happened
166                either::Either::Right((comp, ctes)) => {
167                    let expr = Expression {
168                        kind: ExpressionKind::Compare(comp),
169                        alias: self.alias,
170                    };
171
172                    (expr, ctes)
173                }
174            },
175            ExpressionKind::ConditionTree(tree) => {
176                let (tree, ctes) = tree.convert_tuple_selects_to_ctes(level);
177
178                let expr = Expression {
179                    kind: ExpressionKind::ConditionTree(tree),
180                    alias: self.alias,
181                };
182
183                (expr, ctes)
184            }
185            _ => (self, Vec::new()),
186        }
187    }
188}
189
190/// An expression we can compare and use in database queries.
191#[derive(Debug, Clone, PartialEq)]
192pub enum ExpressionKind<'a> {
193    /// Anything that we must parameterize before querying
194    Parameterized(Value<'a>),
195    /// A user-provided value we do not parameterize.
196    RawValue(Raw<'a>),
197    /// A database column
198    Column(Box<Column<'a>>),
199    /// Data in a row form, e.g. (1, 2, 3)
200    Row(Row<'a>),
201    /// A nested `SELECT` or `SELECT .. UNION` statement
202    Selection(SelectQuery<'a>),
203    /// A database function call
204    Function(Box<Function<'a>>),
205    /// A qualified asterisk to a table
206    Asterisk(Option<Box<Table<'a>>>),
207    /// An operation: sum, sub, mul or div.
208    Op(Box<SqlOp<'a>>),
209    /// A `VALUES` statement
210    Values(Box<Values<'a>>),
211    /// A tree of expressions to evaluate from the deepest value to up
212    ConditionTree(ConditionTree<'a>),
213    /// A comparison expression
214    Compare(Compare<'a>),
215    /// A single value, column, row or a nested select
216    Value(Box<Expression<'a>>),
217    /// DEFAULT keyword, e.g. for `INSERT INTO ... VALUES (..., DEFAULT, ...)`
218    Default,
219}
220
221impl<'a> ExpressionKind<'a> {
222    pub(crate) fn is_xml_value(&self) -> bool {
223        match self {
224            Self::Parameterized(Value::Xml(_)) => true,
225            Self::Value(expr) => expr.is_xml_value(),
226            _ => false,
227        }
228    }
229}
230
231/// A quick alias to create an asterisk to a table.
232pub fn asterisk() -> Expression<'static> {
233    Expression {
234        kind: ExpressionKind::Asterisk(None),
235        alias: None,
236    }
237}
238
239/// A quick alias to create a default value expression.
240pub fn default_value() -> Expression<'static> {
241    Expression {
242        kind: ExpressionKind::Default,
243        alias: None,
244    }
245}
246
247expression!(Row, Row);
248
249impl<'a> From<Function<'a>> for Expression<'a> {
250    fn from(f: Function<'a>) -> Self {
251        Expression {
252            kind: ExpressionKind::Function(Box::new(f)),
253            alias: None,
254        }
255    }
256}
257
258impl<'a> From<Raw<'a>> for Expression<'a> {
259    fn from(r: Raw<'a>) -> Self {
260        Expression {
261            kind: ExpressionKind::RawValue(r),
262            alias: None,
263        }
264    }
265}
266
267impl<'a> From<Values<'a>> for Expression<'a> {
268    fn from(p: Values<'a>) -> Self {
269        Expression {
270            kind: ExpressionKind::Values(Box::new(p)),
271            alias: None,
272        }
273    }
274}
275
276impl<'a> From<SqlOp<'a>> for Expression<'a> {
277    fn from(p: SqlOp<'a>) -> Self {
278        Expression {
279            kind: ExpressionKind::Op(Box::new(p)),
280            alias: None,
281        }
282    }
283}
284
285impl<'a, T> From<T> for Expression<'a>
286where
287    T: Into<Value<'a>>,
288{
289    fn from(p: T) -> Self {
290        Expression {
291            kind: ExpressionKind::Parameterized(p.into()),
292            alias: None,
293        }
294    }
295}
296
297impl<'a, T> From<Vec<T>> for Expression<'a>
298where
299    T: Into<Expression<'a>>,
300{
301    fn from(v: Vec<T>) -> Self {
302        let row: Row<'a> = v.into();
303        row.into()
304    }
305}
306
307impl<'a> From<ExpressionKind<'a>> for Expression<'a> {
308    fn from(kind: ExpressionKind<'a>) -> Self {
309        Self { kind, alias: None }
310    }
311}
312
313impl<'a> Aliasable<'a> for Expression<'a> {
314    type Target = Expression<'a>;
315
316    fn alias<T>(mut self, alias: T) -> Self::Target
317    where
318        T: Into<Cow<'a, str>>,
319    {
320        self.alias = Some(alias.into());
321        self
322    }
323}
324
325impl<'a> Comparable<'a> for Expression<'a> {
326    fn equals<T>(self, comparison: T) -> Compare<'a>
327    where
328        T: Into<Expression<'a>>,
329    {
330        Compare::Equals(Box::new(self), Box::new(comparison.into()))
331    }
332
333    fn not_equals<T>(self, comparison: T) -> Compare<'a>
334    where
335        T: Into<Expression<'a>>,
336    {
337        Compare::NotEquals(Box::new(self), Box::new(comparison.into()))
338    }
339
340    fn less_than<T>(self, comparison: T) -> Compare<'a>
341    where
342        T: Into<Expression<'a>>,
343    {
344        Compare::LessThan(Box::new(self), Box::new(comparison.into()))
345    }
346
347    fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
348    where
349        T: Into<Expression<'a>>,
350    {
351        Compare::LessThanOrEquals(Box::new(self), Box::new(comparison.into()))
352    }
353
354    fn greater_than<T>(self, comparison: T) -> Compare<'a>
355    where
356        T: Into<Expression<'a>>,
357    {
358        Compare::GreaterThan(Box::new(self), Box::new(comparison.into()))
359    }
360
361    fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
362    where
363        T: Into<Expression<'a>>,
364    {
365        Compare::GreaterThanOrEquals(Box::new(self), Box::new(comparison.into()))
366    }
367
368    fn in_selection<T>(self, selection: T) -> Compare<'a>
369    where
370        T: Into<Expression<'a>>,
371    {
372        Compare::In(Box::new(self), Box::new(selection.into()))
373    }
374
375    fn not_in_selection<T>(self, selection: T) -> Compare<'a>
376    where
377        T: Into<Expression<'a>>,
378    {
379        Compare::NotIn(Box::new(self), Box::new(selection.into()))
380    }
381
382    fn like<T>(self, pattern: T) -> Compare<'a>
383    where
384        T: Into<Expression<'a>>,
385    {
386        Compare::Like(Box::new(self), Box::new(pattern.into()))
387    }
388
389    fn not_like<T>(self, pattern: T) -> Compare<'a>
390    where
391        T: Into<Expression<'a>>,
392    {
393        Compare::NotLike(Box::new(self), Box::new(pattern.into()))
394    }
395
396    #[allow(clippy::wrong_self_convention)]
397    fn is_null(self) -> Compare<'a> {
398        Compare::Null(Box::new(self))
399    }
400
401    #[allow(clippy::wrong_self_convention)]
402    fn is_not_null(self) -> Compare<'a> {
403        Compare::NotNull(Box::new(self))
404    }
405
406    fn between<T, V>(self, left: T, right: V) -> Compare<'a>
407    where
408        T: Into<Expression<'a>>,
409        V: Into<Expression<'a>>,
410    {
411        Compare::Between(Box::new(self), Box::new(left.into()), Box::new(right.into()))
412    }
413
414    fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
415    where
416        T: Into<Expression<'a>>,
417        V: Into<Expression<'a>>,
418    {
419        Compare::NotBetween(Box::new(self), Box::new(left.into()), Box::new(right.into()))
420    }
421
422    fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
423    where
424        T: Into<Cow<'a, str>>,
425        V: Into<Expression<'a>>,
426    {
427        Compare::Raw(Box::new(self), raw_comparator.into(), Box::new(right.into()))
428    }
429
430    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
431    fn json_array_contains<T>(self, item: T) -> Compare<'a>
432    where
433        T: Into<Expression<'a>>,
434    {
435        Compare::JsonCompare(JsonCompare::ArrayContains(Box::new(self), Box::new(item.into())))
436    }
437
438    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
439    fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
440    where
441        T: Into<Expression<'a>>,
442    {
443        Compare::JsonCompare(JsonCompare::ArrayNotContains(Box::new(self), Box::new(item.into())))
444    }
445
446    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
447    fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
448    where
449        T: Into<Expression<'a>>,
450    {
451        let array_starts_with: Expression = json_extract_first_array_elem(self).into();
452
453        Compare::Equals(Box::new(array_starts_with), Box::new(item.into()))
454    }
455
456    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
457    fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
458    where
459        T: Into<Expression<'a>>,
460    {
461        let array_starts_with: Expression = json_extract_first_array_elem(self).into();
462
463        Compare::NotEquals(Box::new(array_starts_with), Box::new(item.into()))
464    }
465
466    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
467    fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
468    where
469        T: Into<Expression<'a>>,
470    {
471        let array_ends_into: Expression = json_extract_last_array_elem(self).into();
472
473        Compare::Equals(Box::new(array_ends_into), Box::new(item.into()))
474    }
475
476    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
477    fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
478    where
479        T: Into<Expression<'a>>,
480    {
481        let array_ends_into: Expression = json_extract_last_array_elem(self).into();
482
483        Compare::NotEquals(Box::new(array_ends_into), Box::new(item.into()))
484    }
485
486    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
487    fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
488    where
489        T: Into<JsonType<'a>>,
490    {
491        Compare::JsonCompare(JsonCompare::TypeEquals(Box::new(self), json_type.into()))
492    }
493
494    #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
495    fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
496    where
497        T: Into<JsonType<'a>>,
498    {
499        Compare::JsonCompare(JsonCompare::TypeNotEquals(Box::new(self), json_type.into()))
500    }
501
502    #[cfg(feature = "postgresql")]
503    fn matches<T>(self, query: T) -> Compare<'a>
504    where
505        T: Into<Cow<'a, str>>,
506    {
507        Compare::Matches(Box::new(self), query.into())
508    }
509
510    #[cfg(feature = "postgresql")]
511    fn not_matches<T>(self, query: T) -> Compare<'a>
512    where
513        T: Into<Cow<'a, str>>,
514    {
515        Compare::NotMatches(Box::new(self), query.into())
516    }
517
518    #[cfg(feature = "postgresql")]
519    fn any(self) -> Compare<'a> {
520        Compare::Any(Box::new(self))
521    }
522
523    #[cfg(feature = "postgresql")]
524    fn all(self) -> Compare<'a> {
525        Compare::All(Box::new(self))
526    }
527}