1use super::base::{parse_identifier, parse_operator, parse_value};
2use super::expressions::parse_expression;
3use crate::ast::*;
4use nom::{
5 IResult, Parser,
6 branch::alt,
7 bytes::complete::tag_no_case,
8 character::complete::{char, digit1, multispace0, multispace1},
9 combinator::{map, opt, value},
10 multi::{many0, separated_list0, separated_list1},
11 sequence::{delimited, preceded},
12};
13
14pub fn parse_fields_clause(input: &str) -> IResult<&str, Vec<Expr>> {
16 let (input, _) = tag_no_case("fields").parse(input)?;
17 let (input, _) = multispace1(input)?;
18
19 alt((
20 map(char('*'), |_| vec![Expr::Star]),
22 parse_column_list,
23 ))
24 .parse(input)
25}
26
27pub fn parse_column_list(input: &str) -> IResult<&str, Vec<Expr>> {
30 let mut columns = Vec::new();
31 let mut current_input = input;
32
33 loop {
34 let (remaining, col) = parse_single_column(current_input)?;
35 columns.push(col);
36 current_input = remaining;
37
38 let (remaining, _) = multispace0(current_input)?;
40
41 if remaining.starts_with(',') {
42 let (remaining, _) = char(',')(remaining)?;
44 let (remaining, _) = multispace0(remaining)?;
45 current_input = remaining;
46 } else {
47 current_input = remaining;
49 break;
50 }
51 }
52
53 if columns.is_empty() {
54 Err(nom::Err::Error(nom::error::Error::new(
55 input,
56 nom::error::ErrorKind::SeparatedList,
57 )))
58 } else {
59 Ok((current_input, columns))
60 }
61}
62
63pub fn parse_single_column(input: &str) -> IResult<&str, Expr> {
65 let (input, mut expr) = parse_expression(input)?;
66 let (input, _) = multispace0(input)?;
67
68 let (input, alias) =
69 opt(preceded((tag_no_case("as"), multispace1), parse_identifier)).parse(input)?;
70
71 if let Some(a) = alias {
72 expr = match expr {
85 Expr::Named(n) => Expr::Aliased {
86 name: n,
87 alias: a.to_string(),
88 },
89 Expr::FunctionCall { name, args, .. } => Expr::FunctionCall {
90 name,
91 args,
92 alias: Some(a.to_string()),
93 },
94 Expr::JsonAccess {
95 column,
96 path_segments,
97 ..
98 } => Expr::JsonAccess {
99 column,
100 path_segments,
101 alias: Some(a.to_string()),
102 },
103 Expr::Case {
104 when_clauses,
105 else_value,
106 ..
107 } => Expr::Case {
108 when_clauses,
109 else_value,
110 alias: Some(a.to_string()),
111 },
112 Expr::Aggregate {
113 col,
114 func,
115 distinct,
116 filter,
117 ..
118 } => Expr::Aggregate {
119 col,
120 func,
121 distinct,
122 filter,
123 alias: Some(a.to_string()),
124 },
125 Expr::Cast {
126 expr: inner,
127 target_type,
128 ..
129 } => Expr::Cast {
130 expr: inner,
131 target_type,
132 alias: Some(a.to_string()),
133 },
134 _ => expr,
135 };
136 }
137
138 Ok((input, expr))
139}
140
141pub fn parse_where_clause(input: &str) -> IResult<&str, Vec<Cage>> {
143 let (input, _) = tag_no_case("where").parse(input)?;
144 let (input, _) = multispace1(input)?;
145
146 let (input, conditions) = parse_conditions(input)?;
147
148 Ok((
149 input,
150 vec![Cage {
151 kind: CageKind::Filter,
152 conditions,
153 logical_op: LogicalOp::And, }],
155 ))
156}
157
158pub fn parse_having_clause(input: &str) -> IResult<&str, Vec<Condition>> {
161 let (input, _) = tag_no_case("having").parse(input)?;
162 let (input, _) = multispace1(input)?;
163
164 let (input, conditions) = parse_conditions(input)?;
165
166 Ok((input, conditions))
167}
168
169pub fn parse_conditions(input: &str) -> IResult<&str, Vec<Condition>> {
171 let (input, first) = parse_condition(input)?;
172 let (input, rest) = many0(preceded(
174 (
175 multispace0,
176 alt((tag_no_case("and"), tag_no_case("or"))),
177 multispace1,
178 ),
179 parse_condition,
180 ))
181 .parse(input)?;
182
183 let mut conditions = vec![first];
184 conditions.extend(rest);
185 Ok((input, conditions))
186}
187
188pub fn parse_condition(input: &str) -> IResult<&str, Condition> {
190 if let Ok((input, _)) = tag_no_case::<_, _, nom::error::Error<&str>>("not exists")(input) {
192 let (input, _) = multispace0(input)?;
193 let (input, _) = char('(').parse(input)?;
194 let (input, _) = multispace0(input)?;
195 let (input, subquery) = super::parse_root(input)?;
196 let (input, _) = multispace0(input)?;
197 let (input, _) = char(')').parse(input)?;
198 return Ok((
199 input,
200 Condition {
201 left: Expr::Named("".to_string()),
202 op: Operator::NotExists,
203 value: Value::Subquery(Box::new(subquery)),
204 is_array_unnest: false,
205 },
206 ));
207 }
208 if let Ok((input, _)) = tag_no_case::<_, _, nom::error::Error<&str>>("exists")(input) {
209 let (input, _) = multispace0(input)?;
210 let (input, _) = char('(').parse(input)?;
211 let (input, _) = multispace0(input)?;
212 let (input, subquery) = super::parse_root(input)?;
213 let (input, _) = multispace0(input)?;
214 let (input, _) = char(')').parse(input)?;
215 return Ok((
216 input,
217 Condition {
218 left: Expr::Named("".to_string()),
219 op: Operator::Exists,
220 value: Value::Subquery(Box::new(subquery)),
221 is_array_unnest: false,
222 },
223 ));
224 }
225
226 let (input, left_expr) = parse_expression(input)?;
228 let (input, _) = multispace0(input)?;
229
230 let (input, op) = parse_operator(input)?;
231 let (input, _) = multispace0(input)?;
232
233 let (input, value) = if matches!(op, Operator::IsNull | Operator::IsNotNull) {
234 (input, Value::Null)
235 } else if matches!(op, Operator::Between | Operator::NotBetween) {
236 let (input, min_val) = parse_value(input)?;
237 let (input, _) = multispace1(input)?;
238 let (input, _) = tag_no_case("and").parse(input)?;
239 let (input, _) = multispace1(input)?;
240 let (input, max_val) = parse_value(input)?;
241 (input, Value::Array(vec![min_val, max_val]))
243 } else if matches!(op, Operator::In | Operator::NotIn) {
244 let (input, _) = char('(').parse(input)?;
245 let (input, _) = multispace0(input)?;
246 let (input, values) =
247 separated_list0((multispace0, char(','), multispace0), parse_value).parse(input)?;
248 let (input, _) = multispace0(input)?;
249 let (input, _) = char(')').parse(input)?;
250 (input, Value::Array(values))
251 } else if let Ok((i, val)) = parse_value(input) {
252 (i, val)
253 } else {
254 let (i, col_name) = parse_identifier(input)?;
255 (i, Value::Column(col_name.to_string()))
256 };
257
258 Ok((
259 input,
260 Condition {
261 left: left_expr,
262 op,
263 value,
264 is_array_unnest: false,
265 },
266 ))
267}
268
269pub fn parse_order_by_clause(input: &str) -> IResult<&str, Vec<Cage>> {
271 let (input, _) = tag_no_case("order").parse(input)?;
272 let (input, _) = multispace1(input)?;
273 let (input, _) = tag_no_case("by").parse(input)?;
274 let (input, _) = multispace1(input)?;
275
276 let (input, sorts) =
277 separated_list1((multispace0, char(','), multispace0), parse_sort_column).parse(input)?;
278
279 Ok((input, sorts))
280}
281
282pub fn parse_sort_column(input: &str) -> IResult<&str, Cage> {
284 let (input, expr) = parse_expression(input)?;
285 let (input, _) = multispace0(input)?;
286
287 let (input, order) = opt(alt((
288 value(SortOrder::Desc, tag_no_case("desc")),
289 value(SortOrder::Asc, tag_no_case("asc")),
290 )))
291 .parse(input)?;
292
293 Ok((
294 input,
295 Cage {
296 kind: CageKind::Sort(order.unwrap_or(SortOrder::Asc)),
297 conditions: vec![Condition {
298 left: expr,
299 op: Operator::Eq,
300 value: Value::Null,
301 is_array_unnest: false,
302 }],
303 logical_op: LogicalOp::And,
304 },
305 ))
306}
307
308pub fn parse_limit_clause(input: &str) -> IResult<&str, Cage> {
310 let (input, _) = tag_no_case("limit").parse(input)?;
311 let (input, _) = multispace1(input)?;
312 let (input, n) = digit1(input)?;
313
314 Ok((
315 input,
316 Cage {
317 kind: CageKind::Limit(n.parse().unwrap_or(0)),
318 conditions: vec![],
319 logical_op: LogicalOp::And,
320 },
321 ))
322}
323
324pub fn parse_offset_clause(input: &str) -> IResult<&str, Cage> {
326 let (input, _) = tag_no_case("offset").parse(input)?;
327 let (input, _) = multispace1(input)?;
328 let (input, n) = digit1(input)?;
329
330 Ok((
331 input,
332 Cage {
333 kind: CageKind::Offset(n.parse().unwrap_or(0)),
334 conditions: vec![],
335 logical_op: LogicalOp::And,
336 },
337 ))
338}
339
340pub fn parse_distinct_on(input: &str) -> IResult<&str, Vec<String>> {
343 let (input, _) = tag_no_case("distinct").parse(input)?;
344 let (input, _) = multispace1(input)?;
345 let (input, _) = tag_no_case("on").parse(input)?;
346 let (input, _) = multispace0(input)?;
347
348 let (input, cols) = delimited(
349 char('('),
350 separated_list1(
351 (multispace0, char(','), multispace0),
352 map(parse_identifier, |s| s.to_string()),
353 ),
354 char(')'),
355 )
356 .parse(input)?;
357
358 Ok((input, cols))
359}