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