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