sqlx_models_parser/ast/
mod.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//! SQL Abstract Syntax Tree (AST) types
14
15mod data_type;
16mod ddl;
17mod expression;
18mod operator;
19mod query;
20mod statement;
21mod value;
22pub use expression::*;
23pub use statement::*;
24pub use ddl::*;
25#[cfg(not(feature = "std"))]
26use alloc::{
27    boxed::Box,
28    string::{String, ToString},
29    vec::Vec,
30};
31use core::fmt;
32
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35
36pub use self::data_type::DataType;
37pub use self::ddl::{
38    AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef, ReferentialAction,
39    TableConstraint,
40};
41pub use self::operator::{BinaryOperator, UnaryOperator};
42pub use self::query::{
43    Cte, Fetch, Join, JoinConstraint, JoinOperator, LateralView, Offset, OffsetRows, OrderByExpr,
44    Query, Select, SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top,
45    Values, With,
46};
47pub use self::value::{DateTimeField, TrimWhereField, Value};
48
49struct DisplaySeparated<'a, T>
50where
51    T: fmt::Display,
52{
53    slice: &'a [T],
54    sep: &'static str,
55}
56
57impl<'a, T> fmt::Display for DisplaySeparated<'a, T>
58where
59    T: fmt::Display,
60{
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        let mut delim = "";
63        for t in self.slice {
64            write!(f, "{}", delim)?;
65            delim = self.sep;
66            write!(f, "{}", t)?;
67        }
68        Ok(())
69    }
70}
71
72fn display_separated<'a, T>(slice: &'a [T], sep: &'static str) -> DisplaySeparated<'a, T>
73where
74    T: fmt::Display,
75{
76    DisplaySeparated { slice, sep }
77}
78
79fn display_comma_separated<T>(slice: &[T]) -> DisplaySeparated<'_, T>
80where
81    T: fmt::Display,
82{
83    DisplaySeparated { slice, sep: ", " }
84}
85
86/// An identifier, decomposed into its value or character data and the quote style.
87#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89pub struct Ident {
90    /// The value of the identifier without quotes.
91    pub value: String,
92    /// The starting quote if any. Valid quote characters are the single quote,
93    /// double quote, backtick, and opening square bracket.
94    pub quote_style: Option<char>,
95}
96
97impl Ident {
98    /// Create a new identifier with the given value and no quotes.
99    pub fn new<S>(value: S) -> Self
100    where
101        S: Into<String>,
102    {
103        Ident {
104            value: value.into(),
105            quote_style: None,
106        }
107    }
108
109    /// Create a new quoted identifier with the given quote and value. This function
110    /// panics if the given quote is not a valid quote character.
111    pub fn with_quote<S>(quote: char, value: S) -> Self
112    where
113        S: Into<String>,
114    {
115        assert!(quote == '\'' || quote == '"' || quote == '`' || quote == '[');
116        Ident {
117            value: value.into(),
118            quote_style: Some(quote),
119        }
120    }
121}
122
123impl From<&str> for Ident {
124    fn from(value: &str) -> Self {
125        Ident {
126            value: value.to_string(),
127            quote_style: None,
128        }
129    }
130}
131
132impl fmt::Display for Ident {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        match self.quote_style {
135            Some(q) if q == '"' || q == '\'' || q == '`' => write!(f, "{}{}{}", q, self.value, q),
136            Some(q) if q == '[' => write!(f, "[{}]", self.value),
137            None => f.write_str(&self.value),
138            _ => panic!("unexpected quote style"),
139        }
140    }
141}
142
143/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
146pub struct ObjectName(pub Vec<Ident>);
147
148impl fmt::Display for ObjectName {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        write!(f, "{}", display_separated(&self.0, "."))
151    }
152}
153
154/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
156#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
157pub struct WindowSpec {
158    pub partition_by: Vec<Expr>,
159    pub order_by: Vec<OrderByExpr>,
160    pub window_frame: Option<WindowFrame>,
161}
162
163impl fmt::Display for WindowSpec {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        let mut delim = "";
166        if !self.partition_by.is_empty() {
167            delim = " ";
168            write!(
169                f,
170                "PARTITION BY {}",
171                display_comma_separated(&self.partition_by)
172            )?;
173        }
174        if !self.order_by.is_empty() {
175            f.write_str(delim)?;
176            delim = " ";
177            write!(f, "ORDER BY {}", display_comma_separated(&self.order_by))?;
178        }
179        if let Some(window_frame) = &self.window_frame {
180            if let Some(end_bound) = &window_frame.end_bound {
181                f.write_str(delim)?;
182                write!(
183                    f,
184                    "{} BETWEEN {} AND {}",
185                    window_frame.units, window_frame.start_bound, end_bound
186                )?;
187            } else {
188                f.write_str(delim)?;
189                write!(f, "{} {}", window_frame.units, window_frame.start_bound)?;
190            }
191        }
192        Ok(())
193    }
194}
195
196/// Specifies the data processed by a window function, e.g.
197/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
198///
199/// Note: The parser does not validate the specified bounds; the caller should
200/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
201#[derive(Debug, Clone, PartialEq, Eq, Hash)]
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
203pub struct WindowFrame {
204    pub units: WindowFrameUnits,
205    pub start_bound: WindowFrameBound,
206    /// The right bound of the `BETWEEN .. AND` clause. The end bound of `None`
207    /// indicates the shorthand form (e.g. `ROWS 1 PRECEDING`), which must
208    /// behave the same as `end_bound = WindowFrameBound::CurrentRow`.
209    pub end_bound: Option<WindowFrameBound>,
210    // TBD: EXCLUDE
211}
212
213impl Default for WindowFrame {
214    /// returns default value for window frame
215    ///
216    /// see https://www.sqlite.org/windowfunctions.html#frame_specifications
217    fn default() -> Self {
218        Self {
219            units: WindowFrameUnits::Range,
220            start_bound: WindowFrameBound::Preceding(None),
221            end_bound: None,
222        }
223    }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
228pub enum WindowFrameUnits {
229    Rows,
230    Range,
231    Groups,
232}
233
234impl fmt::Display for WindowFrameUnits {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        f.write_str(match self {
237            WindowFrameUnits::Rows => "ROWS",
238            WindowFrameUnits::Range => "RANGE",
239            WindowFrameUnits::Groups => "GROUPS",
240        })
241    }
242}
243
244/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
245#[derive(Debug, Clone, PartialEq, Eq, Hash)]
246#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
247pub enum WindowFrameBound {
248    /// `CURRENT ROW`
249    CurrentRow,
250    /// `<N> PRECEDING` or `UNBOUNDED PRECEDING`
251    Preceding(Option<u64>),
252    /// `<N> FOLLOWING` or `UNBOUNDED FOLLOWING`.
253    Following(Option<u64>),
254}
255
256impl fmt::Display for WindowFrameBound {
257    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258        match self {
259            WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
260            WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
261            WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
262            WindowFrameBound::Preceding(Some(n)) => write!(f, "{} PRECEDING", n),
263            WindowFrameBound::Following(Some(n)) => write!(f, "{} FOLLOWING", n),
264        }
265    }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Hash)]
269#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
270pub enum AddDropSync {
271    ADD,
272    DROP,
273    SYNC,
274}
275
276impl fmt::Display for AddDropSync {
277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278        match self {
279            AddDropSync::SYNC => f.write_str("SYNC PARTITIONS"),
280            AddDropSync::DROP => f.write_str("DROP PARTITIONS"),
281            AddDropSync::ADD => f.write_str("ADD PARTITIONS"),
282        }
283    }
284}
285
286#[derive(Debug, Clone, PartialEq, Eq, Hash)]
287#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
288pub enum ShowCreateObject {
289    Event,
290    Function,
291    Procedure,
292    Table,
293    Trigger,
294}
295
296impl fmt::Display for ShowCreateObject {
297    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298        match self {
299            ShowCreateObject::Event => f.write_str("EVENT"),
300            ShowCreateObject::Function => f.write_str("FUNCTION"),
301            ShowCreateObject::Procedure => f.write_str("PROCEDURE"),
302            ShowCreateObject::Table => f.write_str("TABLE"),
303            ShowCreateObject::Trigger => f.write_str("TRIGGER"),
304        }
305    }
306}
307
308/// SQL assignment `foo = expr` as used in SQLUpdate
309#[derive(Debug, Clone, PartialEq, Eq, Hash)]
310#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
311pub struct Assignment {
312    pub id: Ident,
313    pub value: Expr,
314}
315
316impl fmt::Display for Assignment {
317    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318        write!(f, "{} = {}", self.id, self.value)
319    }
320}
321
322#[derive(Debug, Clone, PartialEq, Eq, Hash)]
323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
324pub enum FunctionArg {
325    Named { name: Ident, arg: Expr },
326    Unnamed(Expr),
327}
328
329impl fmt::Display for FunctionArg {
330    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331        match self {
332            FunctionArg::Named { name, arg } => write!(f, "{} => {}", name, arg),
333            FunctionArg::Unnamed(unnamed_arg) => write!(f, "{}", unnamed_arg),
334        }
335    }
336}
337
338/// A function call
339#[derive(Debug, Clone, PartialEq, Eq, Hash)]
340#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
341pub struct Function {
342    pub name: ObjectName,
343    pub args: Vec<FunctionArg>,
344    pub over: Option<WindowSpec>,
345    // aggregate functions may specify eg `COUNT(DISTINCT x)`
346    pub distinct: bool,
347}
348
349impl fmt::Display for Function {
350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351        write!(
352            f,
353            "{}({}{})",
354            self.name,
355            if self.distinct { "DISTINCT " } else { "" },
356            display_comma_separated(&self.args),
357        )?;
358        if let Some(o) = &self.over {
359            write!(f, " OVER ({})", o)?;
360        }
361        Ok(())
362    }
363}
364
365/// External table's available file format
366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
367#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
368pub enum FileFormat {
369    TEXTFILE,
370    SEQUENCEFILE,
371    ORC,
372    PARQUET,
373    AVRO,
374    RCFILE,
375    JSONFILE,
376}
377
378impl fmt::Display for FileFormat {
379    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
380        use self::FileFormat::*;
381        f.write_str(match self {
382            TEXTFILE => "TEXTFILE",
383            SEQUENCEFILE => "SEQUENCEFILE",
384            ORC => "ORC",
385            PARQUET => "PARQUET",
386            AVRO => "AVRO",
387            RCFILE => "RCFILE",
388            JSONFILE => "JSONFILE",
389        })
390    }
391}
392
393/// A `LISTAGG` invocation `LISTAGG( [ DISTINCT ] <expr>[, <separator> ] [ON OVERFLOW <on_overflow>] ) )
394/// [ WITHIN GROUP (ORDER BY <within_group1>[, ...] ) ]`
395#[derive(Debug, Clone, PartialEq, Eq, Hash)]
396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
397pub struct ListAgg {
398    pub distinct: bool,
399    pub expr: Box<Expr>,
400    pub separator: Option<Box<Expr>>,
401    pub on_overflow: Option<ListAggOnOverflow>,
402    pub within_group: Vec<OrderByExpr>,
403}
404
405impl fmt::Display for ListAgg {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        write!(
408            f,
409            "LISTAGG({}{}",
410            if self.distinct { "DISTINCT " } else { "" },
411            self.expr
412        )?;
413        if let Some(separator) = &self.separator {
414            write!(f, ", {}", separator)?;
415        }
416        if let Some(on_overflow) = &self.on_overflow {
417            write!(f, "{}", on_overflow)?;
418        }
419        write!(f, ")")?;
420        if !self.within_group.is_empty() {
421            write!(
422                f,
423                " WITHIN GROUP (ORDER BY {})",
424                display_comma_separated(&self.within_group)
425            )?;
426        }
427        Ok(())
428    }
429}
430
431/// The `ON OVERFLOW` clause of a LISTAGG invocation
432#[derive(Debug, Clone, PartialEq, Eq, Hash)]
433#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
434pub enum ListAggOnOverflow {
435    /// `ON OVERFLOW ERROR`
436    Error,
437
438    /// `ON OVERFLOW TRUNCATE [ <filler> ] WITH[OUT] COUNT`
439    Truncate {
440        filler: Option<Box<Expr>>,
441        with_count: bool,
442    },
443}
444
445impl fmt::Display for ListAggOnOverflow {
446    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
447        write!(f, " ON OVERFLOW")?;
448        match self {
449            ListAggOnOverflow::Error => write!(f, " ERROR"),
450            ListAggOnOverflow::Truncate { filler, with_count } => {
451                write!(f, " TRUNCATE")?;
452                if let Some(filler) = filler {
453                    write!(f, " {}", filler)?;
454                }
455                if *with_count {
456                    write!(f, " WITH")?;
457                } else {
458                    write!(f, " WITHOUT")?;
459                }
460                write!(f, " COUNT")
461            }
462        }
463    }
464}
465
466#[derive(Debug, Clone, PartialEq, Eq, Hash)]
467#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
468pub enum ObjectType {
469    Table,
470    View,
471    Index,
472    Schema,
473}
474
475impl fmt::Display for ObjectType {
476    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477        f.write_str(match self {
478            ObjectType::Table => "TABLE",
479            ObjectType::View => "VIEW",
480            ObjectType::Index => "INDEX",
481            ObjectType::Schema => "SCHEMA",
482        })
483    }
484}
485
486#[derive(Debug, Clone, PartialEq, Eq, Hash)]
487#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
488pub enum HiveDistributionStyle {
489    PARTITIONED {
490        columns: Vec<ColumnDef>,
491    },
492    CLUSTERED {
493        columns: Vec<Ident>,
494        sorted_by: Vec<ColumnDef>,
495        num_buckets: i32,
496    },
497    SKEWED {
498        columns: Vec<ColumnDef>,
499        on: Vec<ColumnDef>,
500        stored_as_directories: bool,
501    },
502    NONE,
503}
504
505#[derive(Debug, Clone, PartialEq, Eq, Hash)]
506#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
507pub enum HiveRowFormat {
508    SERDE { class: String },
509    DELIMITED,
510}
511
512#[derive(Debug, Clone, PartialEq, Eq, Hash)]
513#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
514pub enum HiveIOFormat {
515    IOF {
516        input_format: Expr,
517        output_format: Expr,
518    },
519    FileFormat {
520        format: FileFormat,
521    },
522}
523
524#[derive(Debug, Clone, PartialEq, Eq, Hash)]
525#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
526pub struct HiveFormat {
527    pub row_format: Option<HiveRowFormat>,
528    pub storage: Option<HiveIOFormat>,
529    pub location: Option<String>,
530}
531
532impl Default for HiveFormat {
533    fn default() -> Self {
534        HiveFormat {
535            row_format: None,
536            location: None,
537            storage: None,
538        }
539    }
540}
541
542#[derive(Debug, Clone, PartialEq, Eq, Hash)]
543#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
544pub struct SqlOption {
545    pub name: Ident,
546    pub value: Value,
547}
548
549impl fmt::Display for SqlOption {
550    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
551        write!(f, "{} = {}", self.name, self.value)
552    }
553}
554
555#[derive(Debug, Clone, PartialEq, Eq, Hash)]
556#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
557pub enum TransactionMode {
558    AccessMode(TransactionAccessMode),
559    IsolationLevel(TransactionIsolationLevel),
560}
561
562impl fmt::Display for TransactionMode {
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        use TransactionMode::*;
565        match self {
566            AccessMode(access_mode) => write!(f, "{}", access_mode),
567            IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
568        }
569    }
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Hash)]
573#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
574pub enum TransactionAccessMode {
575    ReadOnly,
576    ReadWrite,
577}
578
579impl fmt::Display for TransactionAccessMode {
580    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
581        use TransactionAccessMode::*;
582        f.write_str(match self {
583            ReadOnly => "READ ONLY",
584            ReadWrite => "READ WRITE",
585        })
586    }
587}
588
589#[derive(Debug, Clone, PartialEq, Eq, Hash)]
590#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
591pub enum TransactionIsolationLevel {
592    ReadUncommitted,
593    ReadCommitted,
594    RepeatableRead,
595    Serializable,
596}
597
598impl fmt::Display for TransactionIsolationLevel {
599    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600        use TransactionIsolationLevel::*;
601        f.write_str(match self {
602            ReadUncommitted => "READ UNCOMMITTED",
603            ReadCommitted => "READ COMMITTED",
604            RepeatableRead => "REPEATABLE READ",
605            Serializable => "SERIALIZABLE",
606        })
607    }
608}
609
610#[derive(Debug, Clone, PartialEq, Eq, Hash)]
611#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
612pub enum ShowStatementFilter {
613    Like(String),
614    ILike(String),
615    Where(Expr),
616}
617
618impl fmt::Display for ShowStatementFilter {
619    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
620        use ShowStatementFilter::*;
621        match self {
622            Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
623            ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)),
624            Where(expr) => write!(f, "WHERE {}", expr),
625        }
626    }
627}
628
629#[derive(Debug, Clone, PartialEq, Eq, Hash)]
630#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
631pub enum SetVariableValue {
632    Ident(Ident),
633    Literal(Value),
634}
635
636impl fmt::Display for SetVariableValue {
637    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638        use SetVariableValue::*;
639        match self {
640            Ident(ident) => write!(f, "{}", ident),
641            Literal(literal) => write!(f, "{}", literal),
642        }
643    }
644}
645
646/// Sqlite specific syntax
647///
648/// https://sqlite.org/lang_conflict.html
649#[derive(Debug, Clone, PartialEq, Eq, Hash)]
650#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
651pub enum SqliteOnConflict {
652    Rollback,
653    Abort,
654    Fail,
655    Ignore,
656    Replace,
657}
658
659impl fmt::Display for SqliteOnConflict {
660    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
661        use SqliteOnConflict::*;
662        match self {
663            Rollback => write!(f, "ROLLBACK"),
664            Abort => write!(f, "ABORT"),
665            Fail => write!(f, "FAIL"),
666            Ignore => write!(f, "IGNORE"),
667            Replace => write!(f, "REPLACE"),
668        }
669    }
670}
671
672#[cfg(test)]
673mod tests {
674    use super::*;
675
676    #[test]
677    fn test_window_frame_default() {
678        let window_frame = WindowFrame::default();
679        assert_eq!(WindowFrameBound::Preceding(None), window_frame.start_bound);
680    }
681}