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        span: Span,
216    },
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
220pub enum JoinType {
221    Inner,
222    Left,
223    Right,
224    Full,
225    Cross,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct OrderByExpr {
230    pub expr: Expr,
231    pub asc: Option<bool>,
232    pub nulls_first: Option<bool>,
233    pub span: Span,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct Insert {
238    pub table: String,
239    pub columns: Option<Vec<String>>,
240    pub source: InsertSource,
241    pub span: Span,
242}
243
244/// The row source for an INSERT statement.
245#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(tag = "variant")]
247pub enum InsertSource {
248    Values { values: Vec<Vec<Expr>> },
249    Select { select: Box<Select> },
250    Query { query: Box<QueryBody> },
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct Update {
255    pub table: String,
256    pub assignments: Vec<Assignment>,
257    pub selection: Option<Expr>,
258    pub span: Span,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct Assignment {
263    pub column: String,
264    pub value: Expr,
265    pub span: Span,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct Delete {
270    pub table: String,
271    pub selection: Option<Expr>,
272    pub span: Span,
273}
274
275impl Spanned for Select {
276    fn span(&self) -> Span {
277        self.span
278    }
279}
280
281impl Spanned for Values {
282    fn span(&self) -> Span {
283        self.span
284    }
285}
286
287impl Spanned for QueryBody {
288    fn span(&self) -> Span {
289        match self {
290            QueryBody::Select(select) => select.span,
291            QueryBody::Values(values) => values.span,
292        }
293    }
294}
295
296impl Spanned for SetOperation {
297    fn span(&self) -> Span {
298        self.span
299    }
300}
301
302impl Spanned for SelectItem {
303    fn span(&self) -> Span {
304        match self {
305            SelectItem::Wildcard { span } | SelectItem::QualifiedWildcard { span, .. } => *span,
306            SelectItem::Expr { span, .. } => *span,
307        }
308    }
309}
310
311impl Spanned for FromItem {
312    fn span(&self) -> Span {
313        match self {
314            FromItem::Table { span, .. }
315            | FromItem::Join { span, .. }
316            | FromItem::Derived { span, .. }
317            | FromItem::Function { span, .. } => *span,
318        }
319    }
320}
321
322impl Spanned for OrderByExpr {
323    fn span(&self) -> Span {
324        self.span
325    }
326}
327
328impl Spanned for Insert {
329    fn span(&self) -> Span {
330        self.span
331    }
332}
333
334impl Spanned for Update {
335    fn span(&self) -> Span {
336        self.span
337    }
338}
339
340impl Spanned for Assignment {
341    fn span(&self) -> Span {
342        self.span
343    }
344}
345
346impl Spanned for Delete {
347    fn span(&self) -> Span {
348        self.span
349    }
350}