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