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    // Transactions
35    TxnStart,
36    TxnCommit,
37    TxnRollback,
38    Put,
39    DropCol,
40    RenameCol,
41    // Additional clauses
42    /// JSON_TABLE - convert JSON to relational rows
43    JsonTable,
44    /// COPY TO STDOUT - bulk export data (AST-native)
45    Export,
46}
47
48impl std::fmt::Display for Action {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        match self {
51            Action::Get => write!(f, "GET"),
52            Action::Set => write!(f, "SET"),
53            Action::Del => write!(f, "DEL"),
54            Action::Add => write!(f, "ADD"),
55            Action::Gen => write!(f, "GEN"),
56            Action::Make => write!(f, "MAKE"),
57            Action::Drop => write!(f, "DROP"),
58            Action::Mod => write!(f, "MOD"),
59            Action::Over => write!(f, "OVER"),
60            Action::With => write!(f, "WITH"),
61            Action::Index => write!(f, "INDEX"),
62            Action::DropIndex => write!(f, "DROP_INDEX"),
63            Action::Alter => write!(f, "ALTER"),
64            Action::AlterDrop => write!(f, "ALTER_DROP"),
65            Action::TxnStart => write!(f, "TXN_START"),
66            Action::TxnCommit => write!(f, "TXN_COMMIT"),
67            Action::TxnRollback => write!(f, "TXN_ROLLBACK"),
68            Action::Put => write!(f, "PUT"),
69            Action::DropCol => write!(f, "DROP_COL"),
70            Action::RenameCol => write!(f, "RENAME_COL"),
71            Action::JsonTable => write!(f, "JSON_TABLE"),
72            Action::Export => write!(f, "EXPORT"),
73        }
74    }
75}
76
77/// Logical operator between conditions.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
79pub enum LogicalOp {
80    #[default]
81    And,
82    Or,
83}
84
85/// Sort order direction.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
87pub enum SortOrder {
88    Asc,
89    Desc,
90    /// ASC NULLS FIRST (nulls at top)
91    AscNullsFirst,
92    /// ASC NULLS LAST (nulls at bottom)
93    AscNullsLast,
94    /// DESC NULLS FIRST (nulls at top)
95    DescNullsFirst,
96    /// DESC NULLS LAST (nulls at bottom)
97    DescNullsLast,
98}
99
100/// Comparison operators.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
102pub enum Operator {
103    /// Equal (=)
104    Eq,
105    /// Not equal (!=, <>)
106    Ne,
107    /// Greater than (>)
108    Gt,
109    /// Greater than or equal (>=)
110    Gte,
111    /// Less than (<)
112    Lt,
113    /// Less than or equal (<=)  
114    Lte,
115    /// Fuzzy match (~) -> ILIKE
116    Fuzzy,
117    /// IN array
118    In,
119    /// NOT IN array
120    NotIn,
121    /// IS NULL
122    IsNull,
123    /// IS NOT NULL
124    IsNotNull,
125    /// JSON/Array Contains (@>)
126    Contains,
127    /// JSON Key Exists (?)
128    KeyExists,
129    /// JSON_EXISTS - check if path exists (Postgres 17+)
130    JsonExists,
131    /// JSON_QUERY - extract JSON object/array at path (Postgres 17+)
132    JsonQuery,
133    /// JSON_VALUE - extract scalar value at path (Postgres 17+)
134    JsonValue,
135    /// LIKE pattern match
136    Like,
137    /// NOT LIKE pattern match
138    NotLike,
139    /// ILIKE case-insensitive pattern match (Postgres)
140    ILike,
141    /// NOT ILIKE case-insensitive pattern match (Postgres)
142    NotILike,
143    /// BETWEEN x AND y - range check (value stored as Value::Array with 2 elements)
144    Between,
145    /// NOT BETWEEN x AND y
146    NotBetween,
147    /// EXISTS (subquery) - check if subquery returns any rows
148    Exists,
149    /// NOT EXISTS (subquery)
150    NotExists,
151}
152
153impl Operator {
154    /// Returns the SQL symbol/keyword for this operator.
155    /// For simple operators, returns the symbol directly.
156    /// For complex operators (BETWEEN, EXISTS), returns the keyword.
157    pub fn sql_symbol(&self) -> &'static str {
158        match self {
159            Operator::Eq => "=",
160            Operator::Ne => "!=",
161            Operator::Gt => ">",
162            Operator::Gte => ">=",
163            Operator::Lt => "<",
164            Operator::Lte => "<=",
165            Operator::Fuzzy => "ILIKE",
166            Operator::In => "IN",
167            Operator::NotIn => "NOT IN",
168            Operator::IsNull => "IS NULL",
169            Operator::IsNotNull => "IS NOT NULL",
170            Operator::Contains => "@>",
171            Operator::KeyExists => "?",
172            Operator::JsonExists => "JSON_EXISTS",
173            Operator::JsonQuery => "JSON_QUERY",
174            Operator::JsonValue => "JSON_VALUE",
175            Operator::Like => "LIKE",
176            Operator::NotLike => "NOT LIKE",
177            Operator::ILike => "ILIKE",
178            Operator::NotILike => "NOT ILIKE",
179            Operator::Between => "BETWEEN",
180            Operator::NotBetween => "NOT BETWEEN",
181            Operator::Exists => "EXISTS",
182            Operator::NotExists => "NOT EXISTS",
183        }
184    }
185
186    /// Returns true if this operator requires a value on the right side.
187    /// IS NULL, IS NOT NULL, EXISTS, NOT EXISTS don't need values.
188    pub fn needs_value(&self) -> bool {
189        !matches!(self, 
190            Operator::IsNull | 
191            Operator::IsNotNull | 
192            Operator::Exists | 
193            Operator::NotExists
194        )
195    }
196
197    /// Returns true if this operator is a simple binary operator (col OP value).
198    pub fn is_simple_binary(&self) -> bool {
199        matches!(self,
200            Operator::Eq | Operator::Ne | Operator::Gt | Operator::Gte |
201            Operator::Lt | Operator::Lte | Operator::Like | Operator::NotLike |
202            Operator::ILike | Operator::NotILike
203        )
204    }
205}
206
207/// Aggregate functions.
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
209pub enum AggregateFunc {
210    Count,
211    Sum,
212    Avg,
213    Min,
214    Max,
215}
216
217impl std::fmt::Display for AggregateFunc {
218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219        match self {
220            AggregateFunc::Count => write!(f, "COUNT"),
221            AggregateFunc::Sum => write!(f, "SUM"),
222            AggregateFunc::Avg => write!(f, "AVG"),
223            AggregateFunc::Min => write!(f, "MIN"),
224            AggregateFunc::Max => write!(f, "MAX"),
225        }
226    }
227}
228
229/// Join Type
230#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
231pub enum JoinKind {
232    Inner,
233    Left,
234    Right,
235    /// LATERAL join (Postgres, MySQL 8+)
236    Lateral,
237    /// FULL OUTER JOIN
238    Full,
239    /// CROSS JOIN
240    Cross,
241}
242
243/// Set operation type for combining queries
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
245pub enum SetOp {
246    /// UNION (removes duplicates)
247    Union,
248    /// UNION ALL (keeps duplicates)
249    UnionAll,
250    /// INTERSECT (common rows)
251    Intersect,
252    /// EXCEPT (rows in first but not second)
253    Except,
254}
255
256/// Column modification type
257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
258pub enum ModKind {
259    Add,
260    Drop,
261}
262
263/// GROUP BY mode for advanced aggregations
264#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
265pub enum GroupByMode {
266    /// Standard GROUP BY
267    #[default]
268    Simple,
269    /// ROLLUP - hierarchical subtotals
270    Rollup,
271    /// CUBE - all combinations of subtotals
272    Cube,
273}