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