1use super::error::ParseError;
48use super::Parser;
49use super::PlaceholderMode;
50use crate::ast::{BinOp, Expr, ExprSubquery, FieldRef, Span, UnaryOp};
51use crate::lexer::Token;
52use reddb_types::types::{DataType, Value};
53
54fn is_duration_unit(unit: &str) -> bool {
55 matches!(
56 unit.to_ascii_lowercase().as_str(),
57 "ms" | "msec"
58 | "millisecond"
59 | "milliseconds"
60 | "s"
61 | "sec"
62 | "secs"
63 | "second"
64 | "seconds"
65 | "m"
66 | "min"
67 | "mins"
68 | "minute"
69 | "minutes"
70 | "h"
71 | "hr"
72 | "hrs"
73 | "hour"
74 | "hours"
75 | "d"
76 | "day"
77 | "days"
78 )
79}
80
81fn keyword_function_name(token: &Token) -> Option<&'static str> {
82 match token {
83 Token::Count => Some("COUNT"),
84 Token::Sum => Some("SUM"),
85 Token::Avg => Some("AVG"),
86 Token::Min => Some("MIN"),
87 Token::Max => Some("MAX"),
88 Token::First => Some("FIRST"),
89 Token::Last => Some("LAST"),
90 Token::Left => Some("LEFT"),
91 Token::Right => Some("RIGHT"),
92 Token::Contains => Some("CONTAINS"),
93 Token::Kv => Some("KV"),
94 _ => None,
95 }
96}
97
98fn is_window_eligible_function(name: &str) -> bool {
104 matches!(
105 name.to_ascii_uppercase().as_str(),
106 "LAG"
108 | "LEAD"
109 | "ROW_NUMBER"
110 | "RANK"
111 | "DENSE_RANK"
112 | "PERCENT_RANK"
113 | "CUME_DIST"
114 | "NTILE"
115 | "FIRST_VALUE"
116 | "LAST_VALUE"
117 | "NTH_VALUE"
118 | "COUNT"
120 | "SUM"
121 | "AVG"
122 | "MIN"
123 | "MAX"
124 | "STDDEV"
125 | "VARIANCE"
126 | "MEDIAN"
127 | "PERCENTILE"
128 | "GROUP_CONCAT"
129 | "STRING_AGG"
130 | "FIRST"
131 | "LAST"
132 | "ARRAY_AGG"
133 | "COUNT_DISTINCT"
134 )
135}
136
137fn bare_zero_arg_function_name(name: &str) -> Option<&'static str> {
138 match name.to_ascii_uppercase().as_str() {
139 "CURRENT_TIMESTAMP" => Some("CURRENT_TIMESTAMP"),
140 "CURRENT_DATE" => Some("CURRENT_DATE"),
141 "CURRENT_TIME" => Some("CURRENT_TIME"),
142 _ => None,
143 }
144}
145
146impl<'a> Parser<'a> {
147 pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
150 self.parse_expr_prec(0)
151 }
152
153 pub(crate) fn parse_expr_with_min_precedence(
154 &mut self,
155 min_prec: u8,
156 ) -> Result<Expr, ParseError> {
157 self.parse_expr_prec(min_prec)
158 }
159
160 pub(crate) fn continue_expr(&mut self, left: Expr, min_prec: u8) -> Result<Expr, ParseError> {
163 self.parse_expr_suffix(left, min_prec)
164 }
165
166 fn parse_expr_prec(&mut self, min_prec: u8) -> Result<Expr, ParseError> {
169 self.enter_depth()?;
174 let result = (|| {
175 let left = self.parse_expr_unary()?;
176 self.parse_expr_suffix(left, min_prec)
177 })();
178 self.exit_depth();
179 result
180 }
181
182 fn parse_expr_suffix(&mut self, mut left: Expr, min_prec: u8) -> Result<Expr, ParseError> {
183 let max_infix_chain = self.depth.max_depth.saturating_mul(8).max(1);
184 let mut infix_chain = 0usize;
185 loop {
186 let Some((op, prec)) = self.peek_binop() else {
187 if min_prec <= 32 {
189 if let Some(node) = self.try_parse_postfix(&left)? {
190 left = node;
191 continue;
192 }
193 }
194 if matches!(self.peek(), Token::Arrow) {
201 return Err(ParseError::json_arrow_operator(self.position()));
202 }
203 break;
204 };
205 if prec < min_prec {
206 break;
207 }
208 infix_chain += 1;
209 if infix_chain > max_infix_chain {
210 return Err(ParseError::token_limit(
211 "max_tokens",
212 self.max_tokens,
213 self.position(),
214 ));
215 }
216 self.advance()?; let start_span = self.span_start_of(&left);
218 let rhs = self.parse_expr_prec(prec + 1)?;
219 let end_span = self.span_end_of(&rhs);
220 left = Expr::BinaryOp {
221 op,
222 lhs: Box::new(left),
223 rhs: Box::new(rhs),
224 span: Span::new(start_span, end_span),
225 };
226 }
227 Ok(left)
228 }
229
230 fn parse_expr_unary(&mut self) -> Result<Expr, ParseError> {
233 match self.peek() {
234 Token::Not => {
235 let start = self.position();
236 self.advance()?;
237 let operand = self.parse_expr_prec(25)?;
238 let end = self.span_end_of(&operand);
239 Ok(Expr::UnaryOp {
240 op: UnaryOp::Not,
241 operand: Box::new(operand),
242 span: Span::new(start, end),
243 })
244 }
245 Token::Dash => {
246 let start = self.position();
247 self.advance()?;
248 let operand = self.parse_expr_prec(70)?;
249 let end = self.span_end_of(&operand);
250 Ok(Expr::UnaryOp {
251 op: UnaryOp::Neg,
252 operand: Box::new(operand),
253 span: Span::new(start, end),
254 })
255 }
256 Token::Plus => {
257 self.advance()?;
259 self.parse_expr_prec(70)
260 }
261 _ => self.parse_expr_factor(),
262 }
263 }
264
265 fn parse_expr_factor(&mut self) -> Result<Expr, ParseError> {
268 let start = self.position();
269
270 if self.consume(&Token::LParen)? {
272 if self.check(&Token::Select) {
273 let query = self.parse_select_query()?;
274 self.expect(Token::RParen)?;
275 return Ok(Expr::Subquery {
276 query: ExprSubquery {
277 query: Box::new(query),
278 },
279 span: Span::new(start, self.position()),
280 });
281 }
282 let inner = self.parse_expr_prec(0)?;
283 self.expect(Token::RParen)?;
284 return Ok(inner);
285 }
286
287 if self.consume(&Token::True)? {
289 return Ok(Expr::Literal {
290 value: Value::Boolean(true),
291 span: Span::new(start, self.position()),
292 });
293 }
294 if self.consume(&Token::False)? {
295 return Ok(Expr::Literal {
296 value: Value::Boolean(false),
297 span: Span::new(start, self.position()),
298 });
299 }
300 if self.consume(&Token::Null)? {
301 return Ok(Expr::Literal {
302 value: Value::Null,
303 span: Span::new(start, self.position()),
304 });
305 }
306
307 if let Token::Integer(n) = *self.peek() {
311 self.advance()?;
312 if let Token::Ident(ref unit) = *self.peek() {
313 if is_duration_unit(unit) {
314 let duration = format!("{n}{}", unit.to_ascii_lowercase());
315 self.advance()?;
316 return Ok(Expr::Literal {
317 value: Value::text(duration),
318 span: Span::new(start, self.position()),
319 });
320 }
321 }
322 return Ok(Expr::Literal {
323 value: Value::Integer(n),
324 span: Span::new(start, self.position()),
325 });
326 }
327 if let Token::Float(n) = *self.peek() {
328 self.advance()?;
329 return Ok(Expr::Literal {
330 value: Value::Float(n),
331 span: Span::new(start, self.position()),
332 });
333 }
334 if let Token::String(ref s) = *self.peek() {
335 let text = s.clone();
336 self.advance()?;
337 return Ok(Expr::Literal {
338 value: Value::text(text),
339 span: Span::new(start, self.position()),
340 });
341 }
342
343 if matches!(
348 self.peek(),
349 Token::LBrace | Token::LBracket | Token::JsonLiteral(_)
350 ) {
351 let value = self
352 .parse_literal_value()
353 .map_err(|e| ParseError::new(e.message, self.position()))?;
354 return Ok(Expr::Literal {
355 value,
356 span: Span::new(start, self.position()),
357 });
358 }
359
360 if self.check(&Token::Question) {
364 let (index, span) = self.parse_question_param_index()?;
365 return Ok(Expr::Parameter { index, span });
366 }
367
368 if self.consume(&Token::Dollar)? {
369 if let Token::Integer(n) = *self.peek() {
374 if n < 1 {
375 return Err(ParseError::new(
376 "placeholder index must be >= 1".to_string(),
377 self.position(),
378 ));
379 }
380 if self.placeholder_mode == PlaceholderMode::Question {
381 return Err(ParseError::new(
382 "cannot mix `?` and `$N` placeholders in one statement".to_string(),
383 self.position(),
384 ));
385 }
386 self.placeholder_mode = PlaceholderMode::Dollar;
387 self.advance()?;
388 return Ok(Expr::Parameter {
389 index: (n - 1) as usize,
390 span: Span::new(start, self.position()),
391 });
392 }
393 let path = self.parse_dollar_ref_path()?;
394 let path_lc = path.to_ascii_lowercase();
395 let (name, key) = if let Some(rest) = path_lc.strip_prefix("secret.") {
396 ("__SECRET_REF", format!("red.vault/{rest}"))
397 } else if let Some(rest) = path_lc
398 .strip_prefix("red.secret.")
399 .or_else(|| path_lc.strip_prefix("red.secrets."))
400 {
401 ("__SECRET_REF", format!("red.vault/{rest}"))
402 } else if let Some(rest) = path_lc.strip_prefix("config.") {
403 ("CONFIG", format!("red.config/{rest}"))
404 } else if path_lc.starts_with("red.config.") {
405 let rest = path_lc.trim_start_matches("red.config.");
406 ("CONFIG", format!("red.config/{rest}"))
407 } else if let Some(rest) = path_lc
408 .strip_prefix("kv.")
409 .or_else(|| path_lc.strip_prefix("red.kv."))
410 {
411 ("__KV_REF", format!("red.kv/{rest}"))
415 } else {
416 return Err(ParseError::new(
417 format!(
418 "unknown $ reference `${path}`; expected $secret.*, $red.secret.*, $red.secrets.*, $config.*, $red.config.*, $kv.*, or $red.kv.*"
419 ),
420 self.position(),
421 ));
422 };
423 return Ok(Expr::FunctionCall {
424 name: name.to_string(),
425 args: vec![Expr::Literal {
426 value: Value::text(key),
427 span: Span::new(start, self.position()),
428 }],
429 span: Span::new(start, self.position()),
430 });
431 }
432
433 if let Some(name) = keyword_function_name(self.peek()) {
434 if matches!(self.peek_next()?, Token::LParen) {
435 self.advance()?; return self.parse_function_call_expr_with_name(start, name.to_string());
437 }
438 }
439
440 if let Token::Ident(ref name) = *self.peek() {
448 let name_upper = name.to_uppercase();
449
450 if name_upper == "CASE" {
460 return self.parse_case_expr(start);
461 }
462
463 let saved_name = name.clone();
464 self.advance()?; if matches!(self.peek(), Token::LParen) {
468 return self.parse_function_call_expr_with_name(start, saved_name);
469 }
470
471 if let Some(function_name) = bare_zero_arg_function_name(&saved_name) {
472 let end = self.position();
473 return Ok(Expr::FunctionCall {
474 name: function_name.to_string(),
475 args: Vec::new(),
476 span: Span::new(start, end),
477 });
478 }
479
480 if matches!(self.peek(), Token::Dot) {
482 let mut segments = vec![saved_name];
483 while self.consume(&Token::Dot)? {
484 segments.push(self.expect_ident_or_keyword()?);
485 }
486 if matches!(self.peek(), Token::LParen) {
487 return self.parse_function_call_expr_with_name(start, segments.join("."));
488 }
489 let field = FieldRef::TableColumn {
490 table: segments.remove(0),
491 column: segments.join("."),
492 };
493 let end = self.position();
494 return Ok(Expr::Column {
495 field,
496 span: Span::new(start, end),
497 });
498 }
499
500 let field = FieldRef::TableColumn {
502 table: String::new(),
503 column: saved_name,
504 };
505 let end = self.position();
506 return Ok(Expr::Column {
507 field,
508 span: Span::new(start, end),
509 });
510 }
511
512 let field = self.parse_field_ref()?;
517 let end = self.position();
518 Ok(Expr::Column {
519 field,
520 span: Span::new(start, end),
521 })
522 }
523
524 fn parse_dollar_ref_path(&mut self) -> Result<String, ParseError> {
525 let mut path = self.expect_ident_or_keyword()?;
526 while self.consume(&Token::Dot)? {
527 let next = self.expect_ident_or_keyword()?;
528 path = format!("{path}.{next}");
529 }
530 Ok(path)
531 }
532
533 fn parse_function_call_expr_with_name(
534 &mut self,
535 start: crate::lexer::Position,
536 function_name: String,
537 ) -> Result<Expr, ParseError> {
538 let call = self.parse_function_call_expr_with_name_inner(start, function_name)?;
539 if matches!(self.peek(), Token::Over) {
545 return self.lift_to_window_call(start, call);
546 }
547 Ok(call)
548 }
549
550 fn parse_function_call_expr_with_name_inner(
551 &mut self,
552 start: crate::lexer::Position,
553 function_name: String,
554 ) -> Result<Expr, ParseError> {
555 self.expect(Token::LParen)?;
556
557 if function_name.eq_ignore_ascii_case("CAST") {
558 let inner = self.parse_expr_prec(0)?;
559 self.expect(Token::As)?;
560 let type_name = self.expect_ident_or_keyword()?;
561 self.expect(Token::RParen)?;
562 let end = self.position();
563 let Some(target) = DataType::from_sql_name(&type_name) else {
564 return Err(ParseError::new(
565 format!("unknown type name {type_name:?} in CAST"),
569 self.position(),
570 ));
571 };
572 return Ok(Expr::Cast {
573 inner: Box::new(inner),
574 target,
575 span: Span::new(start, end),
576 });
577 }
578
579 if function_name.eq_ignore_ascii_case("GEO_WITHIN") {
585 let column = self.parse_geo_column_expr()?;
586 self.expect(Token::Comma)?;
587 let polygon = self.parse_expr_prec(0)?;
588 self.expect(Token::RParen)?;
589 let end = self.position();
590 return Ok(Expr::FunctionCall {
591 name: function_name,
592 args: vec![column, polygon],
593 span: Span::new(start, end),
594 });
595 }
596
597 if function_name.eq_ignore_ascii_case("POLYGON") {
604 let args = self.parse_polygon_vertex_args()?;
605 self.expect(Token::RParen)?;
606 let end = self.position();
607 return Ok(Expr::FunctionCall {
608 name: function_name,
609 args,
610 span: Span::new(start, end),
611 });
612 }
613
614 if function_name.eq_ignore_ascii_case("TRIM") {
615 let (name, args) = self.parse_trim_expr_args()?;
616 self.expect(Token::RParen)?;
617 let end = self.position();
618 return Ok(Expr::FunctionCall {
619 name,
620 args,
621 span: Span::new(start, end),
622 });
623 }
624
625 if function_name.eq_ignore_ascii_case("POSITION") {
626 let args = self.parse_position_expr_args()?;
627 self.expect(Token::RParen)?;
628 let end = self.position();
629 return Ok(Expr::FunctionCall {
630 name: function_name,
631 args,
632 span: Span::new(start, end),
633 });
634 }
635
636 if function_name.eq_ignore_ascii_case("SUBSTRING") {
637 let args = self.parse_substring_expr_args()?;
638 self.expect(Token::RParen)?;
639 let end = self.position();
640 return Ok(Expr::FunctionCall {
641 name: function_name,
642 args,
643 span: Span::new(start, end),
644 });
645 }
646
647 if function_name.eq_ignore_ascii_case("COUNT") {
648 if self.consume(&Token::Distinct)? {
649 let arg = self.parse_expr_prec(0)?;
650 self.expect(Token::RParen)?;
651 let end = self.position();
652 return Ok(Expr::FunctionCall {
653 name: "COUNT_DISTINCT".to_string(),
654 args: vec![arg],
655 span: Span::new(start, end),
656 });
657 }
658
659 if self.consume(&Token::Star)? {
660 self.expect(Token::RParen)?;
661 let end = self.position();
662 return Ok(Expr::FunctionCall {
663 name: function_name,
664 args: vec![Expr::Column {
665 field: FieldRef::TableColumn {
666 table: String::new(),
667 column: "*".to_string(),
668 },
669 span: Span::synthetic(),
670 }],
671 span: Span::new(start, end),
672 });
673 }
674 }
675
676 if function_name.eq_ignore_ascii_case("CONFIG") || function_name.eq_ignore_ascii_case("KV")
687 {
688 let mut args = Vec::new();
689 if !self.check(&Token::RParen) {
690 loop {
691 args.push(self.parse_config_kv_arg(start)?);
692 if !self.consume(&Token::Comma)? {
693 break;
694 }
695 }
696 }
697 self.expect(Token::RParen)?;
698 let end = self.position();
699 return Ok(Expr::FunctionCall {
700 name: function_name,
701 args,
702 span: Span::new(start, end),
703 });
704 }
705
706 let mut args = Vec::new();
707 if !self.check(&Token::RParen) {
708 loop {
709 args.push(self.parse_expr_prec(0)?);
710 if !self.consume(&Token::Comma)? {
711 break;
712 }
713 }
714 }
715 self.expect(Token::RParen)?;
716 let end = self.position();
717 Ok(Expr::FunctionCall {
718 name: function_name,
719 args,
720 span: Span::new(start, end),
721 })
722 }
723
724 fn parse_geo_column_expr(&mut self) -> Result<Expr, ParseError> {
730 let start = self.position();
731 let mut segments = vec![self.expect_spatial_column_segment()?];
732 while self.consume(&Token::Dot)? {
733 segments.push(self.expect_spatial_column_segment()?);
734 }
735 let table = if segments.len() > 1 {
736 segments.remove(0)
737 } else {
738 String::new()
739 };
740 Ok(Expr::Column {
741 field: FieldRef::TableColumn {
742 table,
743 column: segments.join("."),
744 },
745 span: Span::new(start, self.position()),
746 })
747 }
748
749 fn parse_polygon_vertex_args(&mut self) -> Result<Vec<Expr>, ParseError> {
755 let pos = self.position();
756 let mut args = Vec::new();
757 loop {
758 self.expect(Token::LParen)?;
759 args.push(self.parse_polygon_coordinate()?);
760 args.push(self.parse_polygon_coordinate()?);
761 self.expect(Token::RParen)?;
762 if !self.consume(&Token::Comma)? {
763 break;
764 }
765 }
766 if let Some(vertices) = crate::ast::geo_predicate::literal_polygon_vertices(&args) {
767 super::search_commands::validate_polygon_vertices(&vertices, "POLYGON", pos)?;
768 } else if args.len() < 6 || !args.len().is_multiple_of(2) {
769 return Err(ParseError::new(
770 "POLYGON requires at least 3 vertices".to_string(),
771 pos,
772 ));
773 }
774 Ok(args)
775 }
776
777 fn parse_polygon_coordinate(&mut self) -> Result<Expr, ParseError> {
790 const ABOVE_ADDITIVE: u8 = 70;
791 let start = self.position();
792 if self.polygon_coordinate_is_numeric()? {
793 let value = self.parse_float()?;
794 return Ok(Expr::Literal {
795 value: Value::Float(value),
796 span: Span::new(start, self.position()),
797 });
798 }
799 self.parse_expr_prec(ABOVE_ADDITIVE)
800 }
801
802 fn polygon_coordinate_is_numeric(&mut self) -> Result<bool, ParseError> {
803 if matches!(self.peek(), Token::Float(_) | Token::Integer(_)) {
804 return Ok(true);
805 }
806 if matches!(self.peek(), Token::Minus | Token::Dash) {
807 return Ok(matches!(
808 self.peek_next()?,
809 Token::Float(_) | Token::Integer(_)
810 ));
811 }
812 Ok(false)
813 }
814
815 fn parse_config_kv_arg(&mut self, start: crate::lexer::Position) -> Result<Expr, ParseError> {
822 let mut is_expression_start = matches!(
827 self.peek(),
828 Token::String(_)
829 | Token::Integer(_)
830 | Token::Float(_)
831 | Token::Dollar
832 | Token::Question
833 | Token::LParen
834 );
835 if matches!(self.peek(), Token::Ident(_)) && matches!(self.peek_next()?, Token::LParen) {
838 is_expression_start = true;
839 }
840 if !is_expression_start && !self.check(&Token::RParen) {
841 let mut path = self.expect_ident_or_keyword()?;
842 while self.consume(&Token::Dot)? {
843 let next = self.expect_ident_or_keyword()?;
844 path = format!("{path}.{next}");
845 }
846 let end = self.position();
847 return Ok(Expr::Literal {
848 value: Value::text(path.to_ascii_lowercase()),
849 span: Span::new(start, end),
850 });
851 }
852 self.parse_expr_prec(0)
853 }
854
855 fn lift_to_window_call(
862 &mut self,
863 start: crate::lexer::Position,
864 call: Expr,
865 ) -> Result<Expr, ParseError> {
866 let (name, args) = match call {
867 Expr::FunctionCall { name, args, .. } => (name, args),
868 other => {
869 return Err(ParseError::new(
870 format!(
871 "OVER may only follow a function call, got {:?}",
872 std::mem::discriminant(&other)
873 ),
874 self.position(),
875 ));
876 }
877 };
878 if !is_window_eligible_function(&name) {
879 return Err(ParseError::new(
880 format!(
881 "function `{}` cannot be used with an OVER clause; \
882 expected a window function (LAG, LEAD, ROW_NUMBER, \
883 RANK, DENSE_RANK) or an aggregate",
884 name.to_uppercase()
885 ),
886 self.position(),
887 ));
888 }
889 let window = self.parse_over_clause()?;
890 let end = self.position();
891 Ok(Expr::WindowFunctionCall {
892 name,
893 args,
894 window,
895 span: Span::new(start, end),
896 })
897 }
898
899 fn parse_over_clause(&mut self) -> Result<crate::ast::WindowSpec, ParseError> {
902 self.expect(Token::Over)?;
903 self.expect(Token::LParen)?;
904
905 let mut spec = crate::ast::WindowSpec::default();
906
907 if self.consume(&Token::Partition)? {
908 self.expect(Token::By)?;
909 loop {
910 spec.partition_by.push(self.parse_expr_prec(0)?);
911 if !self.consume(&Token::Comma)? {
912 break;
913 }
914 }
915 }
916
917 if self.consume(&Token::Order)? {
918 self.expect(Token::By)?;
919 loop {
920 let expr = self.parse_expr_prec(0)?;
921 let ascending = if self.consume(&Token::Desc)? {
922 false
923 } else {
924 self.consume(&Token::Asc)?;
925 true
926 };
927 let mut nulls_first = !ascending;
930 if self.consume(&Token::Nulls)? {
931 if self.consume(&Token::First)? {
932 nulls_first = true;
933 } else if self.consume(&Token::Last)? {
934 nulls_first = false;
935 } else {
936 return Err(ParseError::new(
937 "expected FIRST or LAST after NULLS".to_string(),
938 self.position(),
939 ));
940 }
941 }
942 spec.order_by.push(crate::ast::WindowOrderItem {
943 expr,
944 ascending,
945 nulls_first,
946 });
947 if !self.consume(&Token::Comma)? {
948 break;
949 }
950 }
951 }
952
953 if matches!(self.peek(), Token::Rows | Token::Range) {
954 spec.frame = Some(self.parse_window_frame()?);
955 }
956
957 self.expect(Token::RParen)?;
958 Ok(spec)
959 }
960
961 fn parse_window_frame(&mut self) -> Result<crate::ast::WindowFrame, ParseError> {
962 let unit = if self.consume(&Token::Rows)? {
963 crate::ast::WindowFrameUnit::Rows
964 } else if self.consume(&Token::Range)? {
965 crate::ast::WindowFrameUnit::Range
966 } else {
967 return Err(ParseError::new(
968 "expected ROWS or RANGE in window frame".to_string(),
969 self.position(),
970 ));
971 };
972
973 if self.consume(&Token::Between)? {
974 let start = self.parse_window_frame_bound()?;
975 self.expect(Token::And)?;
976 let end = self.parse_window_frame_bound()?;
977 Ok(crate::ast::WindowFrame {
978 unit,
979 start,
980 end: Some(end),
981 })
982 } else {
983 let start = self.parse_window_frame_bound()?;
984 Ok(crate::ast::WindowFrame {
985 unit,
986 start,
987 end: None,
988 })
989 }
990 }
991
992 fn parse_window_frame_bound(&mut self) -> Result<crate::ast::WindowFrameBound, ParseError> {
993 use crate::ast::WindowFrameBound;
994 if self.consume(&Token::Unbounded)? {
995 if self.consume(&Token::Preceding)? {
996 return Ok(WindowFrameBound::UnboundedPreceding);
997 }
998 if self.consume(&Token::Following)? {
999 return Ok(WindowFrameBound::UnboundedFollowing);
1000 }
1001 return Err(ParseError::new(
1002 "expected PRECEDING or FOLLOWING after UNBOUNDED".to_string(),
1003 self.position(),
1004 ));
1005 }
1006 if self.consume(&Token::Current)? {
1007 self.expect(Token::Row)?;
1008 return Ok(WindowFrameBound::CurrentRow);
1009 }
1010 let offset = self.parse_expr_prec(0)?;
1012 if self.consume(&Token::Preceding)? {
1013 return Ok(WindowFrameBound::Preceding(Box::new(offset)));
1014 }
1015 if self.consume(&Token::Following)? {
1016 return Ok(WindowFrameBound::Following(Box::new(offset)));
1017 }
1018 Err(ParseError::new(
1019 "expected PRECEDING or FOLLOWING after frame offset".to_string(),
1020 self.position(),
1021 ))
1022 }
1023
1024 fn parse_case_expr(&mut self, start: crate::lexer::Position) -> Result<Expr, ParseError> {
1036 self.advance()?; let selector = if matches!(self.peek(), Token::Ident(id) if id.eq_ignore_ascii_case("WHEN"))
1039 {
1040 None
1041 } else {
1042 Some(self.parse_expr_prec(0)?)
1043 };
1044 let mut branches: Vec<(Expr, Expr)> = Vec::new();
1045 loop {
1046 if !self.consume_ident_ci("WHEN")? {
1047 break;
1048 }
1049 let when_val = self.parse_expr_prec(0)?;
1050 let cond = match &selector {
1053 None => when_val,
1054 Some(sel) => {
1055 let span = Span::new(sel.span().start, when_val.span().end);
1056 Expr::BinaryOp {
1057 op: BinOp::Eq,
1058 lhs: Box::new(sel.clone()),
1059 rhs: Box::new(when_val),
1060 span,
1061 }
1062 }
1063 };
1064 if !self.consume_ident_ci("THEN")? {
1065 return Err(ParseError::new(
1066 "expected THEN after CASE WHEN condition".to_string(),
1067 self.position(),
1068 ));
1069 }
1070 let then_val = self.parse_expr_prec(0)?;
1071 branches.push((cond, then_val));
1072 }
1073 if branches.is_empty() {
1074 return Err(ParseError::new(
1075 "CASE must have at least one WHEN branch".to_string(),
1076 self.position(),
1077 ));
1078 }
1079 let else_ = if self.consume_ident_ci("ELSE")? {
1080 Some(Box::new(self.parse_expr_prec(0)?))
1081 } else {
1082 None
1083 };
1084 if !self.consume_ident_ci("END")? {
1085 return Err(ParseError::new(
1086 "expected END to close CASE expression".to_string(),
1087 self.position(),
1088 ));
1089 }
1090 let end = self.position();
1091 Ok(Expr::Case {
1092 branches,
1093 else_,
1094 span: Span::new(start, end),
1095 })
1096 }
1097
1098 fn parse_trim_expr_args(&mut self) -> Result<(String, Vec<Expr>), ParseError> {
1099 let mut function_name = "TRIM".to_string();
1100
1101 if self.consume_ident_ci("LEADING")? {
1102 function_name = "LTRIM".to_string();
1103 } else if self.consume_ident_ci("TRAILING")? {
1104 function_name = "RTRIM".to_string();
1105 } else if self.consume_ident_ci("BOTH")? {
1106 function_name = "TRIM".to_string();
1107 }
1108
1109 if self.consume(&Token::From)? {
1110 let source = self.parse_expr_prec(0)?;
1111 return Ok((function_name, vec![source]));
1112 }
1113
1114 let first = self.parse_expr_prec(0)?;
1115
1116 if self.consume(&Token::Comma)? {
1117 let second = self.parse_expr_prec(0)?;
1118 return Ok((function_name, vec![first, second]));
1119 }
1120
1121 if self.consume(&Token::From)? {
1122 let source = self.parse_expr_prec(0)?;
1123 return Ok((function_name, vec![source, first]));
1124 }
1125
1126 Ok((function_name, vec![first]))
1127 }
1128
1129 fn parse_position_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
1133 let needle = self.parse_expr_prec(35)?;
1137 if !self.consume(&Token::Comma)? {
1138 self.expect(Token::In)?;
1139 }
1140 let haystack = self.parse_expr_prec(0)?;
1141 Ok(vec![needle, haystack])
1142 }
1143
1144 fn parse_substring_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
1152 let source = self.parse_expr_prec(0)?;
1153
1154 if self.consume(&Token::Comma)? {
1155 let mut args = vec![source];
1156 loop {
1157 args.push(self.parse_expr_prec(0)?);
1158 if !self.consume(&Token::Comma)? {
1159 break;
1160 }
1161 }
1162 return Ok(args);
1163 }
1164
1165 if self.consume(&Token::From)? {
1166 let start = self.parse_expr_prec(0)?;
1167 if self.consume(&Token::For)? {
1168 let count = self.parse_expr_prec(0)?;
1169 return Ok(vec![source, start, count]);
1170 }
1171 return Ok(vec![source, start]);
1172 }
1173
1174 if self.consume(&Token::For)? {
1175 let count = self.parse_expr_prec(0)?;
1176 if self.consume(&Token::From)? {
1177 let start = self.parse_expr_prec(0)?;
1178 return Ok(vec![source, start, count]);
1179 }
1180 return Ok(vec![source, Expr::lit(Value::Integer(1)), count]);
1181 }
1182
1183 Ok(vec![source])
1184 }
1185
1186 fn try_parse_postfix(&mut self, left: &Expr) -> Result<Option<Expr>, ParseError> {
1196 let start = self.span_start_of(left);
1197
1198 if self.consume(&Token::Is)? {
1200 let negated = self.consume(&Token::Not)?;
1201 self.expect(Token::Null)?;
1202 let end = self.position();
1203 return Ok(Some(Expr::IsNull {
1204 operand: Box::new(left.clone()),
1205 negated,
1206 span: Span::new(start, end),
1207 }));
1208 }
1209
1210 let negated = if matches!(self.peek(), Token::Not) {
1214 self.advance()?;
1215 if !matches!(self.peek(), Token::Between | Token::In) {
1216 return Err(ParseError::new(
1217 "expected BETWEEN or IN after postfix NOT".to_string(),
1218 self.position(),
1219 ));
1220 }
1221 true
1222 } else {
1223 false
1224 };
1225
1226 if self.consume(&Token::Between)? {
1228 let low = self.parse_expr_prec(34)?;
1229 self.expect(Token::And)?;
1230 let high = self.parse_expr_prec(34)?;
1231 let end = self.position();
1232 return Ok(Some(Expr::Between {
1233 target: Box::new(left.clone()),
1234 low: Box::new(low),
1235 high: Box::new(high),
1236 negated,
1237 span: Span::new(start, end),
1238 }));
1239 }
1240
1241 if self.consume(&Token::In)? {
1243 self.expect(Token::LParen)?;
1244 let mut values = Vec::new();
1245 if self.check(&Token::Select) {
1246 let query = self.parse_select_query()?;
1247 values.push(Expr::Subquery {
1248 query: ExprSubquery {
1249 query: Box::new(query),
1250 },
1251 span: Span::new(self.span_start_of(left), self.position()),
1252 });
1253 } else if !self.check(&Token::RParen) {
1254 loop {
1255 values.push(self.parse_expr_prec(0)?);
1256 if !self.consume(&Token::Comma)? {
1257 break;
1258 }
1259 }
1260 }
1261 self.expect(Token::RParen)?;
1262 let end = self.position();
1263 return Ok(Some(Expr::InList {
1264 target: Box::new(left.clone()),
1265 values,
1266 negated,
1267 span: Span::new(start, end),
1268 }));
1269 }
1270
1271 if negated {
1272 return Err(ParseError::new(
1276 "internal: NOT consumed without BETWEEN/IN follow".to_string(),
1277 self.position(),
1278 ));
1279 }
1280 Ok(None)
1281 }
1282
1283 fn peek_binop(&self) -> Option<(BinOp, u8)> {
1287 let op = match self.peek() {
1288 Token::Or => BinOp::Or,
1289 Token::And => BinOp::And,
1290 Token::Eq => BinOp::Eq,
1291 Token::Ne => BinOp::Ne,
1292 Token::Lt => BinOp::Lt,
1293 Token::Le => BinOp::Le,
1294 Token::Gt => BinOp::Gt,
1295 Token::Ge => BinOp::Ge,
1296 Token::DoublePipe => BinOp::Concat,
1297 Token::Plus => BinOp::Add,
1298 Token::Dash => BinOp::Sub,
1299 Token::Star => BinOp::Mul,
1300 Token::Slash => BinOp::Div,
1301 Token::Percent => BinOp::Mod,
1302 _ => return None,
1303 };
1304 Some((op, op.precedence()))
1305 }
1306
1307 fn span_start_of(&self, expr: &Expr) -> crate::lexer::Position {
1312 let s = expr.span();
1313 if s.is_synthetic() {
1314 self.position()
1315 } else {
1316 s.start
1317 }
1318 }
1319
1320 fn span_end_of(&self, expr: &Expr) -> crate::lexer::Position {
1323 let s = expr.span();
1324 if s.is_synthetic() {
1325 self.position()
1326 } else {
1327 s.end
1328 }
1329 }
1330}
1331
1332#[allow(dead_code)]
1335fn _expr_module_used(_: Expr) {}
1336
1337#[cfg(test)]
1338mod tests {
1339 use super::*;
1340 use crate::ast::FieldRef;
1341
1342 fn parse(input: &str) -> Expr {
1343 let mut parser = Parser::new(input).expect("lexer init");
1344 let expr = parser.parse_expr().expect("parse_expr");
1345 expr
1346 }
1347
1348 #[test]
1349 fn literal_integer() {
1350 let e = parse("42");
1351 match e {
1352 Expr::Literal {
1353 value: Value::Integer(42),
1354 ..
1355 } => {}
1356 other => panic!("expected Integer(42), got {other:?}"),
1357 }
1358 }
1359
1360 #[test]
1361 fn literal_float() {
1362 let e = parse("3.14");
1363 match e {
1364 Expr::Literal {
1365 value: Value::Float(f),
1366 ..
1367 } => assert!((f - 3.14).abs() < 1e-9),
1368 other => panic!("expected float literal, got {other:?}"),
1369 }
1370 }
1371
1372 #[test]
1373 fn literal_string() {
1374 let e = parse("'hello'");
1375 match e {
1376 Expr::Literal {
1377 value: Value::Text(ref s),
1378 ..
1379 } if s.as_ref() == "hello" => {}
1380 other => panic!("expected Text(hello), got {other:?}"),
1381 }
1382 }
1383
1384 #[test]
1385 fn literal_booleans_and_null() {
1386 assert!(matches!(
1387 parse("TRUE"),
1388 Expr::Literal {
1389 value: Value::Boolean(true),
1390 ..
1391 }
1392 ));
1393 assert!(matches!(
1394 parse("FALSE"),
1395 Expr::Literal {
1396 value: Value::Boolean(false),
1397 ..
1398 }
1399 ));
1400 assert!(matches!(
1401 parse("NULL"),
1402 Expr::Literal {
1403 value: Value::Null,
1404 ..
1405 }
1406 ));
1407 }
1408
1409 #[test]
1410 fn bare_column() {
1411 let e = parse("user_id");
1412 match e {
1413 Expr::Column {
1414 field: FieldRef::TableColumn { column, .. },
1415 ..
1416 } => {
1417 assert_eq!(column, "user_id");
1418 }
1419 other => panic!("expected column, got {other:?}"),
1420 }
1421 }
1422
1423 #[test]
1424 fn arithmetic_precedence_mul_over_add() {
1425 let e = parse("a + b * c");
1427 let Expr::BinaryOp {
1428 op: BinOp::Add,
1429 rhs,
1430 ..
1431 } = e
1432 else {
1433 panic!("root must be Add");
1434 };
1435 let Expr::BinaryOp { op: BinOp::Mul, .. } = *rhs else {
1436 panic!("rhs must be Mul");
1437 };
1438 }
1439
1440 #[test]
1441 fn arithmetic_left_associativity() {
1442 let e = parse("a - b - c");
1444 let Expr::BinaryOp {
1445 op: BinOp::Sub,
1446 lhs,
1447 ..
1448 } = e
1449 else {
1450 panic!("root must be Sub");
1451 };
1452 let Expr::BinaryOp { op: BinOp::Sub, .. } = *lhs else {
1453 panic!("lhs must be Sub (left-assoc)");
1454 };
1455 }
1456
1457 #[test]
1458 fn parenthesised_override() {
1459 let e = parse("(a + b) * c");
1461 let Expr::BinaryOp {
1462 op: BinOp::Mul,
1463 lhs,
1464 ..
1465 } = e
1466 else {
1467 panic!("root must be Mul");
1468 };
1469 let Expr::BinaryOp { op: BinOp::Add, .. } = *lhs else {
1470 panic!("lhs must be Add");
1471 };
1472 }
1473
1474 #[test]
1475 fn comparison_binds_weaker_than_arith() {
1476 let e = parse("a + 1 = b - 2");
1479 let Expr::BinaryOp {
1480 op: BinOp::Eq,
1481 lhs,
1482 rhs,
1483 ..
1484 } = e
1485 else {
1486 panic!("root must be Eq");
1487 };
1488 assert!(matches!(*lhs, Expr::BinaryOp { op: BinOp::Add, .. }));
1489 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::Sub, .. }));
1490 }
1491
1492 #[test]
1493 fn and_binds_tighter_than_or() {
1494 let e = parse("a OR b AND c");
1496 let Expr::BinaryOp {
1497 op: BinOp::Or, rhs, ..
1498 } = e
1499 else {
1500 panic!("root must be Or");
1501 };
1502 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::And, .. }));
1503 }
1504
1505 #[test]
1506 fn unary_negation() {
1507 let e = parse("-a");
1508 let Expr::UnaryOp {
1509 op: UnaryOp::Neg, ..
1510 } = e
1511 else {
1512 panic!("expected unary Neg");
1513 };
1514 }
1515
1516 #[test]
1517 fn unary_not() {
1518 let e = parse("NOT a");
1519 let Expr::UnaryOp {
1520 op: UnaryOp::Not, ..
1521 } = e
1522 else {
1523 panic!("expected unary Not");
1524 };
1525 }
1526
1527 #[test]
1528 fn concat_operator() {
1529 let e = parse("'hello' || name");
1530 let Expr::BinaryOp {
1531 op: BinOp::Concat, ..
1532 } = e
1533 else {
1534 panic!("expected Concat");
1535 };
1536 }
1537
1538 #[test]
1539 fn cast_expr() {
1540 let e = parse("CAST(age AS TEXT)");
1541 let Expr::Cast { target, .. } = e else {
1542 panic!("expected Cast");
1543 };
1544 assert_eq!(target, DataType::Text);
1545 }
1546
1547 #[test]
1548 fn case_expr() {
1549 let e = parse("CASE WHEN a = 1 THEN 'one' WHEN a = 2 THEN 'two' ELSE 'other' END");
1550 let Expr::Case {
1551 branches, else_, ..
1552 } = e
1553 else {
1554 panic!("expected Case");
1555 };
1556 assert_eq!(branches.len(), 2);
1557 assert!(else_.is_some());
1558 }
1559
1560 #[test]
1561 fn simple_case_desugars_to_equality() {
1562 let e = parse("CASE id WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'many' END");
1563 let Expr::Case {
1564 branches, else_, ..
1565 } = e
1566 else {
1567 panic!("expected Case");
1568 };
1569 assert_eq!(branches.len(), 2);
1570 assert!(else_.is_some());
1571 for (cond, _) in &branches {
1573 let Expr::BinaryOp { op, lhs, .. } = cond else {
1574 panic!("expected desugared equality condition");
1575 };
1576 assert_eq!(*op, BinOp::Eq);
1577 assert!(matches!(**lhs, Expr::Column { .. }));
1578 }
1579 }
1580
1581 #[test]
1582 fn is_null_postfix() {
1583 let e = parse("name IS NULL");
1584 assert!(matches!(e, Expr::IsNull { negated: false, .. }));
1585 }
1586
1587 #[test]
1588 fn is_not_null_postfix() {
1589 let e = parse("name IS NOT NULL");
1590 assert!(matches!(e, Expr::IsNull { negated: true, .. }));
1591 }
1592
1593 #[test]
1594 fn between_with_columns() {
1595 let e = parse("temp BETWEEN min_t AND max_t");
1596 let Expr::Between {
1597 target,
1598 low,
1599 high,
1600 negated,
1601 ..
1602 } = e
1603 else {
1604 panic!("expected Between");
1605 };
1606 assert!(!negated);
1607 assert!(matches!(*target, Expr::Column { .. }));
1608 assert!(matches!(*low, Expr::Column { .. }));
1609 assert!(matches!(*high, Expr::Column { .. }));
1610 }
1611
1612 #[test]
1613 fn not_between_negates() {
1614 let e = parse("temp NOT BETWEEN 0 AND 100");
1615 let Expr::Between { negated: true, .. } = e else {
1616 panic!("expected negated Between");
1617 };
1618 }
1619
1620 #[test]
1621 fn in_list_literal() {
1622 let e = parse("status IN (1, 2, 3)");
1623 let Expr::InList {
1624 values, negated, ..
1625 } = e
1626 else {
1627 panic!("expected InList");
1628 };
1629 assert!(!negated);
1630 assert_eq!(values.len(), 3);
1631 }
1632
1633 #[test]
1634 fn not_in_list() {
1635 let e = parse("status NOT IN (1, 2)");
1636 let Expr::InList { negated: true, .. } = e else {
1637 panic!("expected negated InList");
1638 };
1639 }
1640
1641 #[test]
1642 fn function_call_with_args() {
1643 let e = parse("UPPER(name)");
1644 let Expr::FunctionCall { name, args, .. } = e else {
1645 panic!("expected FunctionCall");
1646 };
1647 assert_eq!(name, "UPPER");
1648 assert_eq!(args.len(), 1);
1649 }
1650
1651 #[test]
1652 fn nested_function_call() {
1653 let e = parse("COALESCE(a, UPPER(b))");
1654 let Expr::FunctionCall { name, args, .. } = e else {
1655 panic!("expected FunctionCall");
1656 };
1657 assert_eq!(name, "COALESCE");
1658 assert_eq!(args.len(), 2);
1659 assert!(matches!(&args[1], Expr::FunctionCall { .. }));
1660 }
1661
1662 #[test]
1663 fn duration_literal_parses_as_text() {
1664 let e = parse("time_bucket(5m)");
1665 let Expr::FunctionCall { name, args, .. } = e else {
1666 panic!("expected FunctionCall, got {e:?}");
1667 };
1668 assert_eq!(name.to_uppercase(), "TIME_BUCKET");
1669 assert_eq!(args.len(), 1);
1670 assert!(
1671 matches!(&args[0], Expr::Literal { value: Value::Text(s), .. } if s.as_ref() == "5m"),
1672 "expected Text(\"5m\"), got {:?}",
1673 args[0]
1674 );
1675 }
1676
1677 #[test]
1678 fn placeholder_dollar_one() {
1679 let e = parse("$1");
1680 match e {
1681 Expr::Parameter { index: 0, .. } => {}
1682 other => panic!("expected Parameter(0), got {other:?}"),
1683 }
1684 }
1685
1686 #[test]
1687 fn placeholder_dollar_n() {
1688 let e = parse("$7");
1689 match e {
1690 Expr::Parameter { index: 6, .. } => {}
1691 other => panic!("expected Parameter(6), got {other:?}"),
1692 }
1693 }
1694
1695 #[test]
1696 fn placeholder_in_string_literal_is_text() {
1697 let e = parse("'$1'");
1699 match e {
1700 Expr::Literal {
1701 value: Value::Text(s),
1702 ..
1703 } if s.as_ref() == "$1" => {}
1704 other => panic!("expected text literal '$1', got {other:?}"),
1705 }
1706 }
1707
1708 #[test]
1709 fn placeholder_in_comparison() {
1710 let e = parse("id = $1");
1712 let Expr::BinaryOp {
1713 op: BinOp::Eq, rhs, ..
1714 } = e
1715 else {
1716 panic!("root must be Eq");
1717 };
1718 assert!(matches!(*rhs, Expr::Parameter { index: 0, .. }));
1719 }
1720
1721 #[test]
1722 fn placeholder_zero_rejected() {
1723 let mut parser = Parser::new("$0").expect("lexer");
1724 let err = parser.parse_expr().unwrap_err();
1725 assert!(err.to_string().contains("placeholder"));
1726 }
1727
1728 #[test]
1729 fn placeholder_question_single() {
1730 let e = parse("?");
1732 match e {
1733 Expr::Parameter { index: 0, .. } => {}
1734 other => panic!("expected Parameter(0), got {other:?}"),
1735 }
1736 }
1737
1738 #[test]
1739 fn placeholder_question_numbered() {
1740 let e = parse("?7");
1741 match e {
1742 Expr::Parameter { index: 6, .. } => {}
1743 other => panic!("expected Parameter(6), got {other:?}"),
1744 }
1745 }
1746
1747 #[test]
1748 fn placeholder_question_numbered_zero_rejected() {
1749 let mut parser = Parser::new("?0").expect("lexer");
1750 let err = parser.parse_expr().unwrap_err();
1751 assert!(err.to_string().contains("placeholder"));
1752 }
1753
1754 #[test]
1755 fn placeholder_question_left_to_right() {
1756 let e = parse("id = ? AND name = ?");
1758 let Expr::BinaryOp {
1759 op: BinOp::And,
1760 lhs,
1761 rhs,
1762 ..
1763 } = e
1764 else {
1765 panic!("root must be And");
1766 };
1767 let Expr::BinaryOp {
1768 op: BinOp::Eq,
1769 rhs: r1,
1770 ..
1771 } = *lhs
1772 else {
1773 panic!("lhs must be Eq");
1774 };
1775 assert!(matches!(*r1, Expr::Parameter { index: 0, .. }));
1776 let Expr::BinaryOp {
1777 op: BinOp::Eq,
1778 rhs: r2,
1779 ..
1780 } = *rhs
1781 else {
1782 panic!("rhs must be Eq");
1783 };
1784 assert!(matches!(*r2, Expr::Parameter { index: 1, .. }));
1785 }
1786
1787 #[test]
1788 fn placeholder_question_in_string_literal_is_text() {
1789 let e = parse("'?'");
1790 match e {
1791 Expr::Literal {
1792 value: Value::Text(s),
1793 ..
1794 } if s.as_ref() == "?" => {}
1795 other => panic!("expected text literal '?', got {other:?}"),
1796 }
1797 }
1798
1799 #[test]
1800 fn placeholder_mixing_question_then_dollar_rejected() {
1801 let mut parser = Parser::new("id = ? AND x = $2").expect("lexer");
1802 let err = parser.parse_expr().err().expect("should fail");
1803 assert!(
1804 err.to_string().contains("mix"),
1805 "expected mixing error, got: {err}"
1806 );
1807 }
1808
1809 #[test]
1810 fn placeholder_mixing_dollar_then_question_rejected() {
1811 let mut parser = Parser::new("id = $1 AND x = ?").expect("lexer");
1812 let err = parser.parse_expr().err().expect("should fail");
1813 assert!(
1814 err.to_string().contains("mix"),
1815 "expected mixing error, got: {err}"
1816 );
1817 }
1818
1819 #[test]
1820 fn placeholder_question_in_comment_ignored() {
1821 let mut parser = Parser::new("-- ? ignored\n ?").expect("lexer");
1824 let e = parser.parse_expr().expect("parse_expr");
1825 match e {
1826 Expr::Parameter { index: 0, .. } => {}
1827 other => panic!("expected Parameter(0), got {other:?}"),
1828 }
1829 }
1830
1831 #[test]
1832 fn unary_plus_is_noop() {
1833 let e = parse("+42");
1834 assert!(matches!(
1835 e,
1836 Expr::Literal {
1837 value: Value::Integer(42),
1838 ..
1839 }
1840 ));
1841 }
1842
1843 #[test]
1844 fn parenthesised_select_becomes_subquery_expr() {
1845 let e = parse("(SELECT 1)");
1846 assert!(matches!(e, Expr::Subquery { .. }));
1847 }
1848
1849 #[test]
1850 fn bare_zero_arg_current_functions_parse_as_calls() {
1851 for (input, expected) in [
1852 ("CURRENT_TIMESTAMP", "CURRENT_TIMESTAMP"),
1853 ("CURRENT_DATE", "CURRENT_DATE"),
1854 ("CURRENT_TIME", "CURRENT_TIME"),
1855 ] {
1856 let e = parse(input);
1857 let Expr::FunctionCall { name, args, .. } = e else {
1858 panic!("expected FunctionCall for {input}");
1859 };
1860 assert_eq!(name, expected);
1861 assert!(args.is_empty());
1862 }
1863 }
1864
1865 #[test]
1866 fn keyword_function_names_parse_as_calls() {
1867 for (input, expected_len) in [
1868 ("COUNT(*)", 1),
1869 ("SUM(amount)", 1),
1870 ("LEFT(name, 2)", 2),
1871 ("RIGHT(name, 2)", 2),
1872 ("CONTAINS(body, 'red')", 2),
1873 ("KV(cfg, path)", 2),
1874 ] {
1875 let e = parse(input);
1876 let Expr::FunctionCall { args, .. } = e else {
1877 panic!("expected FunctionCall for {input}");
1878 };
1879 assert_eq!(args.len(), expected_len, "{input}");
1880 }
1881 }
1882
1883 #[test]
1884 fn count_distinct_lowers_to_count_distinct_function() {
1885 let e = parse("COUNT(DISTINCT user_id)");
1886 let Expr::FunctionCall { name, args, .. } = e else {
1887 panic!("expected FunctionCall");
1888 };
1889 assert_eq!(name, "COUNT_DISTINCT");
1890 assert_eq!(args.len(), 1);
1891 }
1892
1893 #[test]
1894 fn dollar_secret_and_config_refs_become_function_calls() {
1895 for (input, expected_name, expected_key) in [
1896 ("$secret.api_key", "__SECRET_REF", "red.vault/api_key"),
1897 ("$red.secret.api_key", "__SECRET_REF", "red.vault/api_key"),
1898 ("$red.secrets.api_key", "__SECRET_REF", "red.vault/api_key"),
1899 ("$config.ai.provider", "CONFIG", "red.config/ai.provider"),
1900 (
1901 "$red.config.ai.provider",
1902 "CONFIG",
1903 "red.config/ai.provider",
1904 ),
1905 ] {
1906 let e = parse(input);
1907 let Expr::FunctionCall { name, args, .. } = e else {
1908 panic!("expected FunctionCall for {input}");
1909 };
1910 assert_eq!(name, expected_name);
1911 assert!(matches!(
1912 &args[..],
1913 [Expr::Literal { value: Value::Text(key), .. }] if key.as_ref() == expected_key
1914 ));
1915 }
1916 }
1917
1918 #[test]
1919 fn dollar_ref_rejects_unknown_namespace() {
1920 let mut parser = Parser::new("$tenant.id").expect("lexer");
1921 let err = parser
1922 .parse_expr()
1923 .expect_err("unknown namespace should fail");
1924 assert!(err.to_string().contains("unknown $ reference"));
1925 }
1926
1927 #[test]
1928 fn config_and_kv_bare_path_args_lowercase_to_text() {
1929 let e = parse("CONFIG(Red.AI.Default.Provider, 'openai')");
1930 let Expr::FunctionCall { name, args, .. } = e else {
1931 panic!("expected FunctionCall");
1932 };
1933 assert_eq!(name, "CONFIG");
1934 assert_eq!(args.len(), 2);
1935 assert!(matches!(
1936 &args[0],
1937 Expr::Literal { value: Value::Text(path), .. }
1938 if path.as_ref() == "red.ai.default.provider"
1939 ));
1940 assert!(matches!(
1941 &args[1],
1942 Expr::Literal { value: Value::Text(provider), .. } if provider.as_ref() == "openai"
1943 ));
1944
1945 let e = parse("KV(cfg, default.role, LOWER(name))");
1946 let Expr::FunctionCall { name, args, .. } = e else {
1947 panic!("expected FunctionCall");
1948 };
1949 assert_eq!(name, "KV");
1950 assert!(matches!(
1951 &args[0],
1952 Expr::Literal { value: Value::Text(path), .. } if path.as_ref() == "cfg"
1953 ));
1954 assert!(matches!(
1955 &args[1],
1956 Expr::Literal { value: Value::Text(path), .. } if path.as_ref() == "default.role"
1957 ));
1958 assert!(matches!(&args[2], Expr::FunctionCall { name, .. } if name == "LOWER"));
1959 }
1960
1961 #[test]
1962 fn cast_rejects_unknown_type_name() {
1963 let mut parser = Parser::new("CAST(age AS BOGUS_TYPE)").expect("lexer");
1964 let err = parser
1965 .parse_expr()
1966 .expect_err("unknown cast target should fail");
1967 assert!(err.to_string().contains("unknown type name"));
1968 }
1969
1970 #[test]
1971 fn trim_position_and_substring_sql_forms_lower_to_function_args() {
1972 let e = parse("TRIM(LEADING 'x' FROM name)");
1973 let Expr::FunctionCall { name, args, .. } = e else {
1974 panic!("expected trim function");
1975 };
1976 assert_eq!(name, "LTRIM");
1977 assert_eq!(args.len(), 2);
1978
1979 let e = parse("TRIM(TRAILING FROM name)");
1980 let Expr::FunctionCall { name, args, .. } = e else {
1981 panic!("expected trim function");
1982 };
1983 assert_eq!(name, "RTRIM");
1984 assert_eq!(args.len(), 1);
1985
1986 let e = parse("POSITION('x' IN name)");
1987 let Expr::FunctionCall { name, args, .. } = e else {
1988 panic!("expected position function");
1989 };
1990 assert_eq!(name, "POSITION");
1991 assert_eq!(args.len(), 2);
1992
1993 let e = parse("POSITION('x', name)");
1994 let Expr::FunctionCall { args, .. } = e else {
1995 panic!("expected position function");
1996 };
1997 assert_eq!(args.len(), 2);
1998
1999 let e = parse("SUBSTRING(name FROM 2 FOR 3)");
2000 let Expr::FunctionCall { name, args, .. } = e else {
2001 panic!("expected substring function");
2002 };
2003 assert_eq!(name, "SUBSTRING");
2004 assert_eq!(args.len(), 3);
2005
2006 let e = parse("SUBSTRING(name FOR 3)");
2007 let Expr::FunctionCall { args, .. } = e else {
2008 panic!("expected substring function");
2009 };
2010 assert_eq!(args.len(), 3);
2011 assert!(matches!(
2012 args[1],
2013 Expr::Literal {
2014 value: Value::Integer(1),
2015 ..
2016 }
2017 ));
2018 }
2019
2020 #[test]
2021 fn postfix_in_accepts_subquery_and_empty_list() {
2022 let e = parse("id IN (SELECT user_id FROM users)");
2023 let Expr::InList { values, .. } = e else {
2024 panic!("expected InList");
2025 };
2026 assert!(matches!(&values[..], [Expr::Subquery { .. }]));
2027
2028 let e = parse("id IN ()");
2029 let Expr::InList { values, .. } = e else {
2030 panic!("expected InList");
2031 };
2032 assert!(values.is_empty());
2033 }
2034
2035 #[test]
2036 fn postfix_not_requires_between_or_in() {
2037 let mut parser = Parser::new("status NOT NULL").expect("lexer");
2038 let err = parser.parse_expr().expect_err("postfix NOT should fail");
2039 assert!(err.to_string().contains("BETWEEN or IN"));
2040 }
2041
2042 #[test]
2043 fn case_reports_missing_then_end_and_empty_branch() {
2044 for input in [
2045 "CASE END",
2046 "CASE WHEN a = 1 'one' END",
2047 "CASE WHEN a = 1 THEN 'one'",
2048 ] {
2049 let mut parser = Parser::new(input).expect("lexer");
2050 assert!(
2051 parser.parse_expr().is_err(),
2052 "expected CASE parse failure for {input}"
2053 );
2054 }
2055 }
2056
2057 #[test]
2058 fn span_tracks_token_range() {
2059 let mut parser = Parser::new("123 + 456").expect("lexer");
2061 let e = parser.parse_expr().expect("parse_expr");
2062 let span = e.span();
2063 assert!(!span.is_synthetic(), "root span must be real");
2064 assert!(span.start.offset < span.end.offset);
2065 }
2066
2067 fn try_parse(input: &str) -> Result<Expr, ParseError> {
2072 let mut parser = Parser::new(input).expect("lexer init");
2073 parser.parse_expr()
2074 }
2075
2076 #[test]
2077 fn window_lag_partition_and_order() {
2078 let e = parse("LAG(ts) OVER (PARTITION BY user_id ORDER BY ts)");
2079 let Expr::WindowFunctionCall {
2080 name, args, window, ..
2081 } = e
2082 else {
2083 panic!("expected WindowFunctionCall");
2084 };
2085 assert_eq!(name.to_uppercase(), "LAG");
2086 assert_eq!(args.len(), 1);
2087 assert_eq!(window.partition_by.len(), 1);
2088 assert_eq!(window.order_by.len(), 1);
2089 assert!(window.order_by[0].ascending);
2090 assert!(window.frame.is_none());
2091 }
2092
2093 #[test]
2094 fn window_row_number_empty_over() {
2095 let e = parse("ROW_NUMBER() OVER ()");
2096 let Expr::WindowFunctionCall {
2097 name, args, window, ..
2098 } = e
2099 else {
2100 panic!("expected WindowFunctionCall");
2101 };
2102 assert_eq!(name.to_uppercase(), "ROW_NUMBER");
2103 assert!(args.is_empty());
2104 assert!(window.partition_by.is_empty());
2105 assert!(window.order_by.is_empty());
2106 assert!(window.frame.is_none());
2107 }
2108
2109 #[test]
2110 fn window_sum_with_frame_rows_between() {
2111 let e = parse(
2112 "SUM(amount) OVER (PARTITION BY user_id ORDER BY ts \
2113 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)",
2114 );
2115 let Expr::WindowFunctionCall { name, window, .. } = e else {
2116 panic!("expected WindowFunctionCall");
2117 };
2118 assert_eq!(name.to_uppercase(), "SUM");
2119 let frame = window.frame.expect("frame present");
2120 assert!(matches!(frame.unit, crate::ast::WindowFrameUnit::Rows));
2121 assert!(matches!(
2122 frame.start,
2123 crate::ast::WindowFrameBound::Preceding(_)
2124 ));
2125 assert!(matches!(
2126 frame.end,
2127 Some(crate::ast::WindowFrameBound::CurrentRow)
2128 ));
2129 }
2130
2131 #[test]
2132 fn window_rank_order_desc_multiple_keys() {
2133 let e = parse("RANK() OVER (ORDER BY score DESC, ts)");
2134 let Expr::WindowFunctionCall { window, .. } = e else {
2135 panic!("expected WindowFunctionCall");
2136 };
2137 assert_eq!(window.order_by.len(), 2);
2138 assert!(!window.order_by[0].ascending);
2139 assert!(window.order_by[1].ascending);
2140 }
2141
2142 #[test]
2143 fn window_unbounded_preceding_following_frame() {
2144 let e = parse(
2145 "AVG(x) OVER (ORDER BY t \
2146 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)",
2147 );
2148 let Expr::WindowFunctionCall { window, .. } = e else {
2149 panic!("expected WindowFunctionCall");
2150 };
2151 let frame = window.frame.expect("frame present");
2152 assert!(matches!(frame.unit, crate::ast::WindowFrameUnit::Range));
2153 assert!(matches!(
2154 frame.start,
2155 crate::ast::WindowFrameBound::UnboundedPreceding
2156 ));
2157 assert!(matches!(
2158 frame.end,
2159 Some(crate::ast::WindowFrameBound::UnboundedFollowing)
2160 ));
2161 }
2162
2163 #[test]
2164 fn window_rejects_non_window_function() {
2165 let err = try_parse("UPPER(name) OVER (PARTITION BY id)")
2167 .err()
2168 .expect("should reject scalar OVER");
2169 let msg = err.to_string();
2170 assert!(
2171 msg.contains("UPPER") || msg.contains("upper"),
2172 "error should mention function name, got: {msg}"
2173 );
2174 assert!(msg.to_ascii_uppercase().contains("OVER") || msg.contains("window"));
2175 }
2176
2177 #[test]
2178 fn window_rejects_missing_open_paren() {
2179 let err = try_parse("LAG(ts) OVER PARTITION BY user_id")
2180 .err()
2181 .expect("should reject");
2182 let msg = err.to_string();
2183 assert!(
2184 msg.contains("(") || msg.to_ascii_uppercase().contains("EXPECTED"),
2185 "got: {msg}"
2186 );
2187 }
2188
2189 #[test]
2190 fn window_rejects_invalid_frame_syntax() {
2191 let err = try_parse("LAG(ts) OVER (ORDER BY ts ROWS CURRENT)")
2193 .err()
2194 .expect("should reject");
2195 let msg = err.to_string();
2196 assert!(
2197 !msg.is_empty(),
2198 "expected non-empty error for malformed frame"
2199 );
2200 }
2201
2202 #[test]
2203 fn window_first_value_with_partition_only() {
2204 let e = parse("FIRST_VALUE(price) OVER (PARTITION BY symbol)");
2205 let Expr::WindowFunctionCall {
2206 name, window, args, ..
2207 } = e
2208 else {
2209 panic!("expected WindowFunctionCall");
2210 };
2211 assert_eq!(name.to_uppercase(), "FIRST_VALUE");
2212 assert_eq!(args.len(), 1);
2213 assert_eq!(window.partition_by.len(), 1);
2214 assert!(window.order_by.is_empty());
2215 }
2216
2217 #[test]
2218 fn window_order_nulls_first_and_last() {
2219 let e = parse("SUM(x) OVER (ORDER BY score ASC NULLS FIRST, ts DESC NULLS LAST)");
2220 let Expr::WindowFunctionCall { window, .. } = e else {
2221 panic!("expected WindowFunctionCall");
2222 };
2223 assert_eq!(window.order_by.len(), 2);
2224 assert!(window.order_by[0].ascending);
2225 assert!(window.order_by[0].nulls_first);
2226 assert!(!window.order_by[1].ascending);
2227 assert!(!window.order_by[1].nulls_first);
2228 }
2229
2230 #[test]
2231 fn window_single_bound_frames() {
2232 let e = parse("SUM(x) OVER (ORDER BY ts ROWS 3 PRECEDING)");
2233 let Expr::WindowFunctionCall { window, .. } = e else {
2234 panic!("expected WindowFunctionCall");
2235 };
2236 let frame = window.frame.expect("frame");
2237 assert!(matches!(
2238 frame.start,
2239 crate::ast::WindowFrameBound::Preceding(_)
2240 ));
2241 assert!(frame.end.is_none());
2242
2243 let e = parse("SUM(x) OVER (ORDER BY ts RANGE 1 FOLLOWING)");
2244 let Expr::WindowFunctionCall { window, .. } = e else {
2245 panic!("expected WindowFunctionCall");
2246 };
2247 let frame = window.frame.expect("frame");
2248 assert!(matches!(
2249 frame.start,
2250 crate::ast::WindowFrameBound::Following(_)
2251 ));
2252 assert!(frame.end.is_none());
2253 }
2254
2255 #[test]
2256 fn window_reports_nulls_and_frame_bound_errors() {
2257 for input in [
2258 "SUM(x) OVER (ORDER BY score NULLS MIDDLE)",
2259 "SUM(x) OVER (ORDER BY score ROWS UNBOUNDED)",
2260 "SUM(x) OVER (ORDER BY score ROWS 3)",
2261 ] {
2262 let err = try_parse(input).expect_err("window syntax should fail");
2263 assert!(!err.to_string().is_empty(), "{input}");
2264 }
2265 }
2266}