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