Skip to main content

qcraft_core/ast/
expr.rs

1use super::common::{FieldRef, OrderByDef};
2use super::conditions::Conditions;
3use super::custom::CustomExpr;
4use super::query::QueryStmt;
5use super::value::Value;
6
7/// An expression in a SQL statement.
8#[derive(Debug, Clone)]
9pub enum Expr {
10    /// Literal value.
11    Value(Value),
12
13    /// Column reference.
14    Field(FieldRef),
15
16    /// Binary operation: `left op right`.
17    Binary {
18        left: Box<Expr>,
19        op: BinaryOp,
20        right: Box<Expr>,
21    },
22
23    /// Unary operation: `-expr`, `NOT expr`.
24    Unary { op: UnaryOp, expr: Box<Expr> },
25
26    /// Function call: `name(args...)`.
27    Func { name: String, args: Vec<Expr> },
28
29    /// Aggregate function: `COUNT(expr)`, `SUM(DISTINCT expr) FILTER (WHERE ...)`.
30    Aggregate(AggregationDef),
31
32    /// Type cast: `expr::type` (PG) or `CAST(expr AS type)`.
33    Cast { expr: Box<Expr>, to_type: String },
34
35    /// CASE WHEN ... THEN ... ELSE ... END.
36    Case(CaseDef),
37
38    /// Window function: `expr OVER (PARTITION BY ... ORDER BY ... frame)`.
39    Window(WindowDef),
40
41    /// EXISTS (subquery).
42    Exists(Box<QueryStmt>),
43
44    /// Scalar subquery.
45    SubQuery(Box<QueryStmt>),
46
47    /// ARRAY(subquery).
48    ArraySubQuery(Box<QueryStmt>),
49
50    /// Collation override: `expr COLLATE "name"`.
51    Collate { expr: Box<Expr>, collation: String },
52
53    /// Raw SQL with parameters (escape hatch).
54    Raw { sql: String, params: Vec<Value> },
55
56    /// User-defined expression (extension point).
57    Custom(Box<dyn CustomExpr>),
58}
59
60impl Expr {
61    /// Column reference: `table.field`.
62    pub fn field(table: &str, name: &str) -> Self {
63        Expr::Field(FieldRef::new(table, name))
64    }
65
66    /// Literal value.
67    pub fn value(val: impl Into<Value>) -> Self {
68        Expr::Value(val.into())
69    }
70
71    /// Raw SQL expression (no parameters).
72    pub fn raw(sql: impl Into<String>) -> Self {
73        Expr::Raw {
74            sql: sql.into(),
75            params: vec![],
76        }
77    }
78
79    /// Function call: `name(args...)`.
80    pub fn func(name: impl Into<String>, args: Vec<Expr>) -> Self {
81        Expr::Func {
82            name: name.into(),
83            args,
84        }
85    }
86
87    /// Type cast: `CAST(expr AS to_type)`.
88    pub fn cast(expr: Expr, to_type: impl Into<String>) -> Self {
89        Expr::Cast {
90            expr: Box::new(expr),
91            to_type: to_type.into(),
92        }
93    }
94
95    /// COUNT(expr).
96    pub fn count(expr: Expr) -> Self {
97        Expr::Aggregate(AggregationDef {
98            name: "COUNT".into(),
99            expression: Some(Box::new(expr)),
100            distinct: false,
101            filter: None,
102            args: None,
103            order_by: None,
104        })
105    }
106
107    /// COUNT(*).
108    pub fn count_all() -> Self {
109        Expr::Aggregate(AggregationDef {
110            name: "COUNT".into(),
111            expression: None,
112            distinct: false,
113            filter: None,
114            args: None,
115            order_by: None,
116        })
117    }
118
119    /// SUM(expr).
120    pub fn sum(expr: Expr) -> Self {
121        Expr::Aggregate(AggregationDef {
122            name: "SUM".into(),
123            expression: Some(Box::new(expr)),
124            distinct: false,
125            filter: None,
126            args: None,
127            order_by: None,
128        })
129    }
130
131    /// AVG(expr).
132    pub fn avg(expr: Expr) -> Self {
133        Expr::Aggregate(AggregationDef {
134            name: "AVG".into(),
135            expression: Some(Box::new(expr)),
136            distinct: false,
137            filter: None,
138            args: None,
139            order_by: None,
140        })
141    }
142
143    /// MIN(expr).
144    pub fn min(expr: Expr) -> Self {
145        Expr::Aggregate(AggregationDef {
146            name: "MIN".into(),
147            expression: Some(Box::new(expr)),
148            distinct: false,
149            filter: None,
150            args: None,
151            order_by: None,
152        })
153    }
154
155    /// MAX(expr).
156    pub fn max(expr: Expr) -> Self {
157        Expr::Aggregate(AggregationDef {
158            name: "MAX".into(),
159            expression: Some(Box::new(expr)),
160            distinct: false,
161            filter: None,
162            args: None,
163            order_by: None,
164        })
165    }
166
167    /// EXISTS (subquery).
168    pub fn exists(query: QueryStmt) -> Self {
169        Expr::Exists(Box::new(query))
170    }
171
172    /// Scalar subquery.
173    pub fn subquery(query: QueryStmt) -> Self {
174        Expr::SubQuery(Box::new(query))
175    }
176
177    /// Collation override: `expr COLLATE "name"`.
178    pub fn collate(self, collation: impl Into<String>) -> Self {
179        Expr::Collate {
180            expr: Box::new(self),
181            collation: collation.into(),
182        }
183    }
184}
185
186impl From<Value> for Expr {
187    fn from(v: Value) -> Self {
188        Expr::Value(v)
189    }
190}
191
192impl From<FieldRef> for Expr {
193    fn from(f: FieldRef) -> Self {
194        Expr::Field(f)
195    }
196}
197
198/// Binary operators.
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum BinaryOp {
201    Add,
202    Sub,
203    Mul,
204    Div,
205    Mod,
206    BitwiseAnd,
207    BitwiseOr,
208    ShiftLeft,
209    ShiftRight,
210    Concat,
211}
212
213/// Unary operators.
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub enum UnaryOp {
216    Neg,
217    Not,
218    BitwiseNot,
219}
220
221/// Aggregate function definition.
222#[derive(Debug, Clone)]
223pub struct AggregationDef {
224    pub name: String,
225    pub expression: Option<Box<Expr>>,
226    pub distinct: bool,
227    pub filter: Option<Conditions>,
228    pub args: Option<Vec<Expr>>,
229    pub order_by: Option<Vec<OrderByDef>>,
230}
231
232impl AggregationDef {
233    pub fn new(name: impl Into<String>, expr: Expr) -> Self {
234        Self {
235            name: name.into(),
236            expression: Some(Box::new(expr)),
237            distinct: false,
238            filter: None,
239            args: None,
240            order_by: None,
241        }
242    }
243
244    pub fn count_all() -> Self {
245        Self {
246            name: "COUNT".into(),
247            expression: None,
248            distinct: false,
249            filter: None,
250            args: None,
251            order_by: None,
252        }
253    }
254
255    pub fn distinct(mut self) -> Self {
256        self.distinct = true;
257        self
258    }
259
260    pub fn filter(mut self, cond: Conditions) -> Self {
261        self.filter = Some(cond);
262        self
263    }
264
265    pub fn order_by(mut self, order: Vec<OrderByDef>) -> Self {
266        self.order_by = Some(order);
267        self
268    }
269}
270
271/// CASE expression.
272#[derive(Debug, Clone)]
273pub struct CaseDef {
274    pub cases: Vec<WhenClause>,
275    pub default: Option<Box<Expr>>,
276}
277
278/// WHEN condition THEN result.
279#[derive(Debug, Clone)]
280pub struct WhenClause {
281    pub condition: Conditions,
282    pub result: Expr,
283}
284
285/// Window function definition.
286#[derive(Debug, Clone)]
287pub struct WindowDef {
288    pub expression: Box<Expr>,
289    pub partition_by: Option<Vec<Expr>>,
290    pub order_by: Option<Vec<OrderByDef>>,
291    pub frame: Option<WindowFrameDef>,
292}
293
294/// Window frame specification.
295#[derive(Debug, Clone)]
296pub struct WindowFrameDef {
297    pub frame_type: WindowFrameType,
298    pub start: WindowFrameBound,
299    pub end: Option<WindowFrameBound>,
300}
301
302/// Window frame type.
303#[derive(Debug, Clone, Copy, PartialEq, Eq)]
304pub enum WindowFrameType {
305    Rows,
306    Range,
307    Groups,
308}
309
310/// Window frame bound.
311#[derive(Debug, Clone, PartialEq, Eq)]
312pub enum WindowFrameBound {
313    CurrentRow,
314    Preceding(Option<u64>),
315    Following(Option<u64>),
316}