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