vibesql_ast/
lib.rs

1//! Abstract Syntax Tree (AST) for SQL:1999
2//!
3//! This crate defines the structure of SQL statements and expressions
4//! as parsed from SQL text. The AST is a tree representation that
5//! preserves the semantic structure of SQL queries.
6//!
7//! # Arena-allocated Types
8//!
9//! For performance-critical code paths, this crate provides arena-allocated
10//! versions of AST types in the [`arena`] module. These use bump allocation
11//! for improved cache locality and reduced allocation overhead.
12//!
13//! # Visitor Pattern
14//!
15//! The [`visitor`] module provides traits for traversing and transforming
16//! AST nodes without duplicating traversal logic:
17//!
18//! - [`visitor::ExpressionVisitor`]: Read-only expression traversal
19//! - [`visitor::ExpressionMutVisitor`]: Expression transformation
20//! - [`visitor::StatementVisitor`]: Statement traversal
21//!
22//! See the module documentation for usage examples.
23//!
24//! # SQL Pretty-Printing
25//!
26//! The [`pretty_print`] module provides the [`pretty_print::ToSql`] trait for converting
27//! AST nodes back to valid SQL strings:
28//!
29//! ```
30//! use vibesql_ast::pretty_print::ToSql;
31//! use vibesql_ast::BinaryOperator;
32//!
33//! let op = BinaryOperator::Plus;
34//! assert_eq!(op.to_sql(), "+");
35//! ```
36
37pub mod arena;
38pub mod pretty_print;
39pub mod visitor;
40
41// ============================================================================
42// Table Reference (with case-sensitivity info)
43// ============================================================================
44
45/// A reference to a table name with case-sensitivity information.
46///
47/// This struct captures whether an identifier was quoted (delimited) in the
48/// original SQL, which is necessary for correct SQL:1999 case handling:
49///
50/// - **Unquoted identifiers**: Case-insensitive (e.g., `MyTable`, `mytable`, `MYTABLE` are equivalent)
51/// - **Quoted identifiers**: Case-sensitive (e.g., `"MyTable"` is different from `"mytable"`)
52///
53/// # Example
54///
55/// ```
56/// use vibesql_ast::TableRef;
57///
58/// // Unquoted: case-insensitive
59/// let unquoted = TableRef::new("MyTable".to_string(), false);
60///
61/// // Quoted: case-sensitive
62/// let quoted = TableRef::new("MyTable".to_string(), true);
63/// ```
64#[derive(Debug, Clone, PartialEq)]
65pub struct TableRef {
66    /// Optional schema name for qualified references (e.g., schema.table)
67    pub schema_name: Option<String>,
68    /// Whether the schema name was quoted (delimited) in the original SQL.
69    pub schema_quoted: bool,
70    /// The table name as written in the SQL
71    pub name: String,
72    /// Whether the identifier was quoted (delimited) in the original SQL.
73    /// - `true`: Quoted identifier (case-sensitive), e.g., `"MyTable"`
74    /// - `false`: Unquoted identifier (case-insensitive), e.g., `MyTable`
75    pub quoted: bool,
76}
77
78impl TableRef {
79    /// Create a new table reference.
80    pub fn new(name: String, quoted: bool) -> Self {
81        Self { schema_name: None, schema_quoted: false, name, quoted }
82    }
83
84    /// Create a qualified table reference with schema.
85    pub fn qualified(
86        schema_name: String,
87        schema_quoted: bool,
88        table_name: String,
89        table_quoted: bool,
90    ) -> Self {
91        Self {
92            schema_name: Some(schema_name),
93            schema_quoted,
94            name: table_name,
95            quoted: table_quoted,
96        }
97    }
98
99    /// Create an unquoted (case-insensitive) table reference.
100    pub fn unquoted(name: String) -> Self {
101        Self::new(name, false)
102    }
103
104    /// Create a quoted (case-sensitive) table reference.
105    pub fn quoted_ref(name: String) -> Self {
106        Self::new(name, true)
107    }
108
109    /// Get the full name (schema.table or just table)
110    pub fn full_name(&self) -> String {
111        match &self.schema_name {
112            Some(schema) => format!("{}.{}", schema, self.name),
113            None => self.name.clone(),
114        }
115    }
116
117    /// Check if any part is quoted
118    pub fn is_any_quoted(&self) -> bool {
119        self.quoted || self.schema_quoted
120    }
121}
122
123impl From<String> for TableRef {
124    /// Create an unquoted table reference from a String (for backward compatibility).
125    fn from(name: String) -> Self {
126        Self::unquoted(name)
127    }
128}
129
130impl From<&str> for TableRef {
131    /// Create an unquoted table reference from a &str (for backward compatibility).
132    fn from(name: &str) -> Self {
133        Self::unquoted(name.to_string())
134    }
135}
136
137impl std::fmt::Display for TableRef {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        if self.quoted {
140            // Quote the identifier in output
141            write!(f, "\"{}\"", self.name.replace('"', "\"\""))
142        } else {
143            write!(f, "{}", self.name)
144        }
145    }
146}
147
148mod ddl;
149mod dml;
150mod expression;
151mod grant;
152mod identifier;
153mod introspection;
154mod operators;
155mod revoke;
156mod select;
157mod statement;
158
159pub use ddl::{
160    AddColumnStmt, AddConstraintStmt, AlterColumnStmt, AlterCronStmt, AlterSequenceStmt,
161    AlterTableStmt, AlterTriggerAction, AlterTriggerStmt, AnalyzeStmt, BeginStmt, CallStmt,
162    CancelScheduleStmt, ChangeColumnStmt, CloseCursorStmt, ColumnConstraint, ColumnConstraintKind,
163    ColumnDef, CommitStmt, ConstraintDeferral, CreateAssertionStmt, CreateCharacterSetStmt,
164    CreateCollationStmt, CreateCronStmt, CreateDomainStmt, CreateFunctionStmt, CreateIndexStmt,
165    CreateProcedureStmt, CreateRoleStmt, CreateSchemaStmt, CreateSequenceStmt, CreateTableStmt,
166    CreateTranslationStmt, CreateTriggerStmt, CreateTypeStmt, CreateViewStmt, CursorUpdatability,
167    DeallocateStmt, DeallocateTarget, DeclareCursorStmt, DomainConstraint, DropAssertionStmt,
168    DropBehavior, DropCharacterSetStmt, DropCollationStmt, DropColumnStmt, DropConstraintStmt,
169    DropCronStmt, DropDomainStmt, DropFunctionStmt, DropIndexStmt, DropProcedureStmt, DropRoleStmt,
170    DropSchemaStmt, DropSequenceStmt, DropTableStmt, DropTranslationStmt, DropTriggerStmt,
171    DropTypeStmt, DropViewStmt, DurabilityHint, ExecuteStmt, FetchOrientation, FetchStmt,
172    FunctionParameter, IndexColumn, IndexType, InsertMethod, IsolationLevel, ModifyColumnStmt,
173    OpenCursorStmt, ParameterMode, PragmaStmt, PragmaValue, PrepareStmt, PreparedStatementBody,
174    ProceduralStatement, ProcedureBody, ProcedureParameter, ReferentialAction, ReindexStmt,
175    ReleaseSavepointStmt, RenameTableStmt, RollbackStmt, RollbackToSavepointStmt, RowFormat,
176    SavepointStmt, ScheduleAfterStmt, ScheduleAtStmt, SchemaElement, SetCatalogStmt, SetNamesStmt,
177    SetSchemaStmt, SetTimeZoneStmt, SetTransactionStmt, SetVariableStmt, SqlSecurity,
178    StorageFormat, TableConstraint, TableConstraintKind, TableOption, TimeZoneSpec,
179    TransactionAccessMode, TriggerAction, TriggerEvent, TriggerGranularity, TriggerTiming,
180    TruncateCascadeOption, TruncateTableStmt, TypeAttribute, TypeDefinition, VariableScope,
181    VectorDistanceMetric,
182};
183pub use dml::{
184    Assignment, ConflictClause, DeleteStmt, InsertSource, InsertStmt, OnConflictAction,
185    OnConflictClause, UpdateStmt, WhereClause,
186};
187pub use expression::{
188    CaseWhen, CharacterUnit, Expression, FrameBound, FrameExclude, FrameUnit, FulltextMode,
189    IntervalUnit, PseudoTable, Quantifier, TrimPosition, TruthValue, WindowFrame,
190    WindowFunctionSpec, WindowSpec,
191};
192pub use grant::{GrantStmt, ObjectType, PrivilegeType};
193pub use introspection::{
194    DescribeStmt, ExplainFormat, ExplainStmt, ShowColumnsStmt, ShowCreateTableStmt,
195    ShowDatabasesStmt, ShowIndexStmt, ShowTablesStmt,
196};
197pub use operators::{BinaryOperator, UnaryOperator};
198pub use revoke::{CascadeOption, RevokeStmt};
199pub use select::{
200    CommonTableExpr, CteMaterialization, FromClause, GroupByClause, GroupingElement, GroupingSet,
201    JoinType, MixedGroupingItem, NullsOrder, OrderByItem, OrderDirection, SelectItem, SelectStmt,
202    SetOperation, SetOperator,
203};
204pub use statement::Statement;
205
206// SQL Identifiers with SQL:1999 case sensitivity handling
207pub use identifier::{ColumnIdentifier, FunctionIdentifier, Identifier, TableIdentifier};