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    Del,
11    /// INSERT query
12    Add,
13    Gen,
14    Make,
15    Drop,
16    Mod,
17    Over,
18    With,
19    Index,
20    DropIndex,
21    Alter,
22    /// ALTER TABLE DROP COLUMN
23    AlterDrop,
24    /// ALTER TABLE ALTER COLUMN TYPE
25    AlterType,
26    // Transactions
27    TxnStart,
28    TxnCommit,
29    TxnRollback,
30    Put,
31    DropCol,
32    RenameCol,
33    // Additional clauses
34    /// JSON_TABLE - convert JSON to relational rows
35    JsonTable,
36    /// COPY TO STDOUT - bulk export data (AST-native)
37    Export,
38    /// TRUNCATE TABLE - fast delete all rows
39    Truncate,
40    /// EXPLAIN - query plan analysis
41    Explain,
42    /// EXPLAIN ANALYZE - execute and analyze query plan
43    ExplainAnalyze,
44    /// LOCK TABLE - explicit table locking
45    Lock,
46    CreateMaterializedView,
47    RefreshMaterializedView,
48    DropMaterializedView,
49    // Pub/Sub (LISTEN/NOTIFY)
50    /// LISTEN channel - subscribe to notifications
51    Listen,
52    /// NOTIFY channel, 'payload' - send notification
53    Notify,
54    /// UNLISTEN channel - unsubscribe from notifications
55    Unlisten,
56    // Savepoints
57    Savepoint,
58    ReleaseSavepoint,
59    RollbackToSavepoint,
60    // Views
61    /// CREATE VIEW name AS SELECT ...
62    CreateView,
63    /// DROP VIEW name
64    DropView,
65    // Vector database operations
66    /// Vector similarity search (Qdrant)
67    Search,
68    /// Insert or update points (Qdrant)
69    Upsert,
70    /// Paginated iteration over points (Qdrant)
71    Scroll,
72    /// Create new collection (Qdrant)
73    CreateCollection,
74    /// Delete collection (Qdrant)
75    DeleteCollection,
76    // PostgreSQL Functions and Triggers
77    /// CREATE FUNCTION name() RETURNS type AS $$ body $$ LANGUAGE plpgsql
78    CreateFunction,
79    /// DROP FUNCTION name
80    DropFunction,
81    /// CREATE TRIGGER name AFTER INSERT OR UPDATE ON table
82    CreateTrigger,
83    /// DROP TRIGGER name ON table
84    DropTrigger,
85    // Redis operations (key-value store)
86    /// Redis GET key
87    RedisGet,
88    /// Redis SET key value [EX seconds]
89    RedisSet,
90    /// Redis DEL key [key ...]
91    RedisDel,
92    /// Redis INCR/INCRBY key
93    RedisIncr,
94    /// Redis DECR/DECRBY key
95    RedisDecr,
96    /// Redis TTL/PTTL key
97    RedisTtl,
98    /// Redis EXPIRE/PEXPIRE key seconds
99    RedisExpire,
100    /// Redis EXISTS key
101    RedisExists,
102    /// Redis MGET keys
103    RedisMGet,
104    /// Redis MSET key value [key value ...]
105    RedisMSet,
106    /// Redis PING
107    RedisPing,
108}
109
110impl std::fmt::Display for Action {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        match self {
113            Action::Get => write!(f, "GET"),
114            Action::Set => write!(f, "SET"),
115            Action::Del => write!(f, "DEL"),
116            Action::Add => write!(f, "ADD"),
117            Action::Gen => write!(f, "GEN"),
118            Action::Make => write!(f, "MAKE"),
119            Action::Drop => write!(f, "DROP"),
120            Action::Mod => write!(f, "MOD"),
121            Action::Over => write!(f, "OVER"),
122            Action::With => write!(f, "WITH"),
123            Action::Index => write!(f, "INDEX"),
124            Action::DropIndex => write!(f, "DROP_INDEX"),
125            Action::Alter => write!(f, "ALTER"),
126            Action::AlterDrop => write!(f, "ALTER_DROP"),
127            Action::AlterType => write!(f, "ALTER_TYPE"),
128            Action::TxnStart => write!(f, "TXN_START"),
129            Action::TxnCommit => write!(f, "TXN_COMMIT"),
130            Action::TxnRollback => write!(f, "TXN_ROLLBACK"),
131            Action::Put => write!(f, "PUT"),
132            Action::DropCol => write!(f, "DROP_COL"),
133            Action::RenameCol => write!(f, "RENAME_COL"),
134            Action::JsonTable => write!(f, "JSON_TABLE"),
135            Action::Export => write!(f, "EXPORT"),
136            Action::Truncate => write!(f, "TRUNCATE"),
137            Action::Explain => write!(f, "EXPLAIN"),
138            Action::ExplainAnalyze => write!(f, "EXPLAIN_ANALYZE"),
139            Action::Lock => write!(f, "LOCK"),
140            Action::CreateMaterializedView => write!(f, "CREATE_MATERIALIZED_VIEW"),
141            Action::RefreshMaterializedView => write!(f, "REFRESH_MATERIALIZED_VIEW"),
142            Action::DropMaterializedView => write!(f, "DROP_MATERIALIZED_VIEW"),
143            Action::Listen => write!(f, "LISTEN"),
144            Action::Notify => write!(f, "NOTIFY"),
145            Action::Unlisten => write!(f, "UNLISTEN"),
146            Action::Savepoint => write!(f, "SAVEPOINT"),
147            Action::ReleaseSavepoint => write!(f, "RELEASE_SAVEPOINT"),
148            Action::RollbackToSavepoint => write!(f, "ROLLBACK_TO_SAVEPOINT"),
149            Action::CreateView => write!(f, "CREATE_VIEW"),
150            Action::DropView => write!(f, "DROP_VIEW"),
151            Action::Search => write!(f, "SEARCH"),
152            Action::Upsert => write!(f, "UPSERT"),
153            Action::Scroll => write!(f, "SCROLL"),
154            Action::CreateCollection => write!(f, "CREATE_COLLECTION"),
155            Action::DeleteCollection => write!(f, "DELETE_COLLECTION"),
156            Action::CreateFunction => write!(f, "CREATE_FUNCTION"),
157            Action::DropFunction => write!(f, "DROP_FUNCTION"),
158            Action::CreateTrigger => write!(f, "CREATE_TRIGGER"),
159            Action::DropTrigger => write!(f, "DROP_TRIGGER"),
160            // Redis
161            Action::RedisGet => write!(f, "REDIS_GET"),
162            Action::RedisSet => write!(f, "REDIS_SET"),
163            Action::RedisDel => write!(f, "REDIS_DEL"),
164            Action::RedisIncr => write!(f, "REDIS_INCR"),
165            Action::RedisDecr => write!(f, "REDIS_DECR"),
166            Action::RedisTtl => write!(f, "REDIS_TTL"),
167            Action::RedisExpire => write!(f, "REDIS_EXPIRE"),
168            Action::RedisExists => write!(f, "REDIS_EXISTS"),
169            Action::RedisMGet => write!(f, "REDIS_MGET"),
170            Action::RedisMSet => write!(f, "REDIS_MSET"),
171            Action::RedisPing => write!(f, "REDIS_PING"),
172        }
173    }
174}
175
176/// Logical operator between conditions.
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
178pub enum LogicalOp {
179    #[default]
180    And,
181    Or,
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
185pub enum SortOrder {
186    Asc,
187    Desc,
188    AscNullsFirst,
189    AscNullsLast,
190    DescNullsFirst,
191    DescNullsLast,
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
195pub enum Operator {
196    Eq,
197    /// Not equal (!=, <>)
198    Ne,
199    /// Greater than (>)
200    Gt,
201    /// Greater than or equal (>=)
202    Gte,
203    /// Less than (<)
204    Lt,
205    /// Less than or equal (<=)  
206    Lte,
207    Fuzzy,
208    In,
209    NotIn,
210    IsNull,
211    IsNotNull,
212    Contains,
213    KeyExists,
214    /// JSON_EXISTS - check if path exists (Postgres 17+)
215    JsonExists,
216    /// JSON_QUERY - extract JSON object/array at path (Postgres 17+)
217    JsonQuery,
218    /// JSON_VALUE - extract scalar value at path (Postgres 17+)
219    JsonValue,
220    Like,
221    NotLike,
222    /// ILIKE case-insensitive pattern match (Postgres)
223    ILike,
224    /// NOT ILIKE case-insensitive pattern match (Postgres)
225    NotILike,
226    /// BETWEEN x AND y - range check (value stored as Value::Array with 2 elements)
227    Between,
228    NotBetween,
229    /// EXISTS (subquery) - check if subquery returns any rows
230    Exists,
231    NotExists,
232    /// Regular expression match (~ in Postgres)
233    Regex,
234    /// Case-insensitive regex (~* in Postgres)
235    RegexI,
236    SimilarTo,
237    ContainedBy,
238    /// Array overlap (&&)
239    Overlaps,
240}
241
242impl Operator {
243    /// For simple operators, returns the symbol directly.
244    /// For complex operators (BETWEEN, EXISTS), returns the keyword.
245    pub fn sql_symbol(&self) -> &'static str {
246        match self {
247            Operator::Eq => "=",
248            Operator::Ne => "!=",
249            Operator::Gt => ">",
250            Operator::Gte => ">=",
251            Operator::Lt => "<",
252            Operator::Lte => "<=",
253            Operator::Fuzzy => "ILIKE",
254            Operator::In => "IN",
255            Operator::NotIn => "NOT IN",
256            Operator::IsNull => "IS NULL",
257            Operator::IsNotNull => "IS NOT NULL",
258            Operator::Contains => "@>",
259            Operator::KeyExists => "?",
260            Operator::JsonExists => "JSON_EXISTS",
261            Operator::JsonQuery => "JSON_QUERY",
262            Operator::JsonValue => "JSON_VALUE",
263            Operator::Like => "LIKE",
264            Operator::NotLike => "NOT LIKE",
265            Operator::ILike => "ILIKE",
266            Operator::NotILike => "NOT ILIKE",
267            Operator::Between => "BETWEEN",
268            Operator::NotBetween => "NOT BETWEEN",
269            Operator::Exists => "EXISTS",
270            Operator::NotExists => "NOT EXISTS",
271            Operator::Regex => "~",
272            Operator::RegexI => "~*",
273            Operator::SimilarTo => "SIMILAR TO",
274            Operator::ContainedBy => "<@",
275            Operator::Overlaps => "&&",
276        }
277    }
278
279    /// IS NULL, IS NOT NULL, EXISTS, NOT EXISTS don't need values.
280    pub fn needs_value(&self) -> bool {
281        !matches!(
282            self,
283            Operator::IsNull | Operator::IsNotNull | Operator::Exists | Operator::NotExists
284        )
285    }
286
287    pub fn is_simple_binary(&self) -> bool {
288        matches!(
289            self,
290            Operator::Eq
291                | Operator::Ne
292                | Operator::Gt
293                | Operator::Gte
294                | Operator::Lt
295                | Operator::Lte
296                | Operator::Like
297                | Operator::NotLike
298                | Operator::ILike
299                | Operator::NotILike
300        )
301    }
302}
303
304#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
305pub enum AggregateFunc {
306    Count,
307    Sum,
308    Avg,
309    Min,
310    Max,
311    /// ARRAY_AGG - collect values into array
312    ArrayAgg,
313    /// STRING_AGG - concatenate strings with delimiter
314    StringAgg,
315    /// JSON_AGG - aggregate values as JSON array
316    JsonAgg,
317    /// JSONB_AGG - aggregate values as JSONB array
318    JsonbAgg,
319    /// BOOL_AND - logical AND of all values
320    BoolAnd,
321    /// BOOL_OR - logical OR of all values
322    BoolOr,
323}
324
325impl std::fmt::Display for AggregateFunc {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        match self {
328            AggregateFunc::Count => write!(f, "COUNT"),
329            AggregateFunc::Sum => write!(f, "SUM"),
330            AggregateFunc::Avg => write!(f, "AVG"),
331            AggregateFunc::Min => write!(f, "MIN"),
332            AggregateFunc::Max => write!(f, "MAX"),
333            AggregateFunc::ArrayAgg => write!(f, "ARRAY_AGG"),
334            AggregateFunc::StringAgg => write!(f, "STRING_AGG"),
335            AggregateFunc::JsonAgg => write!(f, "JSON_AGG"),
336            AggregateFunc::JsonbAgg => write!(f, "JSONB_AGG"),
337            AggregateFunc::BoolAnd => write!(f, "BOOL_AND"),
338            AggregateFunc::BoolOr => write!(f, "BOOL_OR"),
339        }
340    }
341}
342
343/// Join Type
344#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
345pub enum JoinKind {
346    Inner,
347    Left,
348    Right,
349    Lateral,
350    Full,
351    Cross,
352}
353
354/// Set operation type for combining queries
355#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
356pub enum SetOp {
357    Union,
358    UnionAll,
359    Intersect,
360    Except,
361}
362
363#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
364pub enum ModKind {
365    Add,
366    Drop,
367}
368
369/// GROUP BY mode for advanced aggregations
370#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
371pub enum GroupByMode {
372    /// Standard GROUP BY
373    #[default]
374    Simple,
375    /// ROLLUP - hierarchical subtotals
376    Rollup,
377    /// CUBE - all combinations of subtotals
378    Cube,
379    /// GROUPING SETS - explicit grouping sets: GROUPING SETS ((a, b), (c))
380    GroupingSets(Vec<Vec<String>>),
381}
382
383/// Row locking mode for SELECT...FOR UPDATE/SHARE
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
385pub enum LockMode {
386    /// FOR UPDATE - exclusive lock
387    Update,
388    /// FOR NO KEY UPDATE - weaker exclusive lock
389    NoKeyUpdate,
390    /// FOR SHARE - shared lock
391    Share,
392    /// FOR KEY SHARE - weakest shared lock
393    KeyShare,
394}
395
396/// OVERRIDING clause for INSERT with GENERATED columns
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
398pub enum OverridingKind {
399    /// OVERRIDING SYSTEM VALUE - override GENERATED ALWAYS columns
400    SystemValue,
401    /// OVERRIDING USER VALUE - override GENERATED BY DEFAULT columns
402    UserValue,
403}
404
405/// TABLESAMPLE sampling method
406#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
407pub enum SampleMethod {
408    /// BERNOULLI - each row has independent probability
409    Bernoulli,
410    /// SYSTEM - faster but less random (block-level sampling)
411    System,
412}
413
414/// Distance metric for vector similarity
415#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
416pub enum Distance {
417    #[default]
418    Cosine,
419    Euclid,
420    Dot,
421}