sqlx_models_parser/ast/
query.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, vec::Vec};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19use crate::ast::*;
20
21/// The most complete variant of a `SELECT` query expression, optionally
22/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Query {
26    /// WITH (common table expressions, or CTEs)
27    pub with: Option<With>,
28    /// SELECT or UNION / EXCEPT / INTERSECT
29    pub body: SetExpr,
30    /// ORDER BY
31    pub order_by: Vec<OrderByExpr>,
32    /// `LIMIT { <N> | ALL }`
33    pub limit: Option<Expr>,
34    /// `OFFSET <N> [ { ROW | ROWS } ]`
35    pub offset: Option<Offset>,
36    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
37    pub fetch: Option<Fetch>,
38}
39
40impl fmt::Display for Query {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        if let Some(ref with) = self.with {
43            write!(f, "{} ", with)?;
44        }
45        write!(f, "{}", self.body)?;
46        if !self.order_by.is_empty() {
47            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
48        }
49        if let Some(ref limit) = self.limit {
50            write!(f, " LIMIT {}", limit)?;
51        }
52        if let Some(ref offset) = self.offset {
53            write!(f, " {}", offset)?;
54        }
55        if let Some(ref fetch) = self.fetch {
56            write!(f, " {}", fetch)?;
57        }
58        Ok(())
59    }
60}
61
62/// A node in a tree, representing a "query body" expression, roughly:
63/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
64#[allow(clippy::large_enum_variant)]
65#[derive(Debug, Clone, PartialEq, Eq, Hash)]
66#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
67pub enum SetExpr {
68    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
69    Select(Box<Select>),
70    /// Parenthesized SELECT subquery, which may include more set operations
71    /// in its body and an optional ORDER BY / LIMIT.
72    Query(Box<Query>),
73    /// UNION/EXCEPT/INTERSECT of two queries
74    SetOperation {
75        op: SetOperator,
76        all: bool,
77        left: Box<SetExpr>,
78        right: Box<SetExpr>,
79    },
80    Values(Values),
81    Insert(Statement),
82    // TODO: ANSI SQL supports `TABLE` here.
83}
84
85impl fmt::Display for SetExpr {
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        match self {
88            SetExpr::Select(s) => write!(f, "{}", s),
89            SetExpr::Query(q) => write!(f, "({})", q),
90            SetExpr::Values(v) => write!(f, "{}", v),
91            SetExpr::Insert(v) => write!(f, "{}", v),
92            SetExpr::SetOperation {
93                left,
94                right,
95                op,
96                all,
97            } => {
98                let all_str = if *all { " ALL" } else { "" };
99                write!(f, "{} {}{} {}", left, op, all_str, right)
100            }
101        }
102    }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
107pub enum SetOperator {
108    Union,
109    Except,
110    Intersect,
111}
112
113impl fmt::Display for SetOperator {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        f.write_str(match self {
116            SetOperator::Union => "UNION",
117            SetOperator::Except => "EXCEPT",
118            SetOperator::Intersect => "INTERSECT",
119        })
120    }
121}
122
123/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
124/// appear either as the only body item of an `SQLQuery`, or as an operand
125/// to a set operation like `UNION`.
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub struct Select {
129    pub distinct: bool,
130    /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
131    pub top: Option<Top>,
132    /// projection expressions
133    pub projection: Vec<SelectItem>,
134    /// FROM
135    pub from: Vec<TableWithJoins>,
136    /// LATERAL VIEWs
137    pub lateral_views: Vec<LateralView>,
138    /// WHERE
139    pub selection: Option<Expr>,
140    /// GROUP BY
141    pub group_by: Vec<Expr>,
142    /// CLUSTER BY (Hive)
143    pub cluster_by: Vec<Expr>,
144    /// DISTRIBUTE BY (Hive)
145    pub distribute_by: Vec<Expr>,
146    /// SORT BY (Hive)
147    pub sort_by: Vec<Expr>,
148    /// HAVING
149    pub having: Option<Expr>,
150}
151
152impl fmt::Display for Select {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        write!(f, "SELECT{}", if self.distinct { " DISTINCT" } else { "" })?;
155        if let Some(ref top) = self.top {
156            write!(f, " {}", top)?;
157        }
158        write!(f, " {}", display_comma_separated(&self.projection))?;
159        if !self.from.is_empty() {
160            write!(f, " FROM {}", display_comma_separated(&self.from))?;
161        }
162        if !self.lateral_views.is_empty() {
163            for lv in &self.lateral_views {
164                write!(f, "{}", lv)?;
165            }
166        }
167        if let Some(ref selection) = self.selection {
168            write!(f, " WHERE {}", selection)?;
169        }
170        if !self.group_by.is_empty() {
171            write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
172        }
173        if !self.cluster_by.is_empty() {
174            write!(
175                f,
176                " CLUSTER BY {}",
177                display_comma_separated(&self.cluster_by)
178            )?;
179        }
180        if !self.distribute_by.is_empty() {
181            write!(
182                f,
183                " DISTRIBUTE BY {}",
184                display_comma_separated(&self.distribute_by)
185            )?;
186        }
187        if !self.sort_by.is_empty() {
188            write!(f, " SORT BY {}", display_comma_separated(&self.sort_by))?;
189        }
190        if let Some(ref having) = self.having {
191            write!(f, " HAVING {}", having)?;
192        }
193        Ok(())
194    }
195}
196
197/// A hive LATERAL VIEW with potential column aliases
198#[derive(Debug, Clone, PartialEq, Eq, Hash)]
199#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
200pub struct LateralView {
201    /// LATERAL VIEW
202    pub lateral_view: Expr,
203    /// LATERAL VIEW table name
204    pub lateral_view_name: ObjectName,
205    /// LATERAL VIEW optional column aliases
206    pub lateral_col_alias: Vec<Ident>,
207    /// LATERAL VIEW OUTER
208    pub outer: bool,
209}
210
211impl fmt::Display for LateralView {
212    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213        write!(
214            f,
215            " LATERAL VIEW{outer} {} {}",
216            self.lateral_view,
217            self.lateral_view_name,
218            outer = if self.outer { " OUTER" } else { "" }
219        )?;
220        if !self.lateral_col_alias.is_empty() {
221            write!(
222                f,
223                " AS {}",
224                display_comma_separated(&self.lateral_col_alias)
225            )?;
226        }
227        Ok(())
228    }
229}
230
231#[derive(Debug, Clone, PartialEq, Eq, Hash)]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233pub struct With {
234    pub recursive: bool,
235    pub cte_tables: Vec<Cte>,
236}
237
238impl fmt::Display for With {
239    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240        write!(
241            f,
242            "WITH {}{}",
243            if self.recursive { "RECURSIVE " } else { "" },
244            display_comma_separated(&self.cte_tables)
245        )
246    }
247}
248
249/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
250/// The names in the column list before `AS`, when specified, replace the names
251/// of the columns returned by the query. The parser does not validate that the
252/// number of columns in the query matches the number of columns in the query.
253#[derive(Debug, Clone, PartialEq, Eq, Hash)]
254#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
255pub struct Cte {
256    pub alias: TableAlias,
257    pub query: Query,
258    pub from: Option<Ident>,
259}
260
261impl fmt::Display for Cte {
262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263        write!(f, "{} AS ({})", self.alias, self.query)?;
264        if let Some(ref fr) = self.from {
265            write!(f, " FROM {}", fr)?;
266        }
267        Ok(())
268    }
269}
270
271/// One item of the comma-separated list following `SELECT`
272#[derive(Debug, Clone, PartialEq, Eq, Hash)]
273#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
274pub enum SelectItem {
275    /// Any expression, not followed by `[ AS ] alias`
276    UnnamedExpr(Expr),
277    /// An expression, followed by `[ AS ] alias`
278    ExprWithAlias { expr: Expr, alias: Ident },
279    /// `alias.*` or even `schema.table.*`
280    QualifiedWildcard(ObjectName),
281    /// An unqualified `*`
282    Wildcard,
283}
284
285impl fmt::Display for SelectItem {
286    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287        match &self {
288            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
289            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
290            SelectItem::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
291            SelectItem::Wildcard => write!(f, "*"),
292        }
293    }
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Hash)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298pub struct TableWithJoins {
299    pub relation: TableFactor,
300    pub joins: Vec<Join>,
301}
302
303impl fmt::Display for TableWithJoins {
304    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305        write!(f, "{}", self.relation)?;
306        for join in &self.joins {
307            write!(f, "{}", join)?;
308        }
309        Ok(())
310    }
311}
312
313/// A table name or a parenthesized subquery with an optional alias
314#[derive(Debug, Clone, PartialEq, Eq, Hash)]
315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
316pub enum TableFactor {
317    Table {
318        name: ObjectName,
319        alias: Option<TableAlias>,
320        /// Arguments of a table-valued function, as supported by Postgres
321        /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
322        /// will also be parsed as `args`.
323        args: Vec<FunctionArg>,
324        /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
325        with_hints: Vec<Expr>,
326    },
327    Derived {
328        lateral: bool,
329        subquery: Box<Query>,
330        alias: Option<TableAlias>,
331    },
332    /// `TABLE(<expr>)[ AS <alias> ]`
333    TableFunction {
334        expr: Expr,
335        alias: Option<TableAlias>,
336    },
337    /// Represents a parenthesized table factor. The SQL spec only allows a
338    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
339    /// possibly several times.
340    ///
341    /// The parser may also accept non-standard nesting of bare tables for some
342    /// dialects, but the information about such nesting is stripped from AST.
343    NestedJoin(Box<TableWithJoins>),
344}
345
346impl fmt::Display for TableFactor {
347    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348        match self {
349            TableFactor::Table {
350                name,
351                alias,
352                args,
353                with_hints,
354            } => {
355                write!(f, "{}", name)?;
356                if !args.is_empty() {
357                    write!(f, "({})", display_comma_separated(args))?;
358                }
359                if let Some(alias) = alias {
360                    write!(f, " AS {}", alias)?;
361                }
362                if !with_hints.is_empty() {
363                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
364                }
365                Ok(())
366            }
367            TableFactor::Derived {
368                lateral,
369                subquery,
370                alias,
371            } => {
372                if *lateral {
373                    write!(f, "LATERAL ")?;
374                }
375                write!(f, "({})", subquery)?;
376                if let Some(alias) = alias {
377                    write!(f, " AS {}", alias)?;
378                }
379                Ok(())
380            }
381            TableFactor::TableFunction { expr, alias } => {
382                write!(f, "TABLE({})", expr)?;
383                if let Some(alias) = alias {
384                    write!(f, " AS {}", alias)?;
385                }
386                Ok(())
387            }
388            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
389        }
390    }
391}
392
393#[derive(Debug, Clone, PartialEq, Eq, Hash)]
394#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
395pub struct TableAlias {
396    pub name: Ident,
397    pub columns: Vec<Ident>,
398}
399
400impl fmt::Display for TableAlias {
401    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402        write!(f, "{}", self.name)?;
403        if !self.columns.is_empty() {
404            write!(f, " ({})", display_comma_separated(&self.columns))?;
405        }
406        Ok(())
407    }
408}
409
410#[derive(Debug, Clone, PartialEq, Eq, Hash)]
411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412pub struct Join {
413    pub relation: TableFactor,
414    pub join_operator: JoinOperator,
415}
416
417impl fmt::Display for Join {
418    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
419        fn prefix(constraint: &JoinConstraint) -> &'static str {
420            match constraint {
421                JoinConstraint::Natural => "NATURAL ",
422                _ => "",
423            }
424        }
425        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
426            struct Suffix<'a>(&'a JoinConstraint);
427            impl<'a> fmt::Display for Suffix<'a> {
428                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
429                    match self.0 {
430                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
431                        JoinConstraint::Using(attrs) => {
432                            write!(f, " USING({})", display_comma_separated(attrs))
433                        }
434                        _ => Ok(()),
435                    }
436                }
437            }
438            Suffix(constraint)
439        }
440        match &self.join_operator {
441            JoinOperator::Inner(constraint) => write!(
442                f,
443                " {}JOIN {}{}",
444                prefix(constraint),
445                self.relation,
446                suffix(constraint)
447            ),
448            JoinOperator::LeftOuter(constraint) => write!(
449                f,
450                " {}LEFT JOIN {}{}",
451                prefix(constraint),
452                self.relation,
453                suffix(constraint)
454            ),
455            JoinOperator::RightOuter(constraint) => write!(
456                f,
457                " {}RIGHT JOIN {}{}",
458                prefix(constraint),
459                self.relation,
460                suffix(constraint)
461            ),
462            JoinOperator::FullOuter(constraint) => write!(
463                f,
464                " {}FULL JOIN {}{}",
465                prefix(constraint),
466                self.relation,
467                suffix(constraint)
468            ),
469            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
470            JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
471            JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
472        }
473    }
474}
475
476#[derive(Debug, Clone, PartialEq, Eq, Hash)]
477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
478pub enum JoinOperator {
479    Inner(JoinConstraint),
480    LeftOuter(JoinConstraint),
481    RightOuter(JoinConstraint),
482    FullOuter(JoinConstraint),
483    CrossJoin,
484    /// CROSS APPLY (non-standard)
485    CrossApply,
486    /// OUTER APPLY (non-standard)
487    OuterApply,
488}
489
490#[derive(Debug, Clone, PartialEq, Eq, Hash)]
491#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
492pub enum JoinConstraint {
493    On(Expr),
494    Using(Vec<Ident>),
495    Natural,
496    None,
497}
498
499/// An `ORDER BY` expression
500#[derive(Debug, Clone, PartialEq, Eq, Hash)]
501#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
502pub struct OrderByExpr {
503    pub expr: Expr,
504    /// Optional `ASC` or `DESC`
505    pub asc: Option<bool>,
506    /// Optional `NULLS FIRST` or `NULLS LAST`
507    pub nulls_first: Option<bool>,
508}
509
510impl fmt::Display for OrderByExpr {
511    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512        write!(f, "{}", self.expr)?;
513        match self.asc {
514            Some(true) => write!(f, " ASC")?,
515            Some(false) => write!(f, " DESC")?,
516            None => (),
517        }
518        match self.nulls_first {
519            Some(true) => write!(f, " NULLS FIRST")?,
520            Some(false) => write!(f, " NULLS LAST")?,
521            None => (),
522        }
523        Ok(())
524    }
525}
526
527#[derive(Debug, Clone, PartialEq, Eq, Hash)]
528#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
529pub struct Offset {
530    pub value: Expr,
531    pub rows: OffsetRows,
532}
533
534impl fmt::Display for Offset {
535    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536        write!(f, "OFFSET {}{}", self.value, self.rows)
537    }
538}
539
540/// Stores the keyword after `OFFSET <number>`
541#[derive(Debug, Clone, PartialEq, Eq, Hash)]
542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
543pub enum OffsetRows {
544    /// Omitting ROW/ROWS is non-standard MySQL quirk.
545    None,
546    Row,
547    Rows,
548}
549
550impl fmt::Display for OffsetRows {
551    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
552        match self {
553            OffsetRows::None => Ok(()),
554            OffsetRows::Row => write!(f, " ROW"),
555            OffsetRows::Rows => write!(f, " ROWS"),
556        }
557    }
558}
559
560#[derive(Debug, Clone, PartialEq, Eq, Hash)]
561#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
562pub struct Fetch {
563    pub with_ties: bool,
564    pub percent: bool,
565    pub quantity: Option<Expr>,
566}
567
568impl fmt::Display for Fetch {
569    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
571        if let Some(ref quantity) = self.quantity {
572            let percent = if self.percent { " PERCENT" } else { "" };
573            write!(f, "FETCH FIRST {}{} ROWS {}", quantity, percent, extension)
574        } else {
575            write!(f, "FETCH FIRST ROWS {}", extension)
576        }
577    }
578}
579
580#[derive(Debug, Clone, PartialEq, Eq, Hash)]
581#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
582pub struct Top {
583    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
584    pub with_ties: bool,
585    pub percent: bool,
586    pub quantity: Option<Expr>,
587}
588
589impl fmt::Display for Top {
590    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591        let extension = if self.with_ties { " WITH TIES" } else { "" };
592        if let Some(ref quantity) = self.quantity {
593            let percent = if self.percent { " PERCENT" } else { "" };
594            write!(f, "TOP ({}){}{}", quantity, percent, extension)
595        } else {
596            write!(f, "TOP{}", extension)
597        }
598    }
599}
600
601#[derive(Debug, Clone, PartialEq, Eq, Hash)]
602#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
603pub struct Values(pub Vec<Vec<Expr>>);
604
605impl fmt::Display for Values {
606    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
607        write!(f, "VALUES ")?;
608        let mut delim = "";
609        for row in &self.0 {
610            write!(f, "{}", delim)?;
611            delim = ", ";
612            write!(f, "({})", display_comma_separated(row))?;
613        }
614        Ok(())
615    }
616}