qail_core/ast/
operators.rs

1use serde::{Deserialize, Serialize};
2
3/// The action type (SQL operation).
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5pub enum Action {
6    /// SELECT query
7    Get,
8    /// UPDATE query  
9    Set,
10    /// DELETE query
11    Del,
12    /// INSERT query
13    Add,
14    /// Generate Rust struct from table schema
15    Gen,
16    /// Create Table (Make)
17    Make,
18    /// Drop Table (Drop)
19    Drop,
20    /// Modify Table (Mod)
21    Mod,
22    /// Window Function (Over)
23    Over,
24    /// CTE (With)
25    With,
26    /// Create Index
27    Index,
28    /// Drop Index
29    DropIndex,
30    /// ALTER TABLE ADD COLUMN
31    Alter,
32    /// ALTER TABLE DROP COLUMN
33    AlterDrop,
34    /// ALTER TABLE ALTER COLUMN TYPE
35    AlterType,
36    // Transactions
37    TxnStart,
38    TxnCommit,
39    TxnRollback,
40    Put,
41    DropCol,
42    RenameCol,
43    // Additional clauses
44    /// JSON_TABLE - convert JSON to relational rows
45    JsonTable,
46    /// COPY TO STDOUT - bulk export data (AST-native)
47    Export,
48    /// TRUNCATE TABLE - fast delete all rows
49    Truncate,
50    /// EXPLAIN - query plan analysis
51    Explain,
52    /// EXPLAIN ANALYZE - execute and analyze query plan
53    ExplainAnalyze,
54    /// LOCK TABLE - explicit table locking
55    Lock,
56    /// CREATE MATERIALIZED VIEW
57    CreateMaterializedView,
58    /// REFRESH MATERIALIZED VIEW
59    RefreshMaterializedView,
60    /// DROP MATERIALIZED VIEW
61    DropMaterializedView,
62    // Pub/Sub (LISTEN/NOTIFY)
63    /// LISTEN channel - subscribe to notifications
64    Listen,
65    /// NOTIFY channel, 'payload' - send notification
66    Notify,
67    /// UNLISTEN channel - unsubscribe from notifications
68    Unlisten,
69    // Savepoints
70    /// SAVEPOINT name
71    Savepoint,
72    /// RELEASE SAVEPOINT name
73    ReleaseSavepoint,
74    /// ROLLBACK TO SAVEPOINT name
75    RollbackToSavepoint,
76}
77
78impl std::fmt::Display for Action {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        match self {
81            Action::Get => write!(f, "GET"),
82            Action::Set => write!(f, "SET"),
83            Action::Del => write!(f, "DEL"),
84            Action::Add => write!(f, "ADD"),
85            Action::Gen => write!(f, "GEN"),
86            Action::Make => write!(f, "MAKE"),
87            Action::Drop => write!(f, "DROP"),
88            Action::Mod => write!(f, "MOD"),
89            Action::Over => write!(f, "OVER"),
90            Action::With => write!(f, "WITH"),
91            Action::Index => write!(f, "INDEX"),
92            Action::DropIndex => write!(f, "DROP_INDEX"),
93            Action::Alter => write!(f, "ALTER"),
94            Action::AlterDrop => write!(f, "ALTER_DROP"),
95            Action::AlterType => write!(f, "ALTER_TYPE"),
96            Action::TxnStart => write!(f, "TXN_START"),
97            Action::TxnCommit => write!(f, "TXN_COMMIT"),
98            Action::TxnRollback => write!(f, "TXN_ROLLBACK"),
99            Action::Put => write!(f, "PUT"),
100            Action::DropCol => write!(f, "DROP_COL"),
101            Action::RenameCol => write!(f, "RENAME_COL"),
102            Action::JsonTable => write!(f, "JSON_TABLE"),
103            Action::Export => write!(f, "EXPORT"),
104            Action::Truncate => write!(f, "TRUNCATE"),
105            Action::Explain => write!(f, "EXPLAIN"),
106            Action::ExplainAnalyze => write!(f, "EXPLAIN_ANALYZE"),
107            Action::Lock => write!(f, "LOCK"),
108            Action::CreateMaterializedView => write!(f, "CREATE_MATERIALIZED_VIEW"),
109            Action::RefreshMaterializedView => write!(f, "REFRESH_MATERIALIZED_VIEW"),
110            Action::DropMaterializedView => write!(f, "DROP_MATERIALIZED_VIEW"),
111            Action::Listen => write!(f, "LISTEN"),
112            Action::Notify => write!(f, "NOTIFY"),
113            Action::Unlisten => write!(f, "UNLISTEN"),
114            Action::Savepoint => write!(f, "SAVEPOINT"),
115            Action::ReleaseSavepoint => write!(f, "RELEASE_SAVEPOINT"),
116            Action::RollbackToSavepoint => write!(f, "ROLLBACK_TO_SAVEPOINT"),
117        }
118    }
119}
120
121/// Logical operator between conditions.
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
123pub enum LogicalOp {
124    #[default]
125    And,
126    Or,
127}
128
129/// Sort order direction.
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
131pub enum SortOrder {
132    Asc,
133    Desc,
134    /// ASC NULLS FIRST (nulls at top)
135    AscNullsFirst,
136    /// ASC NULLS LAST (nulls at bottom)
137    AscNullsLast,
138    /// DESC NULLS FIRST (nulls at top)
139    DescNullsFirst,
140    /// DESC NULLS LAST (nulls at bottom)
141    DescNullsLast,
142}
143
144/// Comparison operators.
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
146pub enum Operator {
147    /// Equal (=)
148    Eq,
149    /// Not equal (!=, <>)
150    Ne,
151    /// Greater than (>)
152    Gt,
153    /// Greater than or equal (>=)
154    Gte,
155    /// Less than (<)
156    Lt,
157    /// Less than or equal (<=)  
158    Lte,
159    /// Fuzzy match (~) -> ILIKE
160    Fuzzy,
161    /// IN array
162    In,
163    /// NOT IN array
164    NotIn,
165    /// IS NULL
166    IsNull,
167    /// IS NOT NULL
168    IsNotNull,
169    /// JSON/Array Contains (@>)
170    Contains,
171    /// JSON Key Exists (?)
172    KeyExists,
173    /// JSON_EXISTS - check if path exists (Postgres 17+)
174    JsonExists,
175    /// JSON_QUERY - extract JSON object/array at path (Postgres 17+)
176    JsonQuery,
177    /// JSON_VALUE - extract scalar value at path (Postgres 17+)
178    JsonValue,
179    /// LIKE pattern match
180    Like,
181    /// NOT LIKE pattern match
182    NotLike,
183    /// ILIKE case-insensitive pattern match (Postgres)
184    ILike,
185    /// NOT ILIKE case-insensitive pattern match (Postgres)
186    NotILike,
187    /// BETWEEN x AND y - range check (value stored as Value::Array with 2 elements)
188    Between,
189    /// NOT BETWEEN x AND y
190    NotBetween,
191    /// EXISTS (subquery) - check if subquery returns any rows
192    Exists,
193    /// NOT EXISTS (subquery)
194    NotExists,
195    /// Regular expression match (~ in Postgres)
196    Regex,
197    /// Case-insensitive regex (~* in Postgres)
198    RegexI,
199    /// SIMILAR TO pattern match
200    SimilarTo,
201    /// Array/JSON is contained by (<@)
202    ContainedBy,
203    /// Array overlap (&&)
204    Overlaps,
205}
206
207impl Operator {
208    /// Returns the SQL symbol/keyword for this operator.
209    /// For simple operators, returns the symbol directly.
210    /// For complex operators (BETWEEN, EXISTS), returns the keyword.
211    pub fn sql_symbol(&self) -> &'static str {
212        match self {
213            Operator::Eq => "=",
214            Operator::Ne => "!=",
215            Operator::Gt => ">",
216            Operator::Gte => ">=",
217            Operator::Lt => "<",
218            Operator::Lte => "<=",
219            Operator::Fuzzy => "ILIKE",
220            Operator::In => "IN",
221            Operator::NotIn => "NOT IN",
222            Operator::IsNull => "IS NULL",
223            Operator::IsNotNull => "IS NOT NULL",
224            Operator::Contains => "@>",
225            Operator::KeyExists => "?",
226            Operator::JsonExists => "JSON_EXISTS",
227            Operator::JsonQuery => "JSON_QUERY",
228            Operator::JsonValue => "JSON_VALUE",
229            Operator::Like => "LIKE",
230            Operator::NotLike => "NOT LIKE",
231            Operator::ILike => "ILIKE",
232            Operator::NotILike => "NOT ILIKE",
233            Operator::Between => "BETWEEN",
234            Operator::NotBetween => "NOT BETWEEN",
235            Operator::Exists => "EXISTS",
236            Operator::NotExists => "NOT EXISTS",
237            Operator::Regex => "~",
238            Operator::RegexI => "~*",
239            Operator::SimilarTo => "SIMILAR TO",
240            Operator::ContainedBy => "<@",
241            Operator::Overlaps => "&&",
242        }
243    }
244
245    /// Returns true if this operator requires a value on the right side.
246    /// IS NULL, IS NOT NULL, EXISTS, NOT EXISTS don't need values.
247    pub fn needs_value(&self) -> bool {
248        !matches!(
249            self,
250            Operator::IsNull | Operator::IsNotNull | Operator::Exists | Operator::NotExists
251        )
252    }
253
254    /// Returns true if this operator is a simple binary operator (col OP value).
255    pub fn is_simple_binary(&self) -> bool {
256        matches!(
257            self,
258            Operator::Eq
259                | Operator::Ne
260                | Operator::Gt
261                | Operator::Gte
262                | Operator::Lt
263                | Operator::Lte
264                | Operator::Like
265                | Operator::NotLike
266                | Operator::ILike
267                | Operator::NotILike
268        )
269    }
270}
271
272/// Aggregate functions.
273#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
274pub enum AggregateFunc {
275    Count,
276    Sum,
277    Avg,
278    Min,
279    Max,
280    /// ARRAY_AGG - collect values into array
281    ArrayAgg,
282    /// STRING_AGG - concatenate strings with delimiter
283    StringAgg,
284    /// JSON_AGG - aggregate values as JSON array
285    JsonAgg,
286    /// JSONB_AGG - aggregate values as JSONB array
287    JsonbAgg,
288    /// BOOL_AND - logical AND of all values
289    BoolAnd,
290    /// BOOL_OR - logical OR of all values
291    BoolOr,
292}
293
294impl std::fmt::Display for AggregateFunc {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        match self {
297            AggregateFunc::Count => write!(f, "COUNT"),
298            AggregateFunc::Sum => write!(f, "SUM"),
299            AggregateFunc::Avg => write!(f, "AVG"),
300            AggregateFunc::Min => write!(f, "MIN"),
301            AggregateFunc::Max => write!(f, "MAX"),
302            AggregateFunc::ArrayAgg => write!(f, "ARRAY_AGG"),
303            AggregateFunc::StringAgg => write!(f, "STRING_AGG"),
304            AggregateFunc::JsonAgg => write!(f, "JSON_AGG"),
305            AggregateFunc::JsonbAgg => write!(f, "JSONB_AGG"),
306            AggregateFunc::BoolAnd => write!(f, "BOOL_AND"),
307            AggregateFunc::BoolOr => write!(f, "BOOL_OR"),
308        }
309    }
310}
311
312/// Join Type
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
314pub enum JoinKind {
315    Inner,
316    Left,
317    Right,
318    /// LATERAL join (Postgres, MySQL 8+)
319    Lateral,
320    /// FULL OUTER JOIN
321    Full,
322    /// CROSS JOIN
323    Cross,
324}
325
326/// Set operation type for combining queries
327#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
328pub enum SetOp {
329    /// UNION (removes duplicates)
330    Union,
331    /// UNION ALL (keeps duplicates)
332    UnionAll,
333    /// INTERSECT (common rows)
334    Intersect,
335    /// EXCEPT (rows in first but not second)
336    Except,
337}
338
339/// Column modification type
340#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
341pub enum ModKind {
342    Add,
343    Drop,
344}
345
346/// GROUP BY mode for advanced aggregations
347#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
348pub enum GroupByMode {
349    /// Standard GROUP BY
350    #[default]
351    Simple,
352    /// ROLLUP - hierarchical subtotals
353    Rollup,
354    /// CUBE - all combinations of subtotals
355    Cube,
356}
357
358/// Row locking mode for SELECT...FOR UPDATE/SHARE
359#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
360pub enum LockMode {
361    /// FOR UPDATE - exclusive lock
362    Update,
363    /// FOR NO KEY UPDATE - weaker exclusive lock
364    NoKeyUpdate,
365    /// FOR SHARE - shared lock
366    Share,
367    /// FOR KEY SHARE - weakest shared lock
368    KeyShare,
369}
370
371/// OVERRIDING clause for INSERT with GENERATED columns
372#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
373pub enum OverridingKind {
374    /// OVERRIDING SYSTEM VALUE - override GENERATED ALWAYS columns
375    SystemValue,
376    /// OVERRIDING USER VALUE - override GENERATED BY DEFAULT columns
377    UserValue,
378}
379
380/// TABLESAMPLE sampling method
381#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
382pub enum SampleMethod {
383    /// BERNOULLI - each row has independent probability
384    Bernoulli,
385    /// SYSTEM - faster but less random (block-level sampling)
386    System,
387}