1use crate::ast::*;
2use crate::lexer::lex;
3use crate::token::Token;
4
5const MAX_NESTING_DEPTH: usize = 64;
9
10#[derive(Debug)]
12pub enum ParseError {
13 Lex { message: String, position: usize },
15 UnexpectedToken { expected: String, got: String },
17 NestingDepthExceeded { max: usize },
19 Unsupported { feature: String },
21 Syntax { message: String },
23}
24
25impl ParseError {
26 pub fn message(&self) -> String {
28 self.to_string()
29 }
30}
31
32impl std::fmt::Display for ParseError {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 Self::Lex { message, position } => write!(f, "at position {position}: {message}"),
36 Self::UnexpectedToken { expected, got } => {
37 write!(f, "expected {expected}, got {got}")
38 }
39 Self::NestingDepthExceeded { max } => {
40 write!(f, "query nesting depth exceeds maximum of {max}")
41 }
42 Self::Unsupported { feature } => write!(f, "{feature}"),
43 Self::Syntax { message } => write!(f, "{message}"),
44 }
45 }
46}
47
48impl std::error::Error for ParseError {}
49
50fn token_to_scalar_fn(tok: &Token) -> ScalarFn {
51 match tok {
52 Token::Upper => ScalarFn::Upper,
53 Token::Lower => ScalarFn::Lower,
54 Token::Length => ScalarFn::Length,
55 Token::Trim => ScalarFn::Trim,
56 Token::Substring => ScalarFn::Substring,
57 Token::Concat => ScalarFn::Concat,
58 Token::Abs => ScalarFn::Abs,
59 Token::Round => ScalarFn::Round,
60 Token::Ceil => ScalarFn::Ceil,
61 Token::Floor => ScalarFn::Floor,
62 Token::Sqrt => ScalarFn::Sqrt,
63 Token::Pow => ScalarFn::Pow,
64 Token::Now => ScalarFn::Now,
65 Token::Extract => ScalarFn::Extract,
66 Token::DateAdd => ScalarFn::DateAdd,
67 Token::DateDiff => ScalarFn::DateDiff,
68 _ => unreachable!(),
69 }
70}
71
72struct Parser {
73 tokens: Vec<Token>,
74 pos: usize,
75 depth: usize,
76}
77
78pub fn parse(input: &str) -> Result<Statement, ParseError> {
79 let tokens = lex(input).map_err(|e| ParseError::Lex {
80 message: e.message,
81 position: e.position,
82 })?;
83 let mut parser = Parser {
84 tokens,
85 pos: 0,
86 depth: 0,
87 };
88 let stmt = parser.parse_statement()?;
89 if !matches!(parser.peek(), Token::Eof) {
95 return Err(ParseError::Syntax {
96 message: format!(
97 "unexpected trailing token: {}",
98 parser.peek().display_name()
99 ),
100 });
101 }
102 Ok(stmt)
103}
104
105fn substitute_projection_aliases(expr: Expr, fields: &[ProjectionField]) -> Expr {
110 match expr {
111 Expr::Field(ref name) => {
112 for f in fields {
113 if f.alias.as_deref() == Some(name.as_str()) {
114 return f.expr.clone();
115 }
116 }
117 expr
118 }
119 Expr::BinaryOp(l, op, r) => Expr::BinaryOp(
120 Box::new(substitute_projection_aliases(*l, fields)),
121 op,
122 Box::new(substitute_projection_aliases(*r, fields)),
123 ),
124 Expr::UnaryOp(op, inner) => {
125 Expr::UnaryOp(op, Box::new(substitute_projection_aliases(*inner, fields)))
126 }
127 Expr::Coalesce(l, r) => Expr::Coalesce(
128 Box::new(substitute_projection_aliases(*l, fields)),
129 Box::new(substitute_projection_aliases(*r, fields)),
130 ),
131 Expr::InList {
132 expr: e,
133 list,
134 negated,
135 } => Expr::InList {
136 expr: Box::new(substitute_projection_aliases(*e, fields)),
137 list: list
138 .into_iter()
139 .map(|i| substitute_projection_aliases(i, fields))
140 .collect(),
141 negated,
142 },
143 Expr::ScalarFunc(f, args) => Expr::ScalarFunc(
144 f,
145 args.into_iter()
146 .map(|a| substitute_projection_aliases(a, fields))
147 .collect(),
148 ),
149 other => other,
150 }
151}
152
153impl Parser {
154 fn peek(&self) -> &Token {
155 &self.tokens[self.pos]
156 }
157
158 fn advance(&mut self) -> Token {
159 let t = self.tokens[self.pos].clone();
160 self.pos += 1;
161 t
162 }
163
164 fn expect(&mut self, expected: &Token) -> Result<(), ParseError> {
165 let t = self.advance();
166 if &t == expected {
167 Ok(())
168 } else {
169 Err(ParseError::UnexpectedToken {
170 expected: expected.display_name(),
171 got: t.display_name(),
172 })
173 }
174 }
175
176 fn unexpected(&self, expected: &str, got: &Token) -> ParseError {
178 ParseError::UnexpectedToken {
179 expected: expected.into(),
180 got: got.display_name(),
181 }
182 }
183
184 fn parse_statement(&mut self) -> Result<Statement, ParseError> {
185 self.depth += 1;
186 if self.depth > MAX_NESTING_DEPTH {
187 self.depth -= 1;
188 return Err(ParseError::NestingDepthExceeded {
189 max: MAX_NESTING_DEPTH,
190 });
191 }
192 if matches!(self.peek(), Token::Explain) {
193 self.advance();
194 let inner = self.parse_statement()?;
195 self.depth -= 1;
196 return Ok(Statement::Explain(Box::new(inner)));
197 }
198 let stmt = match self.peek() {
199 Token::Insert => self.parse_insert(),
200 Token::Upsert => self.parse_upsert(),
201 Token::Type => self.parse_create_type(),
202 Token::Alter => self.parse_alter_table(),
203 Token::Drop => self.parse_drop_or_drop_view(),
204 Token::Materialized => self.parse_create_view(),
205 Token::Refresh => self.parse_refresh_view(),
206 Token::Count | Token::Avg | Token::Sum | Token::Min | Token::Max => {
207 self.parse_aggregate_query()
208 }
209 Token::Ident(_) => self.parse_query_or_mutation(),
210 _ => Err(self.unexpected("statement", self.peek())),
211 }?;
212 let result = self.maybe_parse_union(stmt);
214 self.depth -= 1;
215 result
216 }
217
218 fn parse_query_or_mutation(&mut self) -> Result<Statement, ParseError> {
219 let source = match self.advance() {
220 Token::Ident(name) => name,
221 t => {
222 return Err(ParseError::UnexpectedToken {
223 expected: "type name".into(),
224 got: t.display_name(),
225 })
226 }
227 };
228 let alias = self.try_parse_alias();
229 let joins = self.parse_joins()?;
230
231 let mut filter = None;
235 let mut order = None;
236 let mut limit = None;
237 let mut offset = None;
238 let mut projection = None;
239 let mut distinct = false;
240 let mut group_by = None;
241
242 loop {
243 match self.peek() {
244 Token::Distinct => {
245 self.advance();
246 distinct = true;
247 }
248 Token::Group => {
249 self.advance();
250 group_by = Some(self.parse_group_by()?);
251 }
252 Token::Filter => {
253 self.advance();
254 filter = Some(self.parse_expr()?);
255 }
256 Token::Order => {
257 self.advance();
258 order = Some(self.parse_order()?);
259 }
260 Token::Limit => {
261 self.advance();
262 limit = Some(self.parse_expr()?);
263 }
264 Token::Offset => {
265 self.advance();
266 offset = Some(self.parse_expr()?);
267 }
268 Token::LBrace => {
269 projection = Some(self.parse_projection()?);
270 }
271 Token::Having => {
272 self.advance();
274 let having_expr = self.parse_expr()?;
275 let group = group_by.as_mut().ok_or_else(|| ParseError::Syntax {
276 message: "having without group by".into(),
277 })?;
278 let rewritten = match projection.as_ref() {
279 Some(fields) => substitute_projection_aliases(having_expr, fields),
280 None => having_expr,
281 };
282 group.having = Some(match group.having.take() {
283 Some(existing) => {
284 Expr::BinaryOp(Box::new(existing), BinOp::And, Box::new(rewritten))
285 }
286 None => rewritten,
287 });
288 }
289 Token::Update => {
290 if !joins.is_empty() {
291 return Err(ParseError::Unsupported {
292 feature: "update on a joined query is not supported".into(),
293 });
294 }
295 self.advance();
296 let assignments = self.parse_assignments()?;
297 return Ok(Statement::UpdateQuery(UpdateExpr {
298 source,
299 filter,
300 assignments,
301 }));
302 }
303 Token::Delete => {
304 if !joins.is_empty() {
305 return Err(ParseError::Unsupported {
306 feature: "delete on a joined query is not supported".into(),
307 });
308 }
309 self.advance();
310 return Ok(Statement::DeleteQuery(DeleteExpr { source, filter }));
311 }
312 _ => break,
313 }
314 }
315
316 Ok(Statement::Query(QueryExpr {
317 source,
318 alias,
319 joins,
320 filter,
321 order,
322 limit,
323 offset,
324 projection,
325 aggregation: None,
326 distinct,
327 group_by,
328 }))
329 }
330
331 fn parse_query_tail(&mut self, source: String) -> Result<QueryExpr, ParseError> {
337 let alias = self.try_parse_alias();
338 let joins = self.parse_joins()?;
339 let mut filter = None;
340 let mut order = None;
341 let mut limit = None;
342 let mut offset = None;
343 let mut projection = None;
344 let mut distinct = false;
345 let mut group_by = None;
346
347 loop {
348 match self.peek() {
349 Token::Distinct => {
350 self.advance();
351 distinct = true;
352 }
353 Token::Group => {
354 self.advance();
355 group_by = Some(self.parse_group_by()?);
356 }
357 Token::Filter => {
358 self.advance();
359 filter = Some(self.parse_expr()?);
360 }
361 Token::Order => {
362 self.advance();
363 order = Some(self.parse_order()?);
364 }
365 Token::Limit => {
366 self.advance();
367 limit = Some(self.parse_expr()?);
368 }
369 Token::Offset => {
370 self.advance();
371 offset = Some(self.parse_expr()?);
372 }
373 Token::LBrace => {
374 projection = Some(self.parse_projection()?);
375 }
376 Token::Having => {
377 self.advance();
383 let having_expr = self.parse_expr()?;
384 let group = group_by.as_mut().ok_or_else(|| ParseError::Syntax {
385 message: "having without group by".into(),
386 })?;
387 let rewritten = match projection.as_ref() {
388 Some(fields) => substitute_projection_aliases(having_expr, fields),
389 None => having_expr,
390 };
391 group.having = Some(match group.having.take() {
392 Some(existing) => {
393 Expr::BinaryOp(Box::new(existing), BinOp::And, Box::new(rewritten))
394 }
395 None => rewritten,
396 });
397 }
398 _ => break,
399 }
400 }
401
402 Ok(QueryExpr {
403 source,
404 alias,
405 joins,
406 filter,
407 order,
408 limit,
409 offset,
410 projection,
411 aggregation: None,
412 distinct,
413 group_by,
414 })
415 }
416
417 fn try_parse_alias(&mut self) -> Option<String> {
421 if *self.peek() == Token::As {
422 self.advance();
423 if let Token::Ident(name) = self.peek().clone() {
424 self.advance();
425 return Some(name);
426 }
427 }
428 None
429 }
430
431 fn parse_joins(&mut self) -> Result<Vec<JoinClause>, ParseError> {
438 let mut joins = Vec::new();
439 loop {
440 let kind = match self.peek() {
441 Token::Join => {
442 self.advance();
443 JoinKind::Inner
444 }
445 Token::Inner => {
446 self.advance();
447 self.expect(&Token::Join)?;
448 JoinKind::Inner
449 }
450 Token::LeftKw => {
451 self.advance();
452 if *self.peek() == Token::Outer {
453 self.advance();
454 }
455 self.expect(&Token::Join)?;
456 JoinKind::LeftOuter
457 }
458 Token::RightKw => {
459 self.advance();
460 if *self.peek() == Token::Outer {
461 self.advance();
462 }
463 self.expect(&Token::Join)?;
464 JoinKind::RightOuter
465 }
466 Token::Cross => {
467 self.advance();
468 self.expect(&Token::Join)?;
469 JoinKind::Cross
470 }
471 _ => break,
472 };
473
474 let source = match self.advance() {
475 Token::Ident(name) => name,
476 t => {
477 return Err(ParseError::UnexpectedToken {
478 expected: "type name after join".into(),
479 got: t.display_name(),
480 });
481 }
482 };
483 let alias = self.try_parse_alias();
484 let on = if kind == JoinKind::Cross {
485 None
486 } else if *self.peek() == Token::On {
487 self.advance();
488 Some(self.parse_expr()?)
489 } else {
490 return Err(ParseError::Syntax {
491 message: format!("expected `on <expr>` after join {source}"),
492 });
493 };
494
495 joins.push(JoinClause {
496 kind,
497 source,
498 alias,
499 on,
500 });
501 }
502 Ok(joins)
503 }
504
505 fn parse_insert(&mut self) -> Result<Statement, ParseError> {
506 self.expect(&Token::Insert)?;
507 let target = match self.advance() {
508 Token::Ident(name) => name,
509 t => {
510 return Err(ParseError::UnexpectedToken {
511 expected: "type name".into(),
512 got: t.display_name(),
513 })
514 }
515 };
516 let assignments = self.parse_assignments()?;
517 Ok(Statement::Insert(InsertExpr {
518 target,
519 assignments,
520 }))
521 }
522
523 fn parse_upsert(&mut self) -> Result<Statement, ParseError> {
525 self.expect(&Token::Upsert)?;
526 let target = match self.advance() {
527 Token::Ident(name) => name,
528 t => {
529 return Err(ParseError::UnexpectedToken {
530 expected: "type name".into(),
531 got: t.display_name(),
532 })
533 }
534 };
535 self.expect(&Token::On)?;
536 let key_column = match self.advance() {
537 Token::DotIdent(name) => name,
538 t => {
539 return Err(ParseError::UnexpectedToken {
540 expected: ".key_column".into(),
541 got: t.display_name(),
542 })
543 }
544 };
545 let assignments = self.parse_assignments()?;
546 let on_conflict = if *self.peek() == Token::On {
547 self.advance(); self.expect(&Token::Conflict)?;
549 self.parse_assignments()?
550 } else {
551 Vec::new()
552 };
553 Ok(Statement::Upsert(UpsertExpr {
554 target,
555 key_column,
556 assignments,
557 on_conflict,
558 }))
559 }
560
561 fn parse_assignments(&mut self) -> Result<Vec<Assignment>, ParseError> {
562 self.expect(&Token::LBrace)?;
563 let mut assignments = Vec::new();
564 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
565 let field = match self.advance() {
566 Token::Ident(name) => name,
567 t => {
568 return Err(ParseError::UnexpectedToken {
569 expected: "field name".into(),
570 got: t.display_name(),
571 })
572 }
573 };
574 self.expect(&Token::Assign)?;
575 let value = self.parse_expr()?;
576 assignments.push(Assignment { field, value });
577 if *self.peek() == Token::Comma {
578 self.advance();
579 }
580 }
581 self.expect(&Token::RBrace)?;
582 Ok(assignments)
583 }
584
585 fn parse_projection(&mut self) -> Result<Vec<ProjectionField>, ParseError> {
586 self.expect(&Token::LBrace)?;
587 let mut fields = Vec::new();
588 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
589 let first = self.advance();
590 if *self.peek() == Token::Colon {
591 self.advance();
593 let alias = match first {
594 Token::Ident(name) => name,
595 _ => {
596 return Err(ParseError::Syntax {
597 message: "expected alias name".into(),
598 })
599 }
600 };
601 let expr = self.parse_expr()?;
602 fields.push(ProjectionField {
603 alias: Some(alias),
604 expr,
605 });
606 } else {
607 let expr = match first {
608 Token::Ident(name) => {
612 if let Token::DotIdent(field) = self.peek().clone() {
613 self.advance();
614 Expr::QualifiedField {
615 qualifier: name,
616 field,
617 }
618 } else {
619 Expr::Field(name)
620 }
621 }
622 Token::DotIdent(name) => Expr::Field(name),
623 Token::RowNumber | Token::Rank | Token::DenseRank => {
624 let wfunc = match first {
625 Token::RowNumber => WindowFunc::RowNumber,
626 Token::Rank => WindowFunc::Rank,
627 Token::DenseRank => WindowFunc::DenseRank,
628 _ => {
629 return Err(ParseError::Syntax {
630 message: "unexpected window function token".into(),
631 })
632 }
633 };
634 self.expect(&Token::LParen)?;
635 self.expect(&Token::RParen)?;
636 let (partition_by, order_by) = self.parse_over_clause()?;
637 Expr::Window {
638 function: wfunc,
639 args: vec![],
640 partition_by,
641 order_by,
642 }
643 }
644 Token::Count | Token::Avg | Token::Sum | Token::Min | Token::Max => {
645 let mut func = match first {
646 Token::Count => AggFunc::Count,
647 Token::Avg => AggFunc::Avg,
648 Token::Sum => AggFunc::Sum,
649 Token::Min => AggFunc::Min,
650 Token::Max => AggFunc::Max,
651 _ => {
652 return Err(ParseError::Syntax {
653 message: "unexpected aggregate token".into(),
654 })
655 }
656 };
657 self.expect(&Token::LParen)?;
658 if func == AggFunc::Count && *self.peek() == Token::Star {
660 self.advance();
661 self.expect(&Token::RParen)?;
662 if *self.peek() == Token::Over {
664 let (partition_by, order_by) = self.parse_over_clause()?;
665 Expr::Window {
666 function: WindowFunc::Count,
667 args: vec![Expr::Field("*".into())],
668 partition_by,
669 order_by,
670 }
671 } else {
672 Expr::FunctionCall(
673 AggFunc::Count,
674 Box::new(Expr::Field("*".into())),
675 )
676 }
677 } else {
678 if func == AggFunc::Count && *self.peek() == Token::Distinct {
680 self.advance();
681 func = AggFunc::CountDistinct;
682 }
683 let inner = self.parse_expr()?;
684 self.expect(&Token::RParen)?;
685 if *self.peek() == Token::Over {
687 let wfunc =
688 match func {
689 AggFunc::Count => WindowFunc::Count,
690 AggFunc::Avg => WindowFunc::Avg,
691 AggFunc::Sum => WindowFunc::Sum,
692 AggFunc::Min => WindowFunc::Min,
693 AggFunc::Max => WindowFunc::Max,
694 _ => return Err(ParseError::Unsupported {
695 feature:
696 "count(distinct ...) over (...) is not supported"
697 .into(),
698 }),
699 };
700 let (partition_by, order_by) = self.parse_over_clause()?;
701 Expr::Window {
702 function: wfunc,
703 args: vec![inner],
704 partition_by,
705 order_by,
706 }
707 } else {
708 Expr::FunctionCall(func, Box::new(inner))
709 }
710 }
711 }
712 Token::Upper
713 | Token::Lower
714 | Token::Length
715 | Token::Trim
716 | Token::Substring
717 | Token::Concat
718 | Token::Abs
719 | Token::Round
720 | Token::Ceil
721 | Token::Floor
722 | Token::Sqrt
723 | Token::Pow
724 | Token::Now
725 | Token::Extract
726 | Token::DateAdd
727 | Token::DateDiff => {
728 let func = token_to_scalar_fn(&first);
729 self.expect(&Token::LParen)?;
730 let mut args = Vec::new();
731 while !matches!(self.peek(), Token::RParen | Token::Eof) {
732 args.push(self.parse_expr()?);
733 if *self.peek() == Token::Comma {
734 self.advance();
735 }
736 }
737 self.expect(&Token::RParen)?;
738 Expr::ScalarFunc(func, args)
739 }
740 Token::Cast => {
741 self.expect(&Token::LParen)?;
742 let inner = self.parse_expr()?;
743 self.expect(&Token::Comma)?;
744 let cast_type = self.parse_cast_type()?;
745 self.expect(&Token::RParen)?;
746 Expr::Cast(Box::new(inner), cast_type)
747 }
748 Token::Case => {
749 let mut whens = Vec::new();
750 while *self.peek() == Token::When {
751 self.advance();
752 let condition = self.parse_expr()?;
753 self.expect(&Token::Then)?;
754 let result = self.parse_expr()?;
755 whens.push((Box::new(condition), Box::new(result)));
756 }
757 let else_expr = if *self.peek() == Token::Else {
758 self.advance();
759 Some(Box::new(self.parse_expr()?))
760 } else {
761 None
762 };
763 self.expect(&Token::End)?;
764 Expr::Case { whens, else_expr }
765 }
766 _ => {
767 return Err(ParseError::UnexpectedToken {
768 expected: "field".into(),
769 got: first.display_name(),
770 })
771 }
772 };
773 fields.push(ProjectionField { alias: None, expr });
774 }
775 if *self.peek() == Token::Comma {
776 self.advance();
777 }
778 }
779 self.expect(&Token::RBrace)?;
780 Ok(fields)
781 }
782
783 fn parse_over_clause(&mut self) -> Result<(Vec<String>, Vec<OrderKey>), ParseError> {
786 self.expect(&Token::Over)?;
787 self.expect(&Token::LParen)?;
788 let mut partition_by = Vec::new();
789 let mut order_by = Vec::new();
790 if *self.peek() == Token::Partition {
791 self.advance();
792 while let Token::DotIdent(name) = self.peek() {
793 let name = name.clone();
794 self.advance();
795 partition_by.push(name);
796 if *self.peek() == Token::Comma {
797 if matches!(self.tokens.get(self.pos + 1), Some(Token::DotIdent(_))) {
801 self.advance();
802 } else {
803 break;
804 }
805 } else {
806 break;
807 }
808 }
809 }
810 if *self.peek() == Token::Order {
811 self.advance();
812 while let Token::DotIdent(name) = self.peek() {
813 let field = name.clone();
814 self.advance();
815 let descending = match self.peek() {
816 Token::Desc => {
817 self.advance();
818 true
819 }
820 Token::Asc => {
821 self.advance();
822 false
823 }
824 _ => false,
825 };
826 order_by.push(OrderKey { field, descending });
827 if *self.peek() == Token::Comma {
828 self.advance();
829 } else {
830 break;
831 }
832 }
833 }
834 self.expect(&Token::RParen)?;
835 Ok((partition_by, order_by))
836 }
837
838 fn parse_cast_type(&mut self) -> Result<CastType, ParseError> {
840 match self.advance() {
841 Token::StringLit(s) => match s.as_str() {
842 "int" | "Int" | "INT" => Ok(CastType::Int),
843 "float" | "Float" | "FLOAT" => Ok(CastType::Float),
844 "str" | "Str" | "STR" | "string" | "String" => Ok(CastType::Str),
845 "bool" | "Bool" | "BOOL" | "boolean" => Ok(CastType::Bool),
846 "datetime" | "DateTime" | "DATETIME" => Ok(CastType::DateTime),
847 other => Err(ParseError::Syntax {
848 message: format!("invalid cast type: \"{other}\""),
849 }),
850 },
851 t => Err(ParseError::UnexpectedToken {
852 expected: "string literal for cast type".into(),
853 got: t.display_name(),
854 }),
855 }
856 }
857
858 fn parse_order(&mut self) -> Result<OrderClause, ParseError> {
859 let mut keys = Vec::new();
860 loop {
861 let field = match self.advance() {
862 Token::DotIdent(name) => name,
863 t => {
864 return Err(ParseError::UnexpectedToken {
865 expected: ".field after order".into(),
866 got: t.display_name(),
867 })
868 }
869 };
870 let descending = match self.peek() {
871 Token::Desc => {
872 self.advance();
873 true
874 }
875 Token::Asc => {
876 self.advance();
877 false
878 }
879 _ => false,
880 };
881 keys.push(OrderKey { field, descending });
882 if *self.peek() == Token::Comma {
883 self.advance();
884 } else {
885 break;
886 }
887 }
888 Ok(OrderClause { keys })
889 }
890
891 fn parse_aggregate_query(&mut self) -> Result<Statement, ParseError> {
892 let mut func = match self.advance() {
893 Token::Count => AggFunc::Count,
894 Token::Avg => AggFunc::Avg,
895 Token::Sum => AggFunc::Sum,
896 Token::Min => AggFunc::Min,
897 Token::Max => AggFunc::Max,
898 t => {
899 return Err(ParseError::UnexpectedToken {
900 expected: "aggregate function".into(),
901 got: t.display_name(),
902 })
903 }
904 };
905 self.expect(&Token::LParen)?;
906 if func == AggFunc::Count && *self.peek() == Token::Distinct {
908 self.advance();
909 func = AggFunc::CountDistinct;
910 }
911 let source = match self.advance() {
912 Token::Ident(name) => name,
913 t => {
914 return Err(ParseError::UnexpectedToken {
915 expected: "type name".into(),
916 got: t.display_name(),
917 })
918 }
919 };
920 let mut query = self.parse_query_tail(source)?;
924 self.expect(&Token::RParen)?;
925
926 let mut agg_field: Option<String> = None;
933 if func != AggFunc::Count {
934 if let Some(proj) = &query.projection {
935 if proj.len() == 1 && proj[0].alias.is_none() {
936 if let Expr::Field(name) = &proj[0].expr {
937 agg_field = Some(name.clone());
938 }
939 }
940 }
941 if agg_field.is_some() {
942 query.projection = None;
943 }
944 }
945 query.aggregation = Some(AggregateExpr {
946 function: func,
947 field: agg_field,
948 });
949 Ok(Statement::Query(query))
950 }
951
952 fn parse_expr(&mut self) -> Result<Expr, ParseError> {
953 self.depth += 1;
954 if self.depth > MAX_NESTING_DEPTH {
955 self.depth -= 1;
956 return Err(ParseError::NestingDepthExceeded {
957 max: MAX_NESTING_DEPTH,
958 });
959 }
960 let result = self.parse_or_expr();
961 self.depth -= 1;
962 result
963 }
964
965 fn parse_or_expr(&mut self) -> Result<Expr, ParseError> {
966 let mut left = self.parse_and_expr()?;
967 while *self.peek() == Token::Or {
968 self.advance();
969 let right = self.parse_and_expr()?;
970 left = Expr::BinaryOp(Box::new(left), BinOp::Or, Box::new(right));
971 }
972 Ok(left)
973 }
974
975 fn parse_and_expr(&mut self) -> Result<Expr, ParseError> {
976 let mut left = self.parse_comparison()?;
977 while *self.peek() == Token::And {
978 self.advance();
979 let right = self.parse_comparison()?;
980 left = Expr::BinaryOp(Box::new(left), BinOp::And, Box::new(right));
981 }
982 Ok(left)
983 }
984
985 fn parse_comparison(&mut self) -> Result<Expr, ParseError> {
986 let left = self.parse_additive()?;
987
988 if *self.peek() == Token::Is {
990 self.advance();
991 if *self.peek() == Token::Not {
992 self.advance();
993 self.expect(&Token::Null)?;
994 return Ok(Expr::UnaryOp(UnaryOp::IsNotNull, Box::new(left)));
995 } else {
996 self.expect(&Token::Null)?;
997 return Ok(Expr::UnaryOp(UnaryOp::IsNull, Box::new(left)));
998 }
999 }
1000
1001 match self.peek() {
1004 Token::In => {
1005 self.advance();
1006 return self.parse_in_list(left, false);
1007 }
1008 Token::Like => {
1009 self.advance();
1010 let pattern = self.parse_additive()?;
1011 return Ok(Expr::BinaryOp(
1012 Box::new(left),
1013 BinOp::Like,
1014 Box::new(pattern),
1015 ));
1016 }
1017 Token::Between => {
1018 self.advance();
1019 return self.parse_between(left, false);
1020 }
1021 Token::Not => {
1022 let next = self.tokens.get(self.pos + 1);
1026 match next {
1027 Some(Token::In) => {
1028 self.advance(); self.advance(); return self.parse_in_list(left, true);
1031 }
1032 Some(Token::Like) => {
1033 self.advance(); self.advance(); let pattern = self.parse_additive()?;
1036 let like = Expr::BinaryOp(Box::new(left), BinOp::Like, Box::new(pattern));
1037 return Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(like)));
1038 }
1039 Some(Token::Between) => {
1040 self.advance(); self.advance(); return self.parse_between(left, true);
1043 }
1044 _ => {}
1045 }
1046 }
1047 _ => {}
1048 }
1049
1050 let op = match self.peek() {
1051 Token::Eq => BinOp::Eq,
1052 Token::Neq => BinOp::Neq,
1053 Token::Lt => BinOp::Lt,
1054 Token::Gt => BinOp::Gt,
1055 Token::Lte => BinOp::Lte,
1056 Token::Gte => BinOp::Gte,
1057 _ => return Ok(left),
1058 };
1059 self.advance();
1060 if *self.peek() == Token::Null {
1064 match op {
1065 BinOp::Eq => {
1066 self.advance();
1067 return Ok(Expr::UnaryOp(UnaryOp::IsNull, Box::new(left)));
1068 }
1069 BinOp::Neq => {
1070 self.advance();
1071 return Ok(Expr::UnaryOp(UnaryOp::IsNotNull, Box::new(left)));
1072 }
1073 _ => {}
1074 }
1075 }
1076 let right = self.parse_additive()?;
1077 Ok(Expr::BinaryOp(Box::new(left), op, Box::new(right)))
1078 }
1079
1080 fn parse_in_list(&mut self, expr: Expr, negated: bool) -> Result<Expr, ParseError> {
1085 self.expect(&Token::LParen)?;
1086 if let Token::Ident(_) = self.peek() {
1088 let after = self.tokens.get(self.pos + 1);
1091 let is_subquery = !matches!(after, Some(Token::Comma) | Some(Token::RParen));
1092 if is_subquery {
1093 let source = match self.advance() {
1094 Token::Ident(name) => name,
1095 _ => unreachable!(),
1096 };
1097 let subquery = self.parse_query_tail(source)?;
1098 self.expect(&Token::RParen)?;
1099 return Ok(Expr::InSubquery {
1100 expr: Box::new(expr),
1101 subquery: Box::new(subquery),
1102 negated,
1103 });
1104 }
1105 }
1106 let mut list = Vec::new();
1107 while !matches!(self.peek(), Token::RParen | Token::Eof) {
1108 list.push(self.parse_expr()?);
1109 if *self.peek() == Token::Comma {
1110 self.advance();
1111 }
1112 }
1113 self.expect(&Token::RParen)?;
1114 Ok(Expr::InList {
1115 expr: Box::new(expr),
1116 list,
1117 negated,
1118 })
1119 }
1120
1121 fn try_parse_exists_subquery(&mut self) -> Result<Option<QueryExpr>, ParseError> {
1129 if *self.peek() != Token::LParen {
1130 return Ok(None);
1131 }
1132 let after_lparen = self.tokens.get(self.pos + 1);
1136 if !matches!(after_lparen, Some(Token::Ident(_))) {
1137 return Ok(None);
1138 }
1139 self.expect(&Token::LParen)?;
1140 let source = match self.advance() {
1141 Token::Ident(name) => name,
1142 _ => unreachable!(),
1143 };
1144 let subquery = self.parse_query_tail(source)?;
1145 self.expect(&Token::RParen)?;
1146 Ok(Some(subquery))
1147 }
1148
1149 fn parse_between(&mut self, expr: Expr, negated: bool) -> Result<Expr, ParseError> {
1153 let low = self.parse_additive()?;
1154 self.expect(&Token::And)?;
1155 let high = self.parse_additive()?;
1156 if negated {
1157 Ok(Expr::BinaryOp(
1159 Box::new(Expr::BinaryOp(
1160 Box::new(expr.clone()),
1161 BinOp::Lt,
1162 Box::new(low),
1163 )),
1164 BinOp::Or,
1165 Box::new(Expr::BinaryOp(Box::new(expr), BinOp::Gt, Box::new(high))),
1166 ))
1167 } else {
1168 Ok(Expr::BinaryOp(
1170 Box::new(Expr::BinaryOp(
1171 Box::new(expr.clone()),
1172 BinOp::Gte,
1173 Box::new(low),
1174 )),
1175 BinOp::And,
1176 Box::new(Expr::BinaryOp(Box::new(expr), BinOp::Lte, Box::new(high))),
1177 ))
1178 }
1179 }
1180
1181 fn parse_group_by(&mut self) -> Result<GroupByClause, ParseError> {
1183 let mut keys = Vec::new();
1184 while let Token::DotIdent(name) = self.peek() {
1185 let name = name.clone();
1186 self.advance();
1187 keys.push(name);
1188 if *self.peek() == Token::Comma {
1189 self.advance();
1190 } else {
1191 break;
1192 }
1193 }
1194 if keys.is_empty() {
1195 return Err(ParseError::Syntax {
1196 message: "expected at least one .field after group".into(),
1197 });
1198 }
1199 let having = if *self.peek() == Token::Having {
1200 self.advance();
1201 Some(self.parse_expr()?)
1202 } else {
1203 None
1204 };
1205 Ok(GroupByClause { keys, having })
1206 }
1207
1208 fn parse_additive(&mut self) -> Result<Expr, ParseError> {
1209 let mut left = self.parse_multiplicative()?;
1210 loop {
1211 let op = match self.peek() {
1212 Token::Plus => BinOp::Add,
1213 Token::Minus => BinOp::Sub,
1214 Token::Coalesce => {
1215 self.advance();
1216 let right = self.parse_multiplicative()?;
1217 left = Expr::Coalesce(Box::new(left), Box::new(right));
1218 continue;
1219 }
1220 _ => break,
1221 };
1222 self.advance();
1223 let right = self.parse_multiplicative()?;
1224 left = Expr::BinaryOp(Box::new(left), op, Box::new(right));
1225 }
1226 Ok(left)
1227 }
1228
1229 fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
1230 let mut left = self.parse_primary()?;
1231 loop {
1232 let op = match self.peek() {
1233 Token::Star => BinOp::Mul,
1234 Token::Slash => BinOp::Div,
1235 _ => break,
1236 };
1237 self.advance();
1238 let right = self.parse_primary()?;
1239 left = Expr::BinaryOp(Box::new(left), op, Box::new(right));
1240 }
1241 Ok(left)
1242 }
1243
1244 fn parse_primary(&mut self) -> Result<Expr, ParseError> {
1245 match self.peek().clone() {
1246 Token::DotIdent(name) => {
1247 self.advance();
1248 Ok(Expr::Field(name))
1249 }
1250 Token::IntLit(v) => {
1251 self.advance();
1252 Ok(Expr::Literal(Literal::Int(v)))
1253 }
1254 Token::FloatLit(v) => {
1255 self.advance();
1256 Ok(Expr::Literal(Literal::Float(v)))
1257 }
1258 Token::StringLit(v) => {
1259 self.advance();
1260 Ok(Expr::Literal(Literal::String(v)))
1261 }
1262 Token::BoolLit(v) => {
1263 self.advance();
1264 Ok(Expr::Literal(Literal::Bool(v)))
1265 }
1266 Token::Param(name) => {
1267 self.advance();
1268 Ok(Expr::Param(name))
1269 }
1270 Token::Not => {
1271 self.advance();
1272 if *self.peek() == Token::Exists {
1273 self.advance();
1274 if let Some(sub) = self.try_parse_exists_subquery()? {
1278 return Ok(Expr::ExistsSubquery {
1279 subquery: Box::new(sub),
1280 negated: true,
1281 });
1282 }
1283 let expr = self.parse_primary()?;
1284 Ok(Expr::UnaryOp(UnaryOp::NotExists, Box::new(expr)))
1285 } else {
1286 let expr = self.parse_primary()?;
1287 Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(expr)))
1288 }
1289 }
1290 Token::Exists => {
1291 self.advance();
1292 if let Some(sub) = self.try_parse_exists_subquery()? {
1296 return Ok(Expr::ExistsSubquery {
1297 subquery: Box::new(sub),
1298 negated: false,
1299 });
1300 }
1301 let expr = self.parse_primary()?;
1302 Ok(Expr::UnaryOp(UnaryOp::Exists, Box::new(expr)))
1303 }
1304 Token::LParen => {
1305 self.advance();
1306 let expr = self.parse_expr()?;
1307 self.expect(&Token::RParen)?;
1308 Ok(expr)
1309 }
1310 Token::Ident(name) => {
1311 self.advance();
1312 if let Token::DotIdent(field) = self.peek().clone() {
1316 self.advance();
1317 return Ok(Expr::QualifiedField {
1318 qualifier: name,
1319 field,
1320 });
1321 }
1322 Ok(Expr::Field(name))
1323 }
1324 Token::RowNumber | Token::Rank | Token::DenseRank => {
1326 let wfunc = match self.advance() {
1327 Token::RowNumber => WindowFunc::RowNumber,
1328 Token::Rank => WindowFunc::Rank,
1329 Token::DenseRank => WindowFunc::DenseRank,
1330 _ => {
1331 return Err(ParseError::Syntax {
1332 message: "unexpected window function token".into(),
1333 })
1334 }
1335 };
1336 self.expect(&Token::LParen)?;
1337 self.expect(&Token::RParen)?;
1338 let (partition_by, order_by) = self.parse_over_clause()?;
1339 Ok(Expr::Window {
1340 function: wfunc,
1341 args: vec![],
1342 partition_by,
1343 order_by,
1344 })
1345 }
1346 Token::Count | Token::Avg | Token::Sum | Token::Min | Token::Max => {
1350 let mut func = match self.advance() {
1351 Token::Count => AggFunc::Count,
1352 Token::Avg => AggFunc::Avg,
1353 Token::Sum => AggFunc::Sum,
1354 Token::Min => AggFunc::Min,
1355 Token::Max => AggFunc::Max,
1356 _ => {
1357 return Err(ParseError::Syntax {
1358 message: "unexpected aggregate token".into(),
1359 })
1360 }
1361 };
1362 self.expect(&Token::LParen)?;
1363 if func == AggFunc::Count && *self.peek() == Token::Star {
1365 self.advance();
1366 self.expect(&Token::RParen)?;
1367 if *self.peek() == Token::Over {
1369 let (partition_by, order_by) = self.parse_over_clause()?;
1370 return Ok(Expr::Window {
1371 function: WindowFunc::Count,
1372 args: vec![Expr::Field("*".into())],
1373 partition_by,
1374 order_by,
1375 });
1376 }
1377 return Ok(Expr::FunctionCall(
1378 AggFunc::Count,
1379 Box::new(Expr::Field("*".into())),
1380 ));
1381 }
1382 if func == AggFunc::Count && *self.peek() == Token::Distinct {
1384 self.advance();
1385 func = AggFunc::CountDistinct;
1386 }
1387 let inner = self.parse_expr()?;
1388 self.expect(&Token::RParen)?;
1389 if *self.peek() == Token::Over {
1391 let wfunc = match func {
1392 AggFunc::Count => WindowFunc::Count,
1393 AggFunc::Avg => WindowFunc::Avg,
1394 AggFunc::Sum => WindowFunc::Sum,
1395 AggFunc::Min => WindowFunc::Min,
1396 AggFunc::Max => WindowFunc::Max,
1397 _ => {
1398 return Err(ParseError::Unsupported {
1399 feature: "count(distinct ...) over (...) is not supported".into(),
1400 })
1401 }
1402 };
1403 let (partition_by, order_by) = self.parse_over_clause()?;
1404 return Ok(Expr::Window {
1405 function: wfunc,
1406 args: vec![inner],
1407 partition_by,
1408 order_by,
1409 });
1410 }
1411 Ok(Expr::FunctionCall(func, Box::new(inner)))
1412 }
1413 Token::Upper
1414 | Token::Lower
1415 | Token::Length
1416 | Token::Trim
1417 | Token::Substring
1418 | Token::Concat
1419 | Token::Abs
1420 | Token::Round
1421 | Token::Ceil
1422 | Token::Floor
1423 | Token::Sqrt
1424 | Token::Pow
1425 | Token::Now
1426 | Token::Extract
1427 | Token::DateAdd
1428 | Token::DateDiff => {
1429 let tok = self.advance();
1430 let func = token_to_scalar_fn(&tok);
1431 self.expect(&Token::LParen)?;
1432 let mut args = Vec::new();
1433 while !matches!(self.peek(), Token::RParen | Token::Eof) {
1434 args.push(self.parse_expr()?);
1435 if *self.peek() == Token::Comma {
1436 self.advance();
1437 }
1438 }
1439 self.expect(&Token::RParen)?;
1440 Ok(Expr::ScalarFunc(func, args))
1441 }
1442 Token::Cast => {
1443 self.advance();
1444 self.expect(&Token::LParen)?;
1445 let inner = self.parse_expr()?;
1446 self.expect(&Token::Comma)?;
1447 let cast_type = self.parse_cast_type()?;
1448 self.expect(&Token::RParen)?;
1449 Ok(Expr::Cast(Box::new(inner), cast_type))
1450 }
1451 Token::Case => {
1452 self.advance();
1453 let mut whens = Vec::new();
1454 while *self.peek() == Token::When {
1455 self.advance();
1456 let condition = self.parse_expr()?;
1457 self.expect(&Token::Then)?;
1458 let result = self.parse_expr()?;
1459 whens.push((Box::new(condition), Box::new(result)));
1460 }
1461 let else_expr = if *self.peek() == Token::Else {
1462 self.advance();
1463 Some(Box::new(self.parse_expr()?))
1464 } else {
1465 None
1466 };
1467 self.expect(&Token::End)?;
1468 Ok(Expr::Case { whens, else_expr })
1469 }
1470 t => Err(ParseError::Syntax {
1471 message: format!("unexpected token in expression: {}", t.display_name()),
1472 }),
1473 }
1474 }
1475
1476 fn parse_alter_table(&mut self) -> Result<Statement, ParseError> {
1479 self.expect(&Token::Alter)?;
1480 let table = match self.advance() {
1481 Token::Ident(name) => name,
1482 t => {
1483 return Err(ParseError::UnexpectedToken {
1484 expected: "table name after alter".into(),
1485 got: t.display_name(),
1486 })
1487 }
1488 };
1489 match self.peek() {
1490 Token::Add => {
1491 self.advance();
1492 if *self.peek() == Token::Index {
1494 self.advance();
1495 let column = match self.advance() {
1496 Token::DotIdent(n) => n,
1497 t => {
1498 return Err(ParseError::UnexpectedToken {
1499 expected: ".<column> after add index".into(),
1500 got: t.display_name(),
1501 })
1502 }
1503 };
1504 return Ok(Statement::AlterTable(AlterTableExpr {
1505 table,
1506 action: AlterAction::AddIndex { column },
1507 }));
1508 }
1509 if *self.peek() == Token::Column {
1511 self.advance();
1512 }
1513 let required = if *self.peek() == Token::Required {
1514 self.advance();
1515 true
1516 } else {
1517 false
1518 };
1519 let name = match self.advance() {
1520 Token::Ident(n) => n,
1521 t => {
1522 return Err(ParseError::UnexpectedToken {
1523 expected: "column name".into(),
1524 got: t.display_name(),
1525 })
1526 }
1527 };
1528 self.expect(&Token::Colon)?;
1529 let type_name = match self.advance() {
1530 Token::Ident(n) => n,
1531 t => {
1532 return Err(ParseError::UnexpectedToken {
1533 expected: "type name".into(),
1534 got: t.display_name(),
1535 })
1536 }
1537 };
1538 Ok(Statement::AlterTable(AlterTableExpr {
1539 table,
1540 action: AlterAction::AddColumn {
1541 name,
1542 type_name,
1543 required,
1544 },
1545 }))
1546 }
1547 Token::Drop => {
1548 self.advance();
1549 if *self.peek() == Token::Column {
1551 self.advance();
1552 }
1553 let name = match self.advance() {
1554 Token::Ident(n) => n,
1555 t => {
1556 return Err(ParseError::UnexpectedToken {
1557 expected: "column name".into(),
1558 got: t.display_name(),
1559 })
1560 }
1561 };
1562 Ok(Statement::AlterTable(AlterTableExpr {
1563 table,
1564 action: AlterAction::DropColumn { name },
1565 }))
1566 }
1567 t => Err(ParseError::UnexpectedToken {
1568 expected: "add or drop after alter <table>".into(),
1569 got: t.display_name(),
1570 }),
1571 }
1572 }
1573
1574 fn parse_drop_or_drop_view(&mut self) -> Result<Statement, ParseError> {
1576 self.expect(&Token::Drop)?;
1577 if *self.peek() == Token::View {
1578 self.advance(); let name = match self.advance() {
1580 Token::Ident(name) => name,
1581 t => {
1582 return Err(ParseError::UnexpectedToken {
1583 expected: "view name after drop view".into(),
1584 got: t.display_name(),
1585 })
1586 }
1587 };
1588 return Ok(Statement::DropView(DropViewExpr { name }));
1589 }
1590 let table = match self.advance() {
1591 Token::Ident(name) => name,
1592 t => {
1593 return Err(ParseError::UnexpectedToken {
1594 expected: "table name after drop".into(),
1595 got: t.display_name(),
1596 })
1597 }
1598 };
1599 Ok(Statement::DropTable(DropTableExpr { table }))
1600 }
1601
1602 fn parse_create_view(&mut self) -> Result<Statement, ParseError> {
1607 self.expect(&Token::Materialized)?;
1608 let name = match self.advance() {
1609 Token::Ident(name) => name,
1610 t => {
1611 return Err(ParseError::UnexpectedToken {
1612 expected: "view name after materialize".into(),
1613 got: t.display_name(),
1614 })
1615 }
1616 };
1617 self.expect(&Token::As)?;
1618 let query_start = self.pos;
1620 let source = match self.advance() {
1621 Token::Ident(s) => s,
1622 t => {
1623 return Err(ParseError::UnexpectedToken {
1624 expected: "source table name".into(),
1625 got: t.display_name(),
1626 })
1627 }
1628 };
1629 let query = self.parse_query_tail(source)?;
1630 let query_text = tokens_to_text(&self.tokens[query_start..self.pos]);
1632 Ok(Statement::CreateView(CreateViewExpr {
1633 name,
1634 query,
1635 query_text,
1636 }))
1637 }
1638
1639 fn maybe_parse_union(&mut self, left: Statement) -> Result<Statement, ParseError> {
1642 if *self.peek() != Token::Union {
1643 return Ok(left);
1644 }
1645 if !matches!(left, Statement::Query(_) | Statement::Union(_)) {
1646 return Err(ParseError::Syntax {
1647 message: "UNION requires a query on the left side".into(),
1648 });
1649 }
1650 self.advance(); let all = if let Token::Ident(s) = self.peek() {
1652 if s == "all" {
1653 self.advance();
1654 true
1655 } else {
1656 false
1657 }
1658 } else {
1659 false
1660 };
1661 let right = self.parse_single_query()?;
1663 let union = Statement::Union(UnionExpr {
1664 left: Box::new(left),
1665 right: Box::new(right),
1666 all,
1667 });
1668 self.maybe_parse_union(union)
1670 }
1671
1672 fn parse_single_query(&mut self) -> Result<Statement, ParseError> {
1674 match self.peek() {
1675 Token::Count | Token::Avg | Token::Sum | Token::Min | Token::Max => {
1676 self.parse_aggregate_query()
1677 }
1678 Token::Ident(_) => self.parse_query_or_mutation(),
1679 _ => Err(ParseError::Syntax {
1680 message: format!(
1681 "expected query after UNION, got {}",
1682 self.peek().display_name()
1683 ),
1684 }),
1685 }
1686 }
1687
1688 fn parse_refresh_view(&mut self) -> Result<Statement, ParseError> {
1690 self.expect(&Token::Refresh)?;
1691 let name = match self.advance() {
1692 Token::Ident(name) => name,
1693 t => {
1694 return Err(ParseError::UnexpectedToken {
1695 expected: "view name after refresh".into(),
1696 got: t.display_name(),
1697 })
1698 }
1699 };
1700 Ok(Statement::RefreshView(RefreshViewExpr { name }))
1701 }
1702
1703 fn parse_create_type(&mut self) -> Result<Statement, ParseError> {
1704 self.expect(&Token::Type)?;
1705 let name = match self.advance() {
1706 Token::Ident(n) => n,
1707 t => {
1708 return Err(ParseError::UnexpectedToken {
1709 expected: "type name".into(),
1710 got: t.display_name(),
1711 })
1712 }
1713 };
1714 self.expect(&Token::LBrace)?;
1715 let mut fields = Vec::new();
1716 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
1717 let required = if *self.peek() == Token::Required {
1718 self.advance();
1719 true
1720 } else {
1721 false
1722 };
1723 let field_name = match self.advance() {
1724 Token::Ident(n) => n,
1725 t => {
1726 return Err(ParseError::UnexpectedToken {
1727 expected: "field name".into(),
1728 got: t.display_name(),
1729 })
1730 }
1731 };
1732 self.expect(&Token::Colon)?;
1733 let type_name = match self.advance() {
1734 Token::Ident(n) => n,
1735 t => {
1736 return Err(ParseError::UnexpectedToken {
1737 expected: "type name".into(),
1738 got: t.display_name(),
1739 })
1740 }
1741 };
1742 fields.push(FieldDef {
1743 name: field_name,
1744 type_name,
1745 required,
1746 });
1747 if *self.peek() == Token::Comma {
1748 self.advance();
1749 }
1750 }
1751 self.expect(&Token::RBrace)?;
1752 Ok(Statement::CreateType(CreateTypeExpr { name, fields }))
1753 }
1754}
1755
1756fn tokens_to_text(tokens: &[Token]) -> String {
1760 let mut out = String::with_capacity(64);
1761 for tok in tokens {
1762 if !out.is_empty() && !matches!(tok, Token::Eof) {
1763 out.push(' ');
1764 }
1765 match tok {
1766 Token::Ident(s) => out.push_str(s),
1767 Token::DotIdent(s) => {
1768 out.push('.');
1769 out.push_str(s);
1770 }
1771 Token::IntLit(v) => out.push_str(&v.to_string()),
1772 Token::FloatLit(v) => out.push_str(&v.to_string()),
1773 Token::StringLit(s) => {
1774 out.push('"');
1775 out.push_str(s);
1776 out.push('"');
1777 }
1778 Token::BoolLit(v) => out.push_str(if *v { "true" } else { "false" }),
1779 Token::Param(s) => {
1780 out.push('$');
1781 out.push_str(s);
1782 }
1783 Token::Type => out.push_str("type"),
1784 Token::Filter => out.push_str("filter"),
1785 Token::Order => out.push_str("order"),
1786 Token::Limit => out.push_str("limit"),
1787 Token::Offset => out.push_str("offset"),
1788 Token::Insert => out.push_str("insert"),
1789 Token::Update => out.push_str("update"),
1790 Token::Delete => out.push_str("delete"),
1791 Token::Upsert => out.push_str("upsert"),
1792 Token::Conflict => out.push_str("conflict"),
1793 Token::Select => out.push_str("select"),
1794 Token::Required => out.push_str("required"),
1795 Token::Multi => out.push_str("multi"),
1796 Token::Link => out.push_str("link"),
1797 Token::Index => out.push_str("index"),
1798 Token::On => out.push_str("on"),
1799 Token::Asc => out.push_str("asc"),
1800 Token::Desc => out.push_str("desc"),
1801 Token::And => out.push_str("and"),
1802 Token::Or => out.push_str("or"),
1803 Token::Not => out.push_str("not"),
1804 Token::Exists => out.push_str("exists"),
1805 Token::Let => out.push_str("let"),
1806 Token::As => out.push_str("as"),
1807 Token::Match => out.push_str("match"),
1808 Token::Group => out.push_str("group"),
1809 Token::Join => out.push_str("join"),
1810 Token::Inner => out.push_str("inner"),
1811 Token::LeftKw => out.push_str("left"),
1812 Token::RightKw => out.push_str("right"),
1813 Token::Outer => out.push_str("outer"),
1814 Token::Cross => out.push_str("cross"),
1815 Token::Transaction => out.push_str("transaction"),
1816 Token::View => out.push_str("view"),
1817 Token::Materialized => out.push_str("materialized"),
1818 Token::Refresh => out.push_str("refresh"),
1819 Token::Union => out.push_str("union"),
1820 Token::Having => out.push_str("having"),
1821 Token::Distinct => out.push_str("distinct"),
1822 Token::In => out.push_str("in"),
1823 Token::Between => out.push_str("between"),
1824 Token::Like => out.push_str("like"),
1825 Token::Count => out.push_str("count"),
1826 Token::Avg => out.push_str("avg"),
1827 Token::Sum => out.push_str("sum"),
1828 Token::Min => out.push_str("min"),
1829 Token::Max => out.push_str("max"),
1830 Token::Is => out.push_str("is"),
1831 Token::Null => out.push_str("null"),
1832 Token::Upper => out.push_str("upper"),
1833 Token::Lower => out.push_str("lower"),
1834 Token::Length => out.push_str("length"),
1835 Token::Trim => out.push_str("trim"),
1836 Token::Substring => out.push_str("substring"),
1837 Token::Concat => out.push_str("concat"),
1838 Token::Abs => out.push_str("abs"),
1839 Token::Round => out.push_str("round"),
1840 Token::Ceil => out.push_str("ceil"),
1841 Token::Floor => out.push_str("floor"),
1842 Token::Sqrt => out.push_str("sqrt"),
1843 Token::Pow => out.push_str("pow"),
1844 Token::Now => out.push_str("now"),
1845 Token::Extract => out.push_str("extract"),
1846 Token::DateAdd => out.push_str("date_add"),
1847 Token::DateDiff => out.push_str("date_diff"),
1848 Token::Cast => out.push_str("cast"),
1849 Token::Case => out.push_str("case"),
1850 Token::When => out.push_str("when"),
1851 Token::Then => out.push_str("then"),
1852 Token::Else => out.push_str("else"),
1853 Token::End => out.push_str("end"),
1854 Token::Over => out.push_str("over"),
1855 Token::Partition => out.push_str("partition"),
1856 Token::RowNumber => out.push_str("row_number"),
1857 Token::Rank => out.push_str("rank"),
1858 Token::DenseRank => out.push_str("dense_rank"),
1859 Token::Alter => out.push_str("alter"),
1860 Token::Drop => out.push_str("drop"),
1861 Token::Add => out.push_str("add"),
1862 Token::Column => out.push_str("column"),
1863 Token::Eq => out.push('='),
1864 Token::Neq => out.push_str("!="),
1865 Token::Lt => out.push('<'),
1866 Token::Gt => out.push('>'),
1867 Token::Lte => out.push_str("<="),
1868 Token::Gte => out.push_str(">="),
1869 Token::Assign => out.push_str(":="),
1870 Token::Arrow => out.push_str("->"),
1871 Token::Pipe => out.push('|'),
1872 Token::Coalesce => out.push_str("??"),
1873 Token::Plus => out.push('+'),
1874 Token::Minus => out.push('-'),
1875 Token::Star => out.push('*'),
1876 Token::Slash => out.push('/'),
1877 Token::LBrace => out.push('{'),
1878 Token::RBrace => out.push('}'),
1879 Token::LParen => out.push('('),
1880 Token::RParen => out.push(')'),
1881 Token::Comma => out.push(','),
1882 Token::Colon => out.push(':'),
1883 Token::Dot => out.push('.'),
1884 Token::Explain => out.push_str("explain"),
1885 Token::Eof => {}
1886 }
1887 }
1888 out
1889}
1890
1891#[cfg(test)]
1892mod tests {
1893 use super::*;
1894 #[test]
1895 fn test_parse_simple_query() {
1896 let stmt = parse("User").unwrap();
1897 match stmt {
1898 Statement::Query(q) => {
1899 assert_eq!(q.source, "User");
1900 assert!(q.filter.is_none());
1901 assert!(q.projection.is_none());
1902 }
1903 _ => panic!("expected query"),
1904 }
1905 }
1906
1907 #[test]
1908 fn test_parse_filter() {
1909 let stmt = parse("User filter .age > 30").unwrap();
1910 match stmt {
1911 Statement::Query(q) => {
1912 assert_eq!(q.source, "User");
1913 assert!(q.filter.is_some());
1914 }
1915 _ => panic!("expected query"),
1916 }
1917 }
1918
1919 #[test]
1920 fn test_parse_projection() {
1921 let stmt = parse("User { name, email }").unwrap();
1922 match stmt {
1923 Statement::Query(q) => {
1924 let proj = q.projection.unwrap();
1925 assert_eq!(proj.len(), 2);
1926 }
1927 _ => panic!("expected query"),
1928 }
1929 }
1930
1931 #[test]
1932 fn test_parse_filter_order_limit() {
1933 let stmt = parse("User filter .age > 30 order .name desc limit 10").unwrap();
1934 match stmt {
1935 Statement::Query(q) => {
1936 assert!(q.filter.is_some());
1937 let order = q.order.unwrap();
1938 assert_eq!(order.keys.len(), 1);
1939 assert_eq!(order.keys[0].field, "name");
1940 assert!(order.keys[0].descending);
1941 assert!(q.limit.is_some());
1942 }
1943 _ => panic!("expected query"),
1944 }
1945 }
1946
1947 #[test]
1948 fn test_parse_insert() {
1949 let stmt = parse(r#"insert User { name := "Alice", age := 30 }"#).unwrap();
1950 match stmt {
1951 Statement::Insert(ins) => {
1952 assert_eq!(ins.target, "User");
1953 assert_eq!(ins.assignments.len(), 2);
1954 assert_eq!(ins.assignments[0].field, "name");
1955 assert_eq!(ins.assignments[1].field, "age");
1956 }
1957 _ => panic!("expected insert"),
1958 }
1959 }
1960
1961 #[test]
1962 fn test_parse_update() {
1963 let stmt = parse(r#"User filter .email = "alice@ex.com" update { age := 31 }"#).unwrap();
1964 match stmt {
1965 Statement::UpdateQuery(upd) => {
1966 assert_eq!(upd.source, "User");
1967 assert!(upd.filter.is_some());
1968 assert_eq!(upd.assignments.len(), 1);
1969 }
1970 _ => panic!("expected update"),
1971 }
1972 }
1973
1974 #[test]
1975 fn test_parse_delete() {
1976 let stmt = parse("User filter .age < 18 delete").unwrap();
1977 match stmt {
1978 Statement::DeleteQuery(del) => {
1979 assert_eq!(del.source, "User");
1980 assert!(del.filter.is_some());
1981 }
1982 _ => panic!("expected delete"),
1983 }
1984 }
1985
1986 #[test]
1987 fn test_parse_count() {
1988 let stmt = parse("count(User)").unwrap();
1989 match stmt {
1990 Statement::Query(q) => {
1991 let agg = q.aggregation.unwrap();
1992 assert_eq!(agg.function, AggFunc::Count);
1993 assert!(q.filter.is_none());
1994 }
1995 _ => panic!("expected query with aggregation"),
1996 }
1997 }
1998
1999 #[test]
2000 fn test_parse_count_with_filter() {
2001 let stmt = parse("count(User filter .age > 30)").unwrap();
2004 match stmt {
2005 Statement::Query(q) => {
2006 assert_eq!(q.source, "User");
2007 let agg = q.aggregation.unwrap();
2008 assert_eq!(agg.function, AggFunc::Count);
2009 assert!(q.filter.is_some(), "filter should have been parsed");
2010 }
2011 _ => panic!("expected query with aggregation"),
2012 }
2013 }
2014
2015 #[test]
2016 fn test_parse_count_with_filter_and_limit() {
2017 let stmt = parse("count(User filter .age > 30 limit 100)").unwrap();
2018 match stmt {
2019 Statement::Query(q) => {
2020 assert_eq!(q.source, "User");
2021 assert!(q.filter.is_some());
2022 assert!(q.limit.is_some());
2023 assert_eq!(q.aggregation.unwrap().function, AggFunc::Count);
2024 }
2025 _ => panic!("expected query with aggregation"),
2026 }
2027 }
2028
2029 #[test]
2030 fn test_parse_create_type() {
2031 let stmt = parse("type User { required name: str, age: int }").unwrap();
2032 match stmt {
2033 Statement::CreateType(ct) => {
2034 assert_eq!(ct.name, "User");
2035 assert_eq!(ct.fields.len(), 2);
2036 assert!(ct.fields[0].required);
2037 assert!(!ct.fields[1].required);
2038 }
2039 _ => panic!("expected create type"),
2040 }
2041 }
2042
2043 #[test]
2044 fn test_parse_sum_with_field_projection() {
2045 let stmt = parse("sum(User filter .age > 30 { .age })").unwrap();
2048 match stmt {
2049 Statement::Query(q) => {
2050 let agg = q.aggregation.expect("aggregate");
2051 assert_eq!(agg.function, AggFunc::Sum);
2052 assert_eq!(agg.field.as_deref(), Some("age"));
2053 assert!(
2054 q.projection.is_none(),
2055 "projection should be lifted into agg.field"
2056 );
2057 }
2058 _ => panic!("expected query"),
2059 }
2060 }
2061
2062 #[test]
2063 fn test_parse_avg_min_max_with_field() {
2064 for (src, expected) in [
2065 ("avg(User { .age })", AggFunc::Avg),
2066 ("min(User { .age })", AggFunc::Min),
2067 ("max(User { .age })", AggFunc::Max),
2068 ] {
2069 let stmt = parse(src).unwrap();
2070 match stmt {
2071 Statement::Query(q) => {
2072 let agg = q.aggregation.unwrap();
2073 assert_eq!(agg.function, expected, "func mismatch for {src}");
2074 assert_eq!(
2075 agg.field.as_deref(),
2076 Some("age"),
2077 "field mismatch for {src}"
2078 );
2079 assert!(
2080 q.projection.is_none(),
2081 "projection should be cleared for {src}"
2082 );
2083 }
2084 _ => panic!("expected query for {src}"),
2085 }
2086 }
2087 }
2088
2089 #[test]
2090 fn test_parse_count_leaves_projection_alone() {
2091 let stmt = parse("count(User { .age })").unwrap();
2094 match stmt {
2095 Statement::Query(q) => {
2096 let agg = q.aggregation.unwrap();
2097 assert_eq!(agg.function, AggFunc::Count);
2098 assert!(agg.field.is_none());
2099 assert!(q.projection.is_some(), "count must not eat projection");
2100 }
2101 _ => panic!("expected query"),
2102 }
2103 }
2104
2105 #[test]
2110 fn test_parse_source_alias() {
2111 let stmt = parse("User as u filter u.age > 30").unwrap();
2112 match stmt {
2113 Statement::Query(q) => {
2114 assert_eq!(q.source, "User");
2115 assert_eq!(q.alias.as_deref(), Some("u"));
2116 assert!(q.joins.is_empty());
2117 match q.filter.unwrap() {
2118 Expr::BinaryOp(l, BinOp::Gt, _) => match *l {
2119 Expr::QualifiedField { qualifier, field } => {
2120 assert_eq!(qualifier, "u");
2121 assert_eq!(field, "age");
2122 }
2123 other => panic!("expected qualified field, got {other:?}"),
2124 },
2125 other => panic!("expected >, got {other:?}"),
2126 }
2127 }
2128 _ => panic!("expected query"),
2129 }
2130 }
2131
2132 #[test]
2133 fn test_parse_inner_join_on() {
2134 let stmt = parse("User as u inner join Order as o on u.id = o.user_id").unwrap();
2135 match stmt {
2136 Statement::Query(q) => {
2137 assert_eq!(q.source, "User");
2138 assert_eq!(q.alias.as_deref(), Some("u"));
2139 assert_eq!(q.joins.len(), 1);
2140 let j = &q.joins[0];
2141 assert_eq!(j.kind, JoinKind::Inner);
2142 assert_eq!(j.source, "Order");
2143 assert_eq!(j.alias.as_deref(), Some("o"));
2144 let on = j.on.as_ref().expect("on clause");
2145 match on {
2146 Expr::BinaryOp(l, BinOp::Eq, r) => {
2147 assert!(matches!(**l, Expr::QualifiedField { .. }));
2148 assert!(matches!(**r, Expr::QualifiedField { .. }));
2149 }
2150 other => panic!("expected eq, got {other:?}"),
2151 }
2152 }
2153 _ => panic!("expected query"),
2154 }
2155 }
2156
2157 #[test]
2158 fn test_parse_bare_join_defaults_to_inner() {
2159 let stmt = parse("User join Order on User.id = Order.user_id").unwrap();
2160 match stmt {
2161 Statement::Query(q) => {
2162 assert_eq!(q.joins.len(), 1);
2163 assert_eq!(q.joins[0].kind, JoinKind::Inner);
2164 }
2165 _ => panic!("expected query"),
2166 }
2167 }
2168
2169 #[test]
2170 fn test_parse_left_outer_join() {
2171 let stmt = parse("User as u left outer join Order as o on u.id = o.user_id").unwrap();
2172 match stmt {
2173 Statement::Query(q) => {
2174 assert_eq!(q.joins.len(), 1);
2175 assert_eq!(q.joins[0].kind, JoinKind::LeftOuter);
2176 }
2177 _ => panic!("expected query"),
2178 }
2179 }
2180
2181 #[test]
2182 fn test_parse_left_join_without_outer_keyword() {
2183 let stmt = parse("User as u left join Order as o on u.id = o.user_id").unwrap();
2185 match stmt {
2186 Statement::Query(q) => {
2187 assert_eq!(q.joins[0].kind, JoinKind::LeftOuter);
2188 }
2189 _ => panic!("expected query"),
2190 }
2191 }
2192
2193 #[test]
2194 fn test_parse_right_join() {
2195 let stmt = parse("User as u right join Order as o on u.id = o.user_id").unwrap();
2196 match stmt {
2197 Statement::Query(q) => {
2198 assert_eq!(q.joins[0].kind, JoinKind::RightOuter);
2199 }
2200 _ => panic!("expected query"),
2201 }
2202 }
2203
2204 #[test]
2205 fn test_parse_cross_join_has_no_on() {
2206 let stmt = parse("User cross join Order").unwrap();
2207 match stmt {
2208 Statement::Query(q) => {
2209 assert_eq!(q.joins[0].kind, JoinKind::Cross);
2210 assert!(q.joins[0].on.is_none());
2211 }
2212 _ => panic!("expected query"),
2213 }
2214 }
2215
2216 #[test]
2217 fn test_parse_multi_join_chain() {
2218 let stmt = parse(
2219 "User as u join Order as o on u.id = o.user_id \
2220 join Product as p on o.product_id = p.id",
2221 )
2222 .unwrap();
2223 match stmt {
2224 Statement::Query(q) => {
2225 assert_eq!(q.joins.len(), 2);
2226 assert_eq!(q.joins[0].source, "Order");
2227 assert_eq!(q.joins[1].source, "Product");
2228 }
2229 _ => panic!("expected query"),
2230 }
2231 }
2232
2233 #[test]
2234 fn test_parse_join_with_filter_tail() {
2235 let stmt = parse(
2237 "User as u join Order as o on u.id = o.user_id \
2238 filter o.total > 100 order .name limit 10",
2239 )
2240 .unwrap();
2241 match stmt {
2242 Statement::Query(q) => {
2243 assert_eq!(q.joins.len(), 1);
2244 assert!(q.filter.is_some());
2245 assert!(q.order.is_some());
2246 assert!(q.limit.is_some());
2247 }
2248 _ => panic!("expected query"),
2249 }
2250 }
2251
2252 #[test]
2253 fn test_parse_join_requires_on_for_inner() {
2254 let err = parse("User join Order").unwrap_err();
2256 assert!(
2257 err.message().contains("on"),
2258 "expected on-clause error, got {:?}",
2259 err.message()
2260 );
2261 }
2262
2263 #[test]
2264 fn test_parse_update_on_joined_query_errors() {
2265 let err =
2268 parse("User as u join Order as o on u.id = o.user_id update { age := 1 }").unwrap_err();
2269 assert!(err.message().contains("update"));
2270 }
2271
2272 #[test]
2273 fn test_parse_delete_on_joined_query_errors() {
2274 let err = parse("User as u join Order as o on u.id = o.user_id delete").unwrap_err();
2275 assert!(err.message().contains("delete"));
2276 }
2277
2278 #[test]
2281 fn test_parse_distinct() {
2282 let stmt = parse("User distinct { .name }").unwrap();
2283 match stmt {
2284 Statement::Query(q) => {
2285 assert!(q.distinct);
2286 assert!(q.projection.is_some());
2287 }
2288 _ => panic!("expected query"),
2289 }
2290 }
2291
2292 #[test]
2293 fn test_parse_in_list() {
2294 let stmt = parse(r#"User filter .name in ("Alice", "Bob")"#).unwrap();
2295 match stmt {
2296 Statement::Query(q) => match q.filter.unwrap() {
2297 Expr::InList {
2298 expr,
2299 list,
2300 negated,
2301 } => {
2302 assert!(!negated);
2303 assert!(matches!(*expr, Expr::Field(f) if f == "name"));
2304 assert_eq!(list.len(), 2);
2305 }
2306 other => panic!("expected InList, got {other:?}"),
2307 },
2308 _ => panic!("expected query"),
2309 }
2310 }
2311
2312 #[test]
2313 fn test_parse_not_in_list() {
2314 let stmt = parse("User filter .age not in (1, 2, 3)").unwrap();
2315 match stmt {
2316 Statement::Query(q) => match q.filter.unwrap() {
2317 Expr::InList { negated, list, .. } => {
2318 assert!(negated);
2319 assert_eq!(list.len(), 3);
2320 }
2321 other => panic!("expected InList, got {other:?}"),
2322 },
2323 _ => panic!("expected query"),
2324 }
2325 }
2326
2327 #[test]
2328 fn test_parse_between() {
2329 let stmt = parse("User filter .age between 10 and 20").unwrap();
2331 match stmt {
2332 Statement::Query(q) => {
2333 match q.filter.unwrap() {
2334 Expr::BinaryOp(_, BinOp::And, _) => {} other => panic!("expected And (desugared between), got {other:?}"),
2336 }
2337 }
2338 _ => panic!("expected query"),
2339 }
2340 }
2341
2342 #[test]
2343 fn test_parse_not_between() {
2344 let stmt = parse("User filter .age not between 10 and 20").unwrap();
2346 match stmt {
2347 Statement::Query(q) => {
2348 match q.filter.unwrap() {
2349 Expr::BinaryOp(_, BinOp::Or, _) => {} other => panic!("expected Or (desugared not between), got {other:?}"),
2351 }
2352 }
2353 _ => panic!("expected query"),
2354 }
2355 }
2356
2357 #[test]
2358 fn test_parse_like() {
2359 let stmt = parse(r#"User filter .name like "A%""#).unwrap();
2360 match stmt {
2361 Statement::Query(q) => match q.filter.unwrap() {
2362 Expr::BinaryOp(l, BinOp::Like, r) => {
2363 assert!(matches!(*l, Expr::Field(f) if f == "name"));
2364 assert!(matches!(*r, Expr::Literal(Literal::String(s)) if s == "A%"));
2365 }
2366 other => panic!("expected Like, got {other:?}"),
2367 },
2368 _ => panic!("expected query"),
2369 }
2370 }
2371
2372 #[test]
2373 fn test_parse_not_like() {
2374 let stmt = parse(r#"User filter .name not like "A%""#).unwrap();
2375 match stmt {
2376 Statement::Query(q) => match q.filter.unwrap() {
2377 Expr::UnaryOp(UnaryOp::Not, inner) => {
2378 assert!(matches!(*inner, Expr::BinaryOp(_, BinOp::Like, _)));
2379 }
2380 other => panic!("expected Not(Like), got {other:?}"),
2381 },
2382 _ => panic!("expected query"),
2383 }
2384 }
2385
2386 #[test]
2389 fn test_parse_group_by_single_key() {
2390 let stmt = parse("User group .status { .status, n: count(.name) }").unwrap();
2391 match stmt {
2392 Statement::Query(q) => {
2393 let gb = q.group_by.unwrap();
2394 assert_eq!(gb.keys, vec!["status"]);
2395 assert!(gb.having.is_none());
2396 let proj = q.projection.unwrap();
2397 assert_eq!(proj.len(), 2);
2398 assert!(matches!(
2399 &proj[1].expr,
2400 Expr::FunctionCall(AggFunc::Count, _)
2401 ));
2402 assert_eq!(proj[1].alias.as_deref(), Some("n"));
2403 }
2404 _ => panic!("expected query"),
2405 }
2406 }
2407
2408 #[test]
2409 fn test_parse_group_by_multi_key() {
2410 let stmt = parse("User group .status, .age { .status, .age }").unwrap();
2411 match stmt {
2412 Statement::Query(q) => {
2413 let gb = q.group_by.unwrap();
2414 assert_eq!(gb.keys, vec!["status", "age"]);
2415 }
2416 _ => panic!("expected query"),
2417 }
2418 }
2419
2420 #[test]
2421 fn test_parse_group_by_having() {
2422 let stmt = parse("User group .status having count(.name) > 1 { .status }").unwrap();
2423 match stmt {
2424 Statement::Query(q) => {
2425 let gb = q.group_by.unwrap();
2426 assert_eq!(gb.keys, vec!["status"]);
2427 assert!(gb.having.is_some());
2428 match gb.having.unwrap() {
2430 Expr::BinaryOp(l, BinOp::Gt, _) => {
2431 assert!(matches!(*l, Expr::FunctionCall(AggFunc::Count, _)));
2432 }
2433 other => panic!("expected BinaryOp, got {other:?}"),
2434 }
2435 }
2436 _ => panic!("expected query"),
2437 }
2438 }
2439
2440 #[test]
2441 fn test_parse_aggregate_in_projection() {
2442 let stmt = parse("User group .status { .status, count(.name), sum(.age) }").unwrap();
2444 match stmt {
2445 Statement::Query(q) => {
2446 let proj = q.projection.unwrap();
2447 assert_eq!(proj.len(), 3);
2448 assert!(matches!(
2449 &proj[1].expr,
2450 Expr::FunctionCall(AggFunc::Count, _)
2451 ));
2452 assert!(matches!(&proj[2].expr, Expr::FunctionCall(AggFunc::Sum, _)));
2453 }
2454 _ => panic!("expected query"),
2455 }
2456 }
2457
2458 #[test]
2459 fn test_parse_aggregate_in_aliased_projection() {
2460 let stmt = parse("User group .status { .status, total: count(.name), average: avg(.age) }")
2461 .unwrap();
2462 match stmt {
2463 Statement::Query(q) => {
2464 let proj = q.projection.unwrap();
2465 assert_eq!(proj[1].alias.as_deref(), Some("total"));
2466 assert!(matches!(
2467 &proj[1].expr,
2468 Expr::FunctionCall(AggFunc::Count, _)
2469 ));
2470 assert_eq!(proj[2].alias.as_deref(), Some("average"));
2471 assert!(matches!(&proj[2].expr, Expr::FunctionCall(AggFunc::Avg, _)));
2472 }
2473 _ => panic!("expected query"),
2474 }
2475 }
2476
2477 #[test]
2480 fn test_parse_is_null() {
2481 let stmt = parse("User filter .age is null").unwrap();
2482 match stmt {
2483 Statement::Query(q) => {
2484 let filter = q.filter.unwrap();
2485 assert_eq!(
2486 filter,
2487 Expr::UnaryOp(UnaryOp::IsNull, Box::new(Expr::Field("age".into())))
2488 );
2489 }
2490 _ => panic!("expected query"),
2491 }
2492 }
2493
2494 #[test]
2495 fn test_parse_is_not_null() {
2496 let stmt = parse("User filter .age is not null").unwrap();
2497 match stmt {
2498 Statement::Query(q) => {
2499 let filter = q.filter.unwrap();
2500 assert_eq!(
2501 filter,
2502 Expr::UnaryOp(UnaryOp::IsNotNull, Box::new(Expr::Field("age".into())))
2503 );
2504 }
2505 _ => panic!("expected query"),
2506 }
2507 }
2508
2509 #[test]
2510 fn test_parse_eq_null_desugars_to_is_null() {
2511 let stmt = parse("User filter .age = null").unwrap();
2512 match stmt {
2513 Statement::Query(q) => {
2514 let filter = q.filter.unwrap();
2515 assert_eq!(
2516 filter,
2517 Expr::UnaryOp(UnaryOp::IsNull, Box::new(Expr::Field("age".into())))
2518 );
2519 }
2520 _ => panic!("expected query"),
2521 }
2522 }
2523
2524 #[test]
2525 fn test_parse_neq_null_desugars_to_is_not_null() {
2526 let stmt = parse("User filter .age != null").unwrap();
2527 match stmt {
2528 Statement::Query(q) => {
2529 let filter = q.filter.unwrap();
2530 assert_eq!(
2531 filter,
2532 Expr::UnaryOp(UnaryOp::IsNotNull, Box::new(Expr::Field("age".into())))
2533 );
2534 }
2535 _ => panic!("expected query"),
2536 }
2537 }
2538
2539 #[test]
2540 fn test_parse_ordering_null_still_errors() {
2541 assert!(parse("User filter .age < null").is_err());
2543 assert!(parse("User filter .age >= null").is_err());
2544 }
2545
2546 #[test]
2547 fn test_parse_count_star_expr() {
2548 let stmt = parse("User filter count(*) > 0").unwrap();
2549 match stmt {
2550 Statement::Query(q) => {
2551 let filter = q.filter.unwrap();
2552 match filter {
2553 Expr::BinaryOp(left, BinOp::Gt, _) => {
2554 assert_eq!(
2555 *left,
2556 Expr::FunctionCall(AggFunc::Count, Box::new(Expr::Field("*".into())))
2557 );
2558 }
2559 _ => panic!("expected comparison"),
2560 }
2561 }
2562 _ => panic!("expected query"),
2563 }
2564 }
2565
2566 #[test]
2569 fn test_parse_upper_in_filter() {
2570 let stmt = parse(r#"User filter upper(.name) = "ALICE""#).unwrap();
2571 match stmt {
2572 Statement::Query(q) => {
2573 let f = q.filter.unwrap();
2574 match f {
2575 Expr::BinaryOp(left, BinOp::Eq, _right) => {
2576 assert!(matches!(*left, Expr::ScalarFunc(ScalarFn::Upper, _)));
2577 }
2578 _ => panic!("expected binary op with upper"),
2579 }
2580 }
2581 _ => panic!("expected query"),
2582 }
2583 }
2584
2585 #[test]
2586 fn test_parse_substring() {
2587 let stmt = parse("User { sub: substring(.name, 1, 3) }").unwrap();
2588 match stmt {
2589 Statement::Query(q) => {
2590 let proj = q.projection.unwrap();
2591 match &proj[0].expr {
2592 Expr::ScalarFunc(ScalarFn::Substring, args) => {
2593 assert_eq!(args.len(), 3);
2594 }
2595 other => panic!("expected ScalarFunc Substring, got {other:?}"),
2596 }
2597 }
2598 _ => panic!("expected query"),
2599 }
2600 }
2601
2602 #[test]
2603 fn test_parse_concat() {
2604 let stmt = parse(r#"User { full: concat(.name, " - ", .email) }"#).unwrap();
2605 match stmt {
2606 Statement::Query(q) => {
2607 let proj = q.projection.unwrap();
2608 match &proj[0].expr {
2609 Expr::ScalarFunc(ScalarFn::Concat, args) => {
2610 assert_eq!(args.len(), 3);
2611 }
2612 other => panic!("expected ScalarFunc Concat, got {other:?}"),
2613 }
2614 }
2615 _ => panic!("expected query"),
2616 }
2617 }
2618
2619 #[test]
2622 fn test_parse_case_single_when() {
2623 let stmt = parse(r#"User filter case when .age > 30 then true else false end"#).unwrap();
2624 match stmt {
2625 Statement::Query(q) => {
2626 let filter = q.filter.unwrap();
2627 match filter {
2628 Expr::Case { whens, else_expr } => {
2629 assert_eq!(whens.len(), 1);
2630 assert!(else_expr.is_some());
2631 }
2632 other => panic!("expected Case expr, got {other:?}"),
2633 }
2634 }
2635 _ => panic!("expected query"),
2636 }
2637 }
2638
2639 #[test]
2640 fn test_parse_case_multiple_whens() {
2641 let stmt = parse(
2642 r#"User { label: case when .age > 30 then "senior" when .age > 20 then "adult" else "young" end }"#
2643 ).unwrap();
2644 match stmt {
2645 Statement::Query(q) => {
2646 let proj = q.projection.unwrap();
2647 match &proj[0].expr {
2648 Expr::Case { whens, else_expr } => {
2649 assert_eq!(whens.len(), 2);
2650 assert!(else_expr.is_some());
2651 }
2652 other => panic!("expected Case expr, got {other:?}"),
2653 }
2654 }
2655 _ => panic!("expected query"),
2656 }
2657 }
2658
2659 #[test]
2660 fn test_parse_case_without_else() {
2661 let stmt = parse(r#"User filter case when .age > 30 then true end"#).unwrap();
2662 match stmt {
2663 Statement::Query(q) => {
2664 let filter = q.filter.unwrap();
2665 match filter {
2666 Expr::Case { whens, else_expr } => {
2667 assert_eq!(whens.len(), 1);
2668 assert!(else_expr.is_none());
2669 }
2670 other => panic!("expected Case expr, got {other:?}"),
2671 }
2672 }
2673 _ => panic!("expected query"),
2674 }
2675 }
2676
2677 #[test]
2680 fn test_parse_mul_expr() {
2681 let stmt = parse("User filter .price * .quantity > 100").unwrap();
2682 match stmt {
2683 Statement::Query(q) => {
2684 let filter = q.filter.unwrap();
2685 match filter {
2686 Expr::BinaryOp(left, BinOp::Gt, _) => match *left {
2687 Expr::BinaryOp(_, BinOp::Mul, _) => {}
2688 other => panic!("expected Mul, got {other:?}"),
2689 },
2690 other => panic!("expected BinaryOp Gt, got {other:?}"),
2691 }
2692 }
2693 _ => panic!("expected query"),
2694 }
2695 }
2696
2697 #[test]
2698 fn test_parse_div_expr() {
2699 let stmt = parse("User { ratio: .total / .count }").unwrap();
2700 match stmt {
2701 Statement::Query(q) => {
2702 let proj = q.projection.unwrap();
2703 assert_eq!(proj[0].alias.as_deref(), Some("ratio"));
2704 match &proj[0].expr {
2705 Expr::BinaryOp(_, BinOp::Div, _) => {}
2706 other => panic!("expected Div, got {other:?}"),
2707 }
2708 }
2709 _ => panic!("expected query"),
2710 }
2711 }
2712
2713 #[test]
2714 fn test_parse_mul_div_precedence() {
2715 let stmt = parse("User filter .a + .b * .c > 0").unwrap();
2717 match stmt {
2718 Statement::Query(q) => {
2719 let filter = q.filter.unwrap();
2720 match filter {
2721 Expr::BinaryOp(left, BinOp::Gt, _) => match *left {
2722 Expr::BinaryOp(_, BinOp::Add, right) => {
2723 assert!(matches!(*right, Expr::BinaryOp(_, BinOp::Mul, _)));
2724 }
2725 other => panic!("expected Add, got {other:?}"),
2726 },
2727 other => panic!("expected Gt, got {other:?}"),
2728 }
2729 }
2730 _ => panic!("expected query"),
2731 }
2732 }
2733
2734 #[test]
2737 fn test_parse_multi_order() {
2738 let stmt = parse("User order .name asc, .age desc").unwrap();
2739 match stmt {
2740 Statement::Query(q) => {
2741 let order = q.order.unwrap();
2742 assert_eq!(order.keys.len(), 2);
2743 assert_eq!(order.keys[0].field, "name");
2744 assert!(!order.keys[0].descending);
2745 assert_eq!(order.keys[1].field, "age");
2746 assert!(order.keys[1].descending);
2747 }
2748 _ => panic!("expected query"),
2749 }
2750 }
2751
2752 #[test]
2753 fn test_parse_order_default_asc() {
2754 let stmt = parse("User order .name").unwrap();
2755 match stmt {
2756 Statement::Query(q) => {
2757 let order = q.order.unwrap();
2758 assert_eq!(order.keys.len(), 1);
2759 assert!(!order.keys[0].descending);
2760 }
2761 _ => panic!("expected query"),
2762 }
2763 }
2764
2765 #[test]
2768 fn test_parse_alter_add_column() {
2769 let stmt = parse("alter User add column status: str").unwrap();
2770 match stmt {
2771 Statement::AlterTable(at) => {
2772 assert_eq!(at.table, "User");
2773 match at.action {
2774 AlterAction::AddColumn {
2775 name,
2776 type_name,
2777 required,
2778 } => {
2779 assert_eq!(name, "status");
2780 assert_eq!(type_name, "str");
2781 assert!(!required);
2782 }
2783 other => panic!("expected AddColumn, got {other:?}"),
2784 }
2785 }
2786 other => panic!("expected AlterTable, got {other:?}"),
2787 }
2788 }
2789
2790 #[test]
2791 fn test_parse_alter_add_required_column() {
2792 let stmt = parse("alter User add required status: str").unwrap();
2793 match stmt {
2794 Statement::AlterTable(at) => match at.action {
2795 AlterAction::AddColumn { required, .. } => assert!(required),
2796 other => panic!("expected AddColumn, got {other:?}"),
2797 },
2798 other => panic!("expected AlterTable, got {other:?}"),
2799 }
2800 }
2801
2802 #[test]
2803 fn test_parse_alter_drop_column() {
2804 let stmt = parse("alter User drop column status").unwrap();
2805 match stmt {
2806 Statement::AlterTable(at) => {
2807 assert_eq!(at.table, "User");
2808 match at.action {
2809 AlterAction::DropColumn { name } => assert_eq!(name, "status"),
2810 other => panic!("expected DropColumn, got {other:?}"),
2811 }
2812 }
2813 other => panic!("expected AlterTable, got {other:?}"),
2814 }
2815 }
2816
2817 #[test]
2818 fn test_parse_alter_drop_without_column_keyword() {
2819 let stmt = parse("alter User drop status").unwrap();
2820 match stmt {
2821 Statement::AlterTable(at) => match at.action {
2822 AlterAction::DropColumn { name } => assert_eq!(name, "status"),
2823 other => panic!("expected DropColumn, got {other:?}"),
2824 },
2825 other => panic!("expected AlterTable, got {other:?}"),
2826 }
2827 }
2828
2829 #[test]
2830 fn test_parse_drop_table() {
2831 let stmt = parse("drop User").unwrap();
2832 match stmt {
2833 Statement::DropTable(dt) => assert_eq!(dt.table, "User"),
2834 other => panic!("expected DropTable, got {other:?}"),
2835 }
2836 }
2837
2838 #[test]
2841 fn test_parse_in_subquery() {
2842 let stmt = parse("User filter .name in (VIP { .name })").unwrap();
2843 match stmt {
2844 Statement::Query(q) => {
2845 let filter = q.filter.unwrap();
2846 match filter {
2847 Expr::InSubquery {
2848 expr,
2849 subquery,
2850 negated,
2851 } => {
2852 assert!(!negated);
2853 assert!(matches!(*expr, Expr::Field(ref f) if f == "name"));
2854 assert_eq!(subquery.source, "VIP");
2855 }
2856 other => panic!("expected InSubquery, got {other:?}"),
2857 }
2858 }
2859 _ => panic!("expected query"),
2860 }
2861 }
2862
2863 #[test]
2864 fn test_parse_not_in_subquery() {
2865 let stmt = parse("User filter .id not in (Order { .user_id })").unwrap();
2866 match stmt {
2867 Statement::Query(q) => match q.filter.unwrap() {
2868 Expr::InSubquery { negated, .. } => assert!(negated),
2869 other => panic!("expected InSubquery, got {other:?}"),
2870 },
2871 _ => panic!("expected query"),
2872 }
2873 }
2874
2875 #[test]
2876 fn test_parse_in_literal_list_still_works() {
2877 let stmt = parse("User filter .age in (25, 30, 35)").unwrap();
2879 match stmt {
2880 Statement::Query(q) => match q.filter.unwrap() {
2881 Expr::InList { list, negated, .. } => {
2882 assert!(!negated);
2883 assert_eq!(list.len(), 3);
2884 }
2885 other => panic!("expected InList, got {other:?}"),
2886 },
2887 _ => panic!("expected query"),
2888 }
2889 }
2890
2891 #[test]
2894 fn test_parse_create_view() {
2895 let stmt = parse("materialize OldUsers as User filter .age > 28").unwrap();
2896 match stmt {
2897 Statement::CreateView(cv) => {
2898 assert_eq!(cv.name, "OldUsers");
2899 assert_eq!(cv.query.source, "User");
2900 assert!(cv.query.filter.is_some());
2901 assert!(!cv.query_text.is_empty());
2902 }
2903 _ => panic!("expected CreateView"),
2904 }
2905 }
2906
2907 #[test]
2908 fn test_parse_create_view_with_projection() {
2909 let stmt = parse("materialize UserNames as User { .name }").unwrap();
2910 match stmt {
2911 Statement::CreateView(cv) => {
2912 assert_eq!(cv.name, "UserNames");
2913 assert!(cv.query.projection.is_some());
2914 }
2915 _ => panic!("expected CreateView"),
2916 }
2917 }
2918
2919 #[test]
2920 fn test_parse_refresh_view() {
2921 let stmt = parse("refresh OldUsers").unwrap();
2922 match stmt {
2923 Statement::RefreshView(rv) => {
2924 assert_eq!(rv.name, "OldUsers");
2925 }
2926 _ => panic!("expected RefreshView"),
2927 }
2928 }
2929
2930 #[test]
2931 fn test_parse_drop_view() {
2932 let stmt = parse("drop view OldUsers").unwrap();
2933 match stmt {
2934 Statement::DropView(dv) => {
2935 assert_eq!(dv.name, "OldUsers");
2936 }
2937 _ => panic!("expected DropView"),
2938 }
2939 }
2940
2941 #[test]
2942 fn test_parse_drop_table_still_works() {
2943 let stmt = parse("drop Users").unwrap();
2944 match stmt {
2945 Statement::DropTable(dt) => {
2946 assert_eq!(dt.table, "Users");
2947 }
2948 _ => panic!("expected DropTable"),
2949 }
2950 }
2951
2952 #[test]
2953 fn test_parse_union() {
2954 let stmt = parse("User union Order").unwrap();
2955 match stmt {
2956 Statement::Union(u) => {
2957 assert!(!u.all);
2958 match *u.left {
2959 Statement::Query(_) => {}
2960 _ => panic!("expected Query on left"),
2961 }
2962 match *u.right {
2963 Statement::Query(_) => {}
2964 _ => panic!("expected Query on right"),
2965 }
2966 }
2967 _ => panic!("expected Union"),
2968 }
2969 }
2970
2971 #[test]
2972 fn test_parse_union_all() {
2973 let stmt = parse("User union all Order").unwrap();
2974 match stmt {
2975 Statement::Union(u) => {
2976 assert!(u.all, "expected UNION ALL");
2977 match *u.left {
2978 Statement::Query(_) => {}
2979 _ => panic!("expected Query on left"),
2980 }
2981 match *u.right {
2982 Statement::Query(_) => {}
2983 _ => panic!("expected Query on right"),
2984 }
2985 }
2986 _ => panic!("expected Union"),
2987 }
2988 }
2989
2990 #[test]
2991 fn test_parse_union_chain() {
2992 let stmt = parse("User union Order union Product").unwrap();
2994 match stmt {
2995 Statement::Union(outer) => {
2996 assert!(!outer.all);
2997 match *outer.right {
2999 Statement::Query(q) => assert_eq!(q.source, "Product"),
3000 _ => panic!("expected Query(Product) on right"),
3001 }
3002 match *outer.left {
3004 Statement::Union(inner) => {
3005 assert!(!inner.all);
3006 match *inner.left {
3007 Statement::Query(q) => assert_eq!(q.source, "User"),
3008 _ => panic!("expected Query(User)"),
3009 }
3010 match *inner.right {
3011 Statement::Query(q) => assert_eq!(q.source, "Order"),
3012 _ => panic!("expected Query(Order)"),
3013 }
3014 }
3015 _ => panic!("expected inner Union"),
3016 }
3017 }
3018 _ => panic!("expected Union"),
3019 }
3020 }
3021
3022 #[test]
3023 fn test_parse_union_with_filter() {
3024 let stmt = parse("User filter .age > 10 union Order filter .total > 50").unwrap();
3025 match stmt {
3026 Statement::Union(u) => {
3027 assert!(!u.all);
3028 match *u.left {
3030 Statement::Query(q) => {
3031 assert_eq!(q.source, "User");
3032 assert!(q.filter.is_some());
3033 }
3034 _ => panic!("expected Query on left"),
3035 }
3036 match *u.right {
3037 Statement::Query(q) => {
3038 assert_eq!(q.source, "Order");
3039 assert!(q.filter.is_some());
3040 }
3041 _ => panic!("expected Query on right"),
3042 }
3043 }
3044 _ => panic!("expected Union"),
3045 }
3046 }
3047
3048 #[test]
3049 fn test_parse_count_distinct_standalone() {
3050 let stmt = parse("count(distinct User { .name })").unwrap();
3051 match stmt {
3052 Statement::Query(q) => {
3053 let agg = q.aggregation.unwrap();
3054 assert_eq!(agg.function, AggFunc::CountDistinct);
3055 assert_eq!(agg.field.as_deref(), Some("name"));
3056 }
3057 _ => panic!("expected Query"),
3058 }
3059 }
3060
3061 #[test]
3062 fn test_parse_count_distinct_in_projection() {
3063 let stmt = parse("User group .dept { .dept, count(distinct .name) }").unwrap();
3064 match stmt {
3065 Statement::Query(q) => {
3066 let proj = q.projection.unwrap();
3067 assert_eq!(proj.len(), 2);
3068 match &proj[1].expr {
3069 Expr::FunctionCall(func, _) => {
3070 assert_eq!(*func, AggFunc::CountDistinct);
3071 }
3072 _ => panic!("expected FunctionCall"),
3073 }
3074 }
3075 _ => panic!("expected Query"),
3076 }
3077 }
3078
3079 #[test]
3082 fn test_parse_window_row_number_order() {
3083 let stmt = parse("User { .name, rn: row_number() over (order .age) }").unwrap();
3084 match stmt {
3085 Statement::Query(q) => {
3086 let proj = q.projection.unwrap();
3087 assert_eq!(proj.len(), 2);
3088 assert_eq!(proj[1].alias.as_deref(), Some("rn"));
3089 match &proj[1].expr {
3090 Expr::Window {
3091 function,
3092 args,
3093 partition_by,
3094 order_by,
3095 } => {
3096 assert_eq!(*function, WindowFunc::RowNumber);
3097 assert!(args.is_empty());
3098 assert!(partition_by.is_empty());
3099 assert_eq!(order_by.len(), 1);
3100 assert_eq!(order_by[0].field, "age");
3101 assert!(!order_by[0].descending);
3102 }
3103 other => panic!("expected Window, got {other:?}"),
3104 }
3105 }
3106 _ => panic!("expected query"),
3107 }
3108 }
3109
3110 #[test]
3111 fn test_parse_window_sum_partition_order() {
3112 let stmt =
3113 parse("User { .name, s: sum(.salary) over (partition .dept order .salary) }").unwrap();
3114 match stmt {
3115 Statement::Query(q) => {
3116 let proj = q.projection.unwrap();
3117 assert_eq!(proj.len(), 2);
3118 assert_eq!(proj[1].alias.as_deref(), Some("s"));
3119 match &proj[1].expr {
3120 Expr::Window {
3121 function,
3122 args,
3123 partition_by,
3124 order_by,
3125 } => {
3126 assert_eq!(*function, WindowFunc::Sum);
3127 assert_eq!(args.len(), 1);
3128 assert!(matches!(&args[0], Expr::Field(f) if f == "salary"));
3129 assert_eq!(partition_by, &["dept"]);
3130 assert_eq!(order_by.len(), 1);
3131 assert_eq!(order_by[0].field, "salary");
3132 assert!(!order_by[0].descending);
3133 }
3134 other => panic!("expected Window, got {other:?}"),
3135 }
3136 }
3137 _ => panic!("expected query"),
3138 }
3139 }
3140
3141 #[test]
3142 fn test_parse_window_rank_desc() {
3143 let stmt =
3144 parse("User { .dept, .salary, r: rank() over (partition .dept order .salary desc) }")
3145 .unwrap();
3146 match stmt {
3147 Statement::Query(q) => {
3148 let proj = q.projection.unwrap();
3149 assert_eq!(proj.len(), 3);
3150 match &proj[2].expr {
3151 Expr::Window {
3152 function,
3153 partition_by,
3154 order_by,
3155 ..
3156 } => {
3157 assert_eq!(*function, WindowFunc::Rank);
3158 assert_eq!(partition_by, &["dept"]);
3159 assert_eq!(order_by.len(), 1);
3160 assert!(order_by[0].descending);
3161 }
3162 other => panic!("expected Window, got {other:?}"),
3163 }
3164 }
3165 _ => panic!("expected query"),
3166 }
3167 }
3168
3169 #[test]
3170 fn test_parse_window_dense_rank() {
3171 let stmt = parse("User { .name, dr: dense_rank() over (order .score desc) }").unwrap();
3172 match stmt {
3173 Statement::Query(q) => {
3174 let proj = q.projection.unwrap();
3175 assert_eq!(proj.len(), 2);
3176 match &proj[1].expr {
3177 Expr::Window { function, .. } => {
3178 assert_eq!(*function, WindowFunc::DenseRank);
3179 }
3180 other => panic!("expected Window, got {other:?}"),
3181 }
3182 }
3183 _ => panic!("expected query"),
3184 }
3185 }
3186
3187 #[test]
3188 fn test_parse_sum_without_over_is_aggregate() {
3189 let stmt = parse("User group .dept { .dept, total: sum(.salary) }").unwrap();
3191 match stmt {
3192 Statement::Query(q) => {
3193 let proj = q.projection.unwrap();
3194 assert_eq!(proj.len(), 2);
3195 match &proj[1].expr {
3196 Expr::FunctionCall(AggFunc::Sum, _) => {} other => panic!("expected FunctionCall(Sum), got {other:?}"),
3198 }
3199 }
3200 _ => panic!("expected query"),
3201 }
3202 }
3203
3204 #[test]
3205 fn test_nesting_depth_limit() {
3206 let mut query = String::from("User filter ");
3208 for _ in 0..70 {
3209 query.push('(');
3210 }
3211 query.push_str(".age > 1");
3212 for _ in 0..70 {
3213 query.push(')');
3214 }
3215 let result = parse(&query);
3216 assert!(result.is_err());
3217 let err = result.unwrap_err();
3218 assert!(
3219 err.message().contains("nesting depth"),
3220 "expected nesting depth error, got: {}",
3221 err.message()
3222 );
3223 }
3224
3225 #[test]
3226 fn test_moderate_nesting_succeeds() {
3227 let mut query = String::from("User filter ");
3229 for _ in 0..10 {
3230 query.push('(');
3231 }
3232 query.push_str(".age > 1");
3233 for _ in 0..10 {
3234 query.push(')');
3235 }
3236 assert!(parse(&query).is_ok());
3237 }
3238
3239 #[test]
3243 fn test_parse_fuzz_repro_projection_eof() {
3244 let err = parse("nn{").expect_err("unterminated projection must error, not panic");
3245 let _ = err.message();
3246 }
3247
3248 #[test]
3251 fn test_parse_fuzz_repro_short_projection_eof() {
3252 let err = parse("z{").expect_err("unterminated projection must error, not panic");
3253 let _ = err.message();
3254 }
3255}