1use serde::{Deserialize, Serialize};
2use crate::ast::{AggregateFunc, Cage, Condition, ModKind, Value};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6pub enum BinaryOp {
7 Concat,
9 Add,
11 Sub,
13 Mul,
15 Div,
17 Rem,
19}
20
21impl std::fmt::Display for BinaryOp {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 match self {
24 BinaryOp::Concat => write!(f, "||"),
25 BinaryOp::Add => write!(f, "+"),
26 BinaryOp::Sub => write!(f, "-"),
27 BinaryOp::Mul => write!(f, "*"),
28 BinaryOp::Div => write!(f, "/"),
29 BinaryOp::Rem => write!(f, "%"),
30 }
31 }
32}
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub enum Expr {
37 Star,
39 Named(String),
41 Aliased { name: String, alias: String },
43 Aggregate {
45 col: String,
46 func: AggregateFunc,
47 distinct: bool,
49 filter: Option<Vec<Condition>>,
51 alias: Option<String>,
52 },
53 Cast {
55 expr: Box<Expr>,
56 target_type: String,
57 alias: Option<String>,
58 },
59 Def {
61 name: String,
62 data_type: String,
63 constraints: Vec<Constraint>,
64 },
65 Mod {
67 kind: ModKind,
68 col: Box<Expr>,
69 },
70 Window {
72 name: String,
73 func: String,
74 params: Vec<Value>,
75 partition: Vec<String>,
76 order: Vec<Cage>,
77 frame: Option<WindowFrame>,
78 },
79 Case {
81 when_clauses: Vec<(Condition, Box<Expr>)>,
83 else_value: Option<Box<Expr>>,
85 alias: Option<String>,
87 },
88 JsonAccess {
90 column: String,
92 path_segments: Vec<(String, bool)>,
96 alias: Option<String>,
98 },
99 FunctionCall {
101 name: String,
103 args: Vec<Expr>,
105 alias: Option<String>,
107 },
108 SpecialFunction {
111 name: String,
113 args: Vec<(Option<String>, Box<Expr>)>,
116 alias: Option<String>,
118 },
119 Binary {
121 left: Box<Expr>,
122 op: BinaryOp,
123 right: Box<Expr>,
124 alias: Option<String>,
125 },
126}
127
128impl std::fmt::Display for Expr {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 match self {
131 Expr::Star => write!(f, "*"),
132 Expr::Named(name) => write!(f, "{}", name),
133 Expr::Aliased { name, alias } => write!(f, "{} AS {}", name, alias),
134 Expr::Aggregate { col, func, distinct, filter, alias } => {
135 if *distinct {
136 write!(f, "{}(DISTINCT {})", func, col)?;
137 } else {
138 write!(f, "{}({})", func, col)?;
139 }
140 if let Some(conditions) = filter {
141 write!(f, " FILTER (WHERE {})", conditions.iter().map(|c| c.to_string()).collect::<Vec<_>>().join(" AND "))?;
142 }
143 if let Some(a) = alias {
144 write!(f, " AS {}", a)?;
145 }
146 Ok(())
147 }
148 Expr::Cast { expr, target_type, alias } => {
149 write!(f, "{}::{}", expr, target_type)?;
150 if let Some(a) = alias {
151 write!(f, " AS {}", a)?;
152 }
153 Ok(())
154 }
155 Expr::Def {
156 name,
157 data_type,
158 constraints,
159 } => {
160 write!(f, "{}:{}", name, data_type)?;
161 for c in constraints {
162 write!(f, "^{}", c)?;
163 }
164 Ok(())
165 }
166 Expr::Mod { kind, col } => match kind {
167 ModKind::Add => write!(f, "+{}", col),
168 ModKind::Drop => write!(f, "-{}", col),
169 },
170 Expr::Window { name, func, params, partition, order, frame } => {
171 write!(f, "{}:{}(", name, func)?;
172 for (i, p) in params.iter().enumerate() {
173 if i > 0 { write!(f, ", ")?; }
174 write!(f, "{}", p)?;
175 }
176 write!(f, ")")?;
177
178 if !partition.is_empty() {
180 write!(f, "{{Part=")?;
181 for (i, p) in partition.iter().enumerate() {
182 if i > 0 { write!(f, ",")?; }
183 write!(f, "{}", p)?;
184 }
185 if let Some(fr) = frame {
186 write!(f, ", Frame={:?}", fr)?; }
188 write!(f, "}}")?;
189 } else if frame.is_some() {
190 write!(f, "{{Frame={:?}}}", frame.as_ref().unwrap())?;
191 }
192
193 for _cage in order {
195 }
197 Ok(())
198 }
199 Expr::Case { when_clauses, else_value, alias } => {
200 write!(f, "CASE")?;
201 for (cond, val) in when_clauses {
202 write!(f, " WHEN {} THEN {}", cond.left, val)?;
203 }
204 if let Some(e) = else_value {
205 write!(f, " ELSE {}", e)?;
206 }
207 write!(f, " END")?;
208 if let Some(a) = alias {
209 write!(f, " AS {}", a)?;
210 }
211 Ok(())
212 }
213 Expr::JsonAccess { column, path_segments, alias } => {
214 write!(f, "{}", column)?;
215 for (path, as_text) in path_segments {
216 let op = if *as_text { "->>" } else { "->" };
217 if path.parse::<i64>().is_ok() {
220 write!(f, "{}{}", op, path)?;
221 } else {
222 write!(f, "{}'{}'", op, path)?;
223 }
224 }
225 if let Some(a) = alias {
226 write!(f, " AS {}", a)?;
227 }
228 Ok(())
229 }
230 Expr::FunctionCall { name, args, alias } => {
231 let args_str: Vec<String> = args.iter().map(|a| a.to_string()).collect();
232 write!(f, "{}({})", name.to_uppercase(), args_str.join(", "))?;
233 if let Some(a) = alias {
234 write!(f, " AS {}", a)?;
235 }
236 Ok(())
237 }
238 Expr::SpecialFunction { name, args, alias } => {
239 write!(f, "{}(", name.to_uppercase())?;
240 for (i, (keyword, expr)) in args.iter().enumerate() {
241 if i > 0 { write!(f, " ")?; }
242 if let Some(kw) = keyword {
243 write!(f, "{} ", kw)?;
244 }
245 write!(f, "{}", expr)?;
246 }
247 write!(f, ")")?;
248 if let Some(a) = alias {
249 write!(f, " AS {}", a)?;
250 }
251 Ok(())
252 }
253 Expr::Binary { left, op, right, alias } => {
254 write!(f, "({} {} {})", left, op, right)?;
255 if let Some(a) = alias {
256 write!(f, " AS {}", a)?;
257 }
258 Ok(())
259 }
260 }
261 }
262}
263
264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
266pub enum Constraint {
267 PrimaryKey,
268 Unique,
269 Nullable,
270 Default(String),
272 Check(Vec<String>),
274 Comment(String),
276 Generated(ColumnGeneration),
278}
279
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
282pub enum ColumnGeneration {
283 Stored(String),
285 Virtual(String),
287}
288
289#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
291pub enum WindowFrame {
292 Rows { start: FrameBound, end: FrameBound },
294 Range { start: FrameBound, end: FrameBound },
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
300pub enum FrameBound {
301 UnboundedPreceding,
302 Preceding(i32),
303 CurrentRow,
304 Following(i32),
305 UnboundedFollowing,
306}
307
308impl std::fmt::Display for Constraint {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 match self {
311 Constraint::PrimaryKey => write!(f, "pk"),
312 Constraint::Unique => write!(f, "uniq"),
313 Constraint::Nullable => write!(f, "?"),
314 Constraint::Default(val) => write!(f, "={}", val),
315 Constraint::Check(vals) => write!(f, "check({})", vals.join(",")),
316 Constraint::Comment(text) => write!(f, "comment(\"{}\")", text),
317 Constraint::Generated(generation) => match generation {
318 ColumnGeneration::Stored(expr) => write!(f, "gen({})", expr),
319 ColumnGeneration::Virtual(expr) => write!(f, "vgen({})", expr),
320 },
321 }
322 }
323}
324
325#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
327pub struct IndexDef {
328 pub name: String,
330 pub table: String,
332 pub columns: Vec<String>,
334 pub unique: bool,
336}
337
338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
340pub enum TableConstraint {
341 Unique(Vec<String>),
343 PrimaryKey(Vec<String>),
345}