Skip to main content

alopex_sql/ast/
dml.rs

1use super::expr::Expr;
2use super::span::{Span, Spanned};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Select {
7    #[serde(default)]
8    pub with: Option<WithClause>,
9    pub distinct: bool,
10    /// SELECT DISTINCT ON (expr, ...) key expressions in source order.
11    /// Empty when the clause is absent (issue #150, contract 0.11.0).
12    /// Mutually exclusive with `distinct` by grammar.
13    #[serde(default)]
14    pub distinct_on: Vec<Expr>,
15    pub projection: Vec<SelectItem>,
16    pub from: Vec<FromItem>,
17    pub selection: Option<Expr>,
18    pub group_by: Option<Vec<GroupByItem>>,
19    pub having: Option<Expr>,
20    #[serde(default)]
21    pub windows: Vec<NamedWindow>,
22    #[serde(default)]
23    pub qualify: Option<Expr>,
24    #[serde(default)]
25    pub set_operations: Vec<SetOperation>,
26    pub order_by: Vec<OrderByExpr>,
27    pub limit: Option<Expr>,
28    pub offset: Option<Expr>,
29    /// FETCH ... WITH TIES: the limit keeps every peer of the final row
30    /// under the ORDER BY sort key (issue #152, contract 0.10.0).
31    #[serde(default)]
32    pub limit_with_ties: bool,
33    #[serde(default)]
34    pub span: Span,
35}
36
37/// One item of a GROUP BY list (issue #149, contract 0.13.0).
38///
39/// `GROUP BY a, ROLLUP(b, c)` is `[Expr(a), Rollup([b, c])]`; the planner
40/// expands the items into grouping sets by cross product (D2). `GROUP BY ()`
41/// arrives as one `GroupingSets` item holding a single empty set.
42#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(tag = "variant")]
44#[allow(clippy::large_enum_variant)]
45pub enum GroupByItem {
46    Expr { expr: Expr },
47    Rollup { exprs: Vec<Expr> },
48    Cube { exprs: Vec<Expr> },
49    GroupingSets { sets: Vec<Vec<Expr>> },
50}
51
52impl GroupByItem {
53    /// Iterate every expression contained in this item, in source order.
54    pub fn exprs(&self) -> Box<dyn Iterator<Item = &Expr> + '_> {
55        match self {
56            GroupByItem::Expr { expr } => Box::new(std::iter::once(expr)),
57            GroupByItem::Rollup { exprs } | GroupByItem::Cube { exprs } => Box::new(exprs.iter()),
58            GroupByItem::GroupingSets { sets } => Box::new(sets.iter().flatten()),
59        }
60    }
61
62    /// Mutably iterate every expression contained in this item.
63    ///
64    /// Span normalization, natural-join annotation, and named-window
65    /// resolution all walk this iterator so that expressions inside
66    /// ROLLUP/CUBE/GROUPING SETS receive the same treatment as plain keys.
67    pub fn exprs_mut(&mut self) -> Box<dyn Iterator<Item = &mut Expr> + '_> {
68        match self {
69            GroupByItem::Expr { expr } => Box::new(std::iter::once(expr)),
70            GroupByItem::Rollup { exprs } | GroupByItem::Cube { exprs } => {
71                Box::new(exprs.iter_mut())
72            }
73            GroupByItem::GroupingSets { sets } => Box::new(sets.iter_mut().flatten()),
74        }
75    }
76}
77
78/// A VALUES query body with the same set/order/limit tail as SELECT.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct Values {
81    #[serde(default)]
82    pub with: Option<WithClause>,
83    pub rows: Vec<Vec<Expr>>,
84    #[serde(default)]
85    pub set_operations: Vec<SetOperation>,
86    #[serde(default)]
87    pub order_by: Vec<OrderByExpr>,
88    #[serde(default)]
89    pub limit: Option<Expr>,
90    #[serde(default)]
91    pub offset: Option<Expr>,
92    /// FETCH ... WITH TIES on a VALUES tail (issue #152, contract 0.10.0).
93    #[serde(default)]
94    pub limit_with_ties: bool,
95    #[serde(default)]
96    pub span: Span,
97}
98
99/// A relational query body accepted by nested query positions.
100#[derive(Debug, Clone, Serialize, Deserialize)]
101#[serde(tag = "variant")]
102#[allow(clippy::large_enum_variant)]
103pub enum QueryBody {
104    Select(Select),
105    Values(Values),
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct NamedWindow {
110    pub name: String,
111    pub spec: super::expr::WindowSpec,
112    #[serde(default)]
113    pub span: Span,
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
117pub enum SetOperator {
118    Union,
119    Intersect,
120    Except,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct SetOperation {
125    pub operator: SetOperator,
126    pub all: bool,
127    pub right: Box<QueryBody>,
128    #[serde(default)]
129    pub span: Span,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct WithClause {
134    pub recursive: bool,
135    pub ctes: Vec<CommonTableExpr>,
136    pub span: Span,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct CommonTableExpr {
141    pub name: String,
142    #[serde(default)]
143    pub columns: Vec<String>,
144    pub query: Box<QueryBody>,
145    pub span: Span,
146}
147
148pub const LITERAL_TABLE: &str = "__literal__";
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
151#[serde(tag = "variant")]
152// `Expr` grew with the issue #148 aggregate clauses; almost every SelectItem
153// is the Expr variant, so boxing it would add a pointless allocation to the
154// hot projection path.
155#[allow(clippy::large_enum_variant)]
156pub enum SelectItem {
157    Wildcard {
158        span: Span,
159    },
160    QualifiedWildcard {
161        table: String,
162        span: Span,
163    },
164    Expr {
165        expr: Expr,
166        alias: Option<String>,
167        span: Span,
168    },
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(tag = "variant")]
173#[allow(clippy::large_enum_variant)]
174pub enum FromItem {
175    Table {
176        name: String,
177        alias: Option<String>,
178        /// Relation alias column-name list (`AS t(c1, c2)`), contract 0.14.0.
179        #[serde(default)]
180        columns: Vec<String>,
181        span: Span,
182    },
183    Join {
184        left: Box<FromItem>,
185        right: Box<FromItem>,
186        join_type: JoinType,
187        condition: Option<Expr>,
188        using: Option<Vec<String>>,
189        #[serde(default)]
190        natural: bool,
191        span: Span,
192    },
193    Derived {
194        subquery: Box<QueryBody>,
195        alias: Option<String>,
196        #[serde(default)]
197        columns: Vec<String>,
198        /// `LATERAL (subquery)`: the enclosing FROM items are in scope
199        /// (issue #151, contract 0.14.0).
200        #[serde(default)]
201        lateral: bool,
202        span: Span,
203    },
204    /// FROM-clause table function such as `UNNEST(v)` (issue #151).
205    Function {
206        name: String,
207        args: Vec<Expr>,
208        alias: Option<String>,
209        #[serde(default)]
210        columns: Vec<String>,
211        /// Explicit `LATERAL` keyword. Table-function arguments see the
212        /// preceding FROM items either way (implicit LATERAL).
213        #[serde(default)]
214        lateral: bool,
215        #[serde(default)]
216        with_ordinality: bool,
217        span: Span,
218    },
219}
220
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
222pub enum JoinType {
223    Inner,
224    Left,
225    Right,
226    Full,
227    Cross,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct OrderByExpr {
232    pub expr: Expr,
233    pub asc: Option<bool>,
234    pub nulls_first: Option<bool>,
235    pub span: Span,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct Insert {
240    pub table: String,
241    pub columns: Option<Vec<String>>,
242    pub source: InsertSource,
243    pub span: Span,
244}
245
246/// The row source for an INSERT statement.
247#[derive(Debug, Clone, Serialize, Deserialize)]
248#[serde(tag = "variant")]
249pub enum InsertSource {
250    Values { values: Vec<Vec<Expr>> },
251    Select { select: Box<Select> },
252    Query { query: Box<QueryBody> },
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct Update {
257    pub table: String,
258    pub assignments: Vec<Assignment>,
259    pub selection: Option<Expr>,
260    pub span: Span,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct Assignment {
265    pub column: String,
266    pub value: Expr,
267    pub span: Span,
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct Delete {
272    pub table: String,
273    pub selection: Option<Expr>,
274    pub span: Span,
275}
276
277impl Spanned for Select {
278    fn span(&self) -> Span {
279        self.span
280    }
281}
282
283impl Spanned for Values {
284    fn span(&self) -> Span {
285        self.span
286    }
287}
288
289impl Spanned for QueryBody {
290    fn span(&self) -> Span {
291        match self {
292            QueryBody::Select(select) => select.span,
293            QueryBody::Values(values) => values.span,
294        }
295    }
296}
297
298impl Spanned for SetOperation {
299    fn span(&self) -> Span {
300        self.span
301    }
302}
303
304impl Spanned for SelectItem {
305    fn span(&self) -> Span {
306        match self {
307            SelectItem::Wildcard { span } | SelectItem::QualifiedWildcard { span, .. } => *span,
308            SelectItem::Expr { span, .. } => *span,
309        }
310    }
311}
312
313impl Spanned for FromItem {
314    fn span(&self) -> Span {
315        match self {
316            FromItem::Table { span, .. }
317            | FromItem::Join { span, .. }
318            | FromItem::Derived { span, .. }
319            | FromItem::Function { span, .. } => *span,
320        }
321    }
322}
323
324impl Spanned for OrderByExpr {
325    fn span(&self) -> Span {
326        self.span
327    }
328}
329
330impl Spanned for Insert {
331    fn span(&self) -> Span {
332        self.span
333    }
334}
335
336impl Spanned for Update {
337    fn span(&self) -> Span {
338        self.span
339    }
340}
341
342impl Spanned for Assignment {
343    fn span(&self) -> Span {
344        self.span
345    }
346}
347
348impl Spanned for Delete {
349    fn span(&self) -> Span {
350        self.span
351    }
352}