1use super::types::*;
7use crate::error::{Error, Result};
8use nom::{
9 branch::alt,
10 bytes::complete::{tag, take_while1},
11 character::complete::char,
12 combinator::{opt, value},
13 multi::{many0, separated_list0},
14 sequence::preceded,
15 IResult,
16};
17use percent_encoding::percent_decode_str;
18
19pub fn parse_query_params(query: &str, is_rpc: bool) -> Result<QueryParams> {
29 let mut params = QueryParams::default();
30
31 if query.is_empty() {
32 return Ok(params);
33 }
34
35 let mut pairs: Vec<(&str, &str)> = query
37 .split('&')
38 .filter_map(|pair| {
39 let mut parts = pair.splitn(2, '=');
40 Some((parts.next()?, parts.next().unwrap_or("")))
41 })
42 .collect();
43 pairs.sort_by_key(|(k, _)| *k);
44 params.canonical = pairs
45 .iter()
46 .map(|(k, v)| format!("{}={}", k, v))
47 .collect::<Vec<_>>()
48 .join("&");
49
50 for (key, value) in pairs {
51 let decoded_value = percent_decode_str(value)
52 .decode_utf8()
53 .map_err(|_| Error::InvalidQueryParam(key.into()))?
54 .to_string();
55
56 let decoded_key = percent_decode_str(key)
60 .decode_utf8()
61 .map_err(|_| Error::InvalidQueryParam(key.into()))?
62 .to_string();
63 let key: &str = &decoded_key;
64
65 if let Some((path, modifier)) = parse_modifier_key(key) {
68 match modifier {
69 Modifier::Order => {
70 let (_, terms) = parse_order_param(&decoded_value)?;
71 params.order.push((path, terms));
72 }
73 Modifier::Limit => {
74 let limit: i64 = decoded_value
75 .parse()
76 .map_err(|_| Error::InvalidQueryParam("limit".into()))?;
77 if limit < 0 {
81 return Err(Error::InvalidRange(
82 "Limit should be greater than or equal to zero.".into(),
83 ));
84 }
85 params.ranges.entry(path.join(".")).or_default().limit = Some(limit);
86 }
87 Modifier::Offset => {
88 let offset: i64 = decoded_value
89 .parse()
90 .map_err(|_| Error::InvalidQueryParam("offset".into()))?;
91 let range = params.ranges.entry(path.join(".")).or_default();
92 range.offset = offset;
93 range.offset_explicit = true;
94 }
95 Modifier::Logic(op, negated) => {
96 params
97 .logic
98 .push((path, parse_logic_param(op, negated, &decoded_value)?));
99 }
100 }
101 continue;
102 }
103
104 match key {
105 "select" => {
106 params.select = parse_select(&decoded_value)?;
107 }
108 "columns" => {
109 params.columns = Some(parse_columns(&decoded_value)?.into_iter().collect());
110 }
111 "on_conflict" => {
112 params.on_conflict = Some(
113 decoded_value
114 .split(',')
115 .map(|s| s.trim().to_string())
116 .collect(),
117 );
118 }
119 key if !key.starts_with('_') => {
120 if is_rpc {
121 params.params.push((key.to_string(), decoded_value.clone()));
122 }
123
124 let parsed = parse_filter_param(key, &decoded_value);
126 let (path, filter) = match parsed {
127 Ok(parsed) => parsed,
128 Err(_) if is_rpc => continue,
131 Err(e) => return Err(e),
132 };
133
134 if path.is_empty() {
135 params.filter_fields.insert(filter.field.name.clone());
136 params.filters_root.push(filter);
137 } else {
138 params.filters.push((path, filter));
139 }
140 }
141 _ => {
142 params.params.push((key.to_string(), decoded_value));
144 }
145 }
146 }
147
148 Ok(params)
149}
150
151fn parse_columns(input: &str) -> Result<Vec<String>> {
164 const EXPECTED: &str = "expecting field name (* or [a..z0..9_$])";
165
166 let mut columns = Vec::new();
167 let mut at = 0usize;
168
169 for (index, field) in input.split(',').enumerate() {
170 if index > 0 {
171 at += 1;
173 }
174 let trimmed = field.trim();
175 if trimmed.is_empty() {
176 return Err(Error::UnparsableQuery {
177 kind: "columns parameter",
178 text: input.to_string(),
179 column: at + 1,
182 expected: match at >= input.len() {
183 true => format!("unexpected end of input {}", EXPECTED),
184 false => format!(
185 "unexpected {:?} {}",
186 input[at..].chars().next().unwrap_or_default(),
187 EXPECTED
188 ),
189 },
190 });
191 }
192 columns.push(trimmed.to_string());
193 at += field.len();
194 }
195
196 Ok(columns)
197}
198
199pub fn parse_select(input: &str) -> Result<Vec<SelectItem>> {
201 if input.is_empty() {
202 return Ok(vec![]);
203 }
204
205 match parse_select_items(input) {
209 Ok(("", items)) => Ok(items),
210 _ => Err(Error::InvalidQueryParam(format!("select={}", input))),
211 }
212}
213
214fn parse_select_items(input: &str) -> IResult<&str, Vec<SelectItem>> {
215 separated_list0(char(','), parse_select_item)(input)
216}
217
218fn parse_select_item(input: &str) -> IResult<&str, SelectItem> {
219 let (input, _) = nom::character::complete::space0(input)?;
222 alt((
223 parse_star,
224 parse_bare_aggregate,
227 parse_spread_relation,
228 parse_relation_select,
229 parse_field_select,
230 ))(input)
231}
232
233fn parse_star(input: &str) -> IResult<&str, SelectItem> {
239 let (input, _) = char('*')(input)?;
240 Ok((input, SelectItem::field("*")))
241}
242
243fn parse_bare_aggregate(input: &str) -> IResult<&str, SelectItem> {
248 let (input, alias) = opt(parse_alias_prefix)(input)?;
249 let (input, _) = tag("count()")(input)?;
250 let (input, cast) = opt(preceded(tag("::"), parse_identifier))(input)?;
251
252 Ok((
253 input,
254 SelectItem::Field {
255 field: Field::simple(""),
258 aggregate: Some(AggregateFunction::Count),
259 aggregate_cast: cast.map(|s| s.to_string()),
260 cast: None,
261 alias: alias.map(|s| s.to_string()),
262 },
263 ))
264}
265
266fn parse_aggregate_suffix(input: &str) -> IResult<&str, AggregateFunction> {
268 let (input, _) = char('.')(input)?;
269 let (input, function) = alt((
270 value(AggregateFunction::Sum, tag("sum")),
271 value(AggregateFunction::Avg, tag("avg")),
272 value(AggregateFunction::Max, tag("max")),
273 value(AggregateFunction::Min, tag("min")),
274 value(AggregateFunction::Count, tag("count")),
275 ))(input)?;
276 let (input, _) = tag("()")(input)?;
277 Ok((input, function))
278}
279
280fn parse_spread_relation(input: &str) -> IResult<&str, SelectItem> {
282 let (input, _) = tag("...")(input)?;
283 let (input, relation) = parse_field_name(input)?;
284 let (input, (hint, join_type)) = parse_relation_modifiers(input)?;
285 let (input, _) = char('(')(input)?;
289 let (input, nested) = parse_nested_select(input)?;
290 let (input, _) = char(')')(input)?;
291
292 Ok((
293 input,
294 SelectItem::SpreadRelation {
295 relation,
296 hint,
297 join_type,
298 select: nested,
299 },
300 ))
301}
302
303fn parse_nested_select(input: &str) -> IResult<&str, Vec<SelectItem>> {
309 let mut depth = 0usize;
310 let mut end = input.len();
311
312 for (idx, ch) in input.char_indices() {
313 match ch {
314 '(' => depth += 1,
315 ')' => {
316 if depth == 0 {
317 end = idx;
318 break;
319 }
320 depth -= 1;
321 }
322 _ => {}
323 }
324 }
325
326 let (body, rest) = input.split_at(end);
327
328 if body.is_empty() {
329 return Ok((rest, Vec::new()));
330 }
331
332 match parse_select_items(body) {
333 Ok(("", items)) => Ok((rest, items)),
334 _ => Err(nom::Err::Error(nom::error::Error::new(
335 input,
336 nom::error::ErrorKind::Verify,
337 ))),
338 }
339}
340
341fn parse_relation_select(input: &str) -> IResult<&str, SelectItem> {
343 let (input, alias) = opt(parse_alias_prefix)(input)?;
345 let (input, name) = parse_field_name(input)?;
346 let (input, (hint, join_type)) = parse_relation_modifiers(input)?;
347 let (input, _) = char('(')(input)?;
351 let (input, nested) = parse_nested_select(input)?;
352 let (input, _) = char(')')(input)?;
353
354 Ok((
355 input,
356 SelectItem::Relation {
357 relation: name,
358 alias,
359 hint,
360 join_type,
361 select: nested,
362 },
363 ))
364}
365
366fn parse_field_select(input: &str) -> IResult<&str, SelectItem> {
368 let (input, alias) = opt(parse_alias_prefix)(input)?;
372
373 let (input, name) = parse_field_name(input)?;
374 let (input, json_path) = parse_json_path(input)?;
375
376 let (input, cast) = opt(preceded(tag("::"), parse_identifier))(input)?;
379 let (input, aggregate) = opt(parse_aggregate_suffix)(input)?;
380 let (input, aggregate_cast) = if aggregate.is_some() {
381 let (input, cast) = opt(preceded(tag("::"), parse_identifier))(input)?;
382 (input, cast.map(|s| s.to_string()))
383 } else {
384 (input, None)
385 };
386
387 Ok((
388 input,
389 SelectItem::Field {
390 field: Field { name, json_path },
391 aggregate,
392 aggregate_cast,
393 cast: cast.map(|s| s.to_string()),
394 alias: alias.map(|s| s.to_string()),
395 },
396 ))
397}
398
399fn parse_alias_prefix(input: &str) -> IResult<&str, String> {
413 let (rest, name) = parse_field_name(input)?;
414 let (rest, _) = char(':')(rest)?;
415
416 if rest.starts_with(':') {
417 return Err(nom::Err::Error(nom::error::Error::new(
418 input,
419 nom::error::ErrorKind::Verify,
420 )));
421 }
422
423 Ok((rest, name))
424}
425
426fn parse_relation_modifiers(input: &str) -> IResult<&str, (Option<String>, Option<JoinType>)> {
427 let (input, modifiers) = many0(preceded(char('!'), parse_identifier))(input)?;
428
429 let mut hint = None;
430 let mut join_type = None;
431 for modifier in modifiers {
432 match modifier {
433 "inner" => join_type = Some(JoinType::Inner),
434 "left" => join_type = Some(JoinType::Left),
435 other => hint = Some(other.to_string()),
436 }
437 }
438
439 Ok((input, (hint, join_type)))
440}
441
442fn parse_filter_param(key: &str, value: &str) -> Result<(EmbedPath, Filter)> {
448 let (path, field) = parse_filter_key(key)?;
450
451 let op_expr = parse_filter_value(value)?;
453
454 Ok((path, Filter::new(field, op_expr)))
455}
456
457fn split_json_path(reference: &str) -> Field {
464 let Some(arrow) = reference.find("->") else {
465 return Field::simple(reference);
466 };
467
468 let (column, rest) = reference.split_at(arrow);
469 match parse_json_path(rest) {
470 Ok(("", json_path)) if !json_path.is_empty() => Field::with_json_path(column, json_path),
471 _ => Field::simple(reference),
472 }
473}
474
475fn parse_filter_key(key: &str) -> Result<(EmbedPath, Field)> {
487 if let Some(parsed) = parse_field_reference(key) {
488 return Ok(parsed);
489 }
490
491 let mut parts: Vec<&str> = key.split('.').collect();
492 let field = parts
493 .pop()
494 .ok_or_else(|| Error::InvalidQueryParam(key.into()))?;
495 let path = parts.into_iter().map(String::from).collect();
496 Ok((path, split_json_path(field)))
497}
498
499fn parse_field_reference(key: &str) -> Option<(EmbedPath, Field)> {
504 let mut names = Vec::new();
505 let mut rest = key;
506
507 loop {
508 let (remainder, name) = parse_field_name(rest).ok()?;
509 names.push(name);
510 match remainder.strip_prefix('.') {
511 Some(after) => rest = after,
512 None => {
513 rest = remainder;
514 break;
515 }
516 }
517 }
518
519 let (rest, json_path) = parse_json_path(rest).ok()?;
520 if !rest.is_empty() {
521 return None;
522 }
523
524 let field = names.pop()?;
525 Some((names, Field::with_json_path(field, json_path)))
526}
527
528pub fn value_is_filter(value: &str) -> bool {
535 parse_filter_value(value).is_ok()
536}
537
538fn parse_filter_value(value: &str) -> Result<OpExpr> {
540 let whole = value;
541 let (value, negated) = if let Some(rest) = value.strip_prefix("not.") {
542 (rest, true)
543 } else {
544 (value, false)
545 };
546
547 let operation = parse_operation(value).map_err(|error| match error {
548 Error::InvalidQueryParam(_) => Error::UnparsableQuery {
553 kind: "filter",
554 text: whole.to_string(),
555 column: 1,
556 expected: format!(
557 "unexpected \"{}\" expecting \"not\" or operator (eq, gt, ...)",
558 whole.chars().next().unwrap_or_default()
559 ),
560 },
561 other => other,
562 })?;
563 Ok(OpExpr { negated, operation })
564}
565
566fn quant_operator(name: &str) -> Option<QuantOperator> {
570 Some(match name {
571 "eq" => QuantOperator::Equal,
572 "gt" => QuantOperator::GreaterThan,
573 "gte" => QuantOperator::GreaterThanEqual,
574 "lt" => QuantOperator::LessThan,
575 "lte" => QuantOperator::LessThanEqual,
576 "like" => QuantOperator::Like,
577 "ilike" => QuantOperator::ILike,
578 "match" => QuantOperator::Match,
579 "imatch" => QuantOperator::IMatch,
580 _ => return None,
581 })
582}
583
584fn parse_quantifier(modifier: &str) -> Option<OpQuantifier> {
586 match modifier {
587 "any" => Some(OpQuantifier::Any),
588 "all" => Some(OpQuantifier::All),
589 _ => None,
590 }
591}
592
593fn parse_operation(value: &str) -> Result<Operation> {
595 if let Some((name, rest)) = value.split_once('(') {
599 if let Some((modifier, operand)) = rest.split_once(").") {
600 if let (Some(op), Some(quantifier)) = (quant_operator(name), parse_quantifier(modifier))
601 {
602 return Ok(Operation::Quant {
603 op,
604 quantifier: Some(quantifier),
605 value: operand.to_string(),
606 });
607 }
608 }
609 }
610
611 if let Some((name, rest)) = value.split_once('.') {
614 if let Some(op) = quant_operator(name) {
615 return Ok(Operation::Quant {
616 op,
617 quantifier: None,
618 value: rest.to_string(),
619 });
620 }
621 }
622
623 if let Some(rest) = value.strip_prefix("neq.") {
624 return Ok(Operation::Simple {
625 op: SimpleOperator::NotEqual,
626 value: rest.to_string(),
627 });
628 }
629
630 if let Some(rest) = value.strip_prefix("cs.") {
632 return Ok(Operation::Simple {
633 op: SimpleOperator::Contains,
634 value: rest.to_string(),
635 });
636 }
637 if let Some(rest) = value.strip_prefix("cd.") {
638 return Ok(Operation::Simple {
639 op: SimpleOperator::Contained,
640 value: rest.to_string(),
641 });
642 }
643 if let Some(rest) = value.strip_prefix("ov.") {
644 return Ok(Operation::Simple {
645 op: SimpleOperator::Overlap,
646 value: rest.to_string(),
647 });
648 }
649 if let Some(rest) = value.strip_prefix("sl.") {
650 return Ok(Operation::Simple {
651 op: SimpleOperator::StrictlyLeft,
652 value: rest.to_string(),
653 });
654 }
655 if let Some(rest) = value.strip_prefix("sr.") {
656 return Ok(Operation::Simple {
657 op: SimpleOperator::StrictlyRight,
658 value: rest.to_string(),
659 });
660 }
661 if let Some(rest) = value.strip_prefix("nxr.") {
662 return Ok(Operation::Simple {
663 op: SimpleOperator::NotExtendsRight,
664 value: rest.to_string(),
665 });
666 }
667 if let Some(rest) = value.strip_prefix("nxl.") {
668 return Ok(Operation::Simple {
669 op: SimpleOperator::NotExtendsLeft,
670 value: rest.to_string(),
671 });
672 }
673 if let Some(rest) = value.strip_prefix("adj.") {
674 return Ok(Operation::Simple {
675 op: SimpleOperator::Adjacent,
676 value: rest.to_string(),
677 });
678 }
679
680 if let Some(rest) = value.strip_prefix("in.") {
682 let values = parse_in_list(rest)?;
683 return Ok(Operation::In(values));
684 }
685
686 if let Some(rest) = value.strip_prefix("is.") {
688 let is_val = match rest.to_ascii_lowercase().as_str() {
692 "null" => IsValue::Null,
693 "not_null" => IsValue::NotNull,
694 "true" => IsValue::True,
695 "false" => IsValue::False,
696 "unknown" => IsValue::Unknown,
697 _ => return Err(unreadable_is_value(rest)),
698 };
699 return Ok(Operation::Is(is_val));
700 }
701
702 if let Some(rest) = value.strip_prefix("isdistinct.") {
704 return Ok(Operation::IsDistinctFrom(rest.to_string()));
705 }
706
707 if let Some(rest) = value.strip_prefix("fts") {
709 return parse_fts(FtsOperator::Fts, rest);
710 }
711 if let Some(rest) = value.strip_prefix("plfts") {
712 return parse_fts(FtsOperator::Plain, rest);
713 }
714 if let Some(rest) = value.strip_prefix("phfts") {
715 return parse_fts(FtsOperator::Phrase, rest);
716 }
717 if let Some(rest) = value.strip_prefix("wfts") {
718 return parse_fts(FtsOperator::Websearch, rest);
719 }
720
721 Err(Error::InvalidQueryParam(value.into()))
722}
723
724fn unreadable_order(term: &str, at: usize, part: &str) -> Error {
730 const MODIFIERS: [&str; 4] = ["asc", "desc", "nullsfirst", "nullslast"];
731
732 let read = MODIFIERS
733 .iter()
734 .map(|modifier| {
735 part.chars()
736 .zip(modifier.chars())
737 .take_while(|(a, b)| a == b)
738 .count()
739 })
740 .max()
741 .unwrap_or(0);
742
743 Error::UnparsableQuery {
744 kind: "order",
745 text: term.to_string(),
746 column: at + read + 1,
747 expected: format!(
748 "unexpected {:?} expecting \",\" or end of input",
749 part.chars().nth(read).unwrap_or_default()
750 ),
751 }
752}
753
754fn unreadable_is_value(rest: &str) -> Error {
762 const VALUES: [&str; 5] = ["null", "not_null", "true", "false", "unknown"];
763
764 let lowered = rest.to_ascii_lowercase();
765 let read = VALUES
766 .iter()
767 .map(|value| {
768 lowered
769 .chars()
770 .zip(value.chars())
771 .take_while(|(a, b)| a == b)
772 .count()
773 })
774 .max()
775 .unwrap_or(0);
776
777 Error::UnparsableQuery {
778 kind: "filter",
779 text: format!("is.{}", rest),
780 column: 4 + read,
782 expected: format!(
783 "unexpected \"{}\" expecting isVal: ({})",
784 rest.chars().nth(read).unwrap_or_default(),
785 VALUES.join(", ")
786 ),
787 }
788}
789
790fn parse_in_list(value: &str) -> Result<Vec<String>> {
792 let inner = value
796 .trim()
797 .strip_prefix('(')
798 .and_then(|s| s.strip_suffix(')'))
799 .map(|inner| {
800 inner
801 .trim_start_matches([' ', '\t'])
802 .trim_end_matches([' ', '\t'])
803 })
804 .ok_or_else(|| Error::InvalidQueryParam(format!("in.{}", value)))?;
805
806 if inner.is_empty() {
809 return Ok(Vec::new());
810 }
811
812 let mut values = Vec::new();
813 let mut rest = inner;
814
815 loop {
816 let element = match quoted_element(rest) {
821 Some((unquoted, remainder)) => {
822 rest = remainder;
823 unquoted
824 }
825 None => {
826 let end = rest.find(',').unwrap_or(rest.len());
827 let (element, remainder) = rest.split_at(end);
828 rest = remainder;
829 element.to_string()
830 }
831 };
832 values.push(element);
833
834 match rest.strip_prefix(',') {
835 Some(remainder) => rest = remainder,
836 None => break,
837 }
838 }
839
840 Ok(values)
841}
842
843fn quoted_element(input: &str) -> Option<(String, &str)> {
848 let body = input.strip_prefix('"')?;
849
850 let mut value = String::new();
851 let mut chars = body.char_indices();
852 while let Some((index, ch)) = chars.next() {
853 match ch {
854 '\\' => {
855 let (_, escaped) = chars.next()?;
856 value.push(escaped);
857 }
858 '"' => {
859 let rest = &body[index + 1..];
860 return match rest.is_empty() || rest.starts_with(',') {
861 true => Some((value, rest)),
862 false => None,
863 };
864 }
865 other => value.push(other),
866 }
867 }
868
869 None
870}
871
872fn parse_fts(op: FtsOperator, rest: &str) -> Result<Operation> {
874 if let Some(rest) = rest.strip_prefix('(') {
875 let (lang, query) = rest
877 .split_once(").")
878 .ok_or_else(|| Error::InvalidQueryParam(format!("fts{}", rest)))?;
879 return Ok(Operation::Fts {
880 op,
881 language: Some(lang.to_string()),
882 value: query.to_string(),
883 });
884 }
885
886 let query = rest
887 .strip_prefix('.')
888 .ok_or_else(|| Error::InvalidQueryParam(format!("fts{}", rest)))?;
889 Ok(Operation::Fts {
890 op,
891 language: None,
892 value: query.to_string(),
893 })
894}
895
896fn parse_order_param(value: &str) -> Result<(EmbedPath, Vec<OrderTerm>)> {
902 let terms: Vec<OrderTerm> = value
903 .split(',')
904 .map(|s| parse_order_term(s.trim()))
905 .collect::<Result<Vec<_>>>()?;
906 Ok((vec![], terms))
907}
908
909fn parse_order_term(value: &str) -> Result<OrderTerm> {
910 let parts: Vec<&str> = value.split('.').collect();
911 if parts.is_empty() {
912 return Err(Error::InvalidQueryParam("order".into()));
913 }
914
915 let field_name = parts[0];
916 let field = split_json_path(field_name);
917 let mut direction = None;
918 let mut nulls = None;
919
920 let mut at = field_name.len() + 1;
923 for part in &parts[1..] {
924 match *part {
925 "asc" => direction = Some(OrderDirection::Asc),
926 "desc" => direction = Some(OrderDirection::Desc),
927 "nullsfirst" => nulls = Some(OrderNulls::First),
928 "nullslast" => nulls = Some(OrderNulls::Last),
929 other => return Err(unreadable_order(value, at, other)),
934 }
935 at += part.len() + 1;
936 }
937
938 if let Some((relation, rest)) = field_name.split_once('(') {
941 if let Some(column) = rest.strip_suffix(')') {
942 return Ok(OrderTerm::Relation {
943 relation: relation.to_string(),
944 field: split_json_path(column),
945 direction,
946 nulls,
947 });
948 }
949 }
950
951 Ok(OrderTerm::Field {
952 field,
953 direction,
954 nulls,
955 })
956}
957
958fn parse_logic_param(op: LogicOperator, negated: bool, value: &str) -> Result<LogicTree> {
964 let trimmed = value.trim();
971 let inner = balanced_group(trimmed).ok_or_else(|| Error::InvalidQueryParam(value.into()))?;
972
973 let members = split_top_level(inner);
980 for member in &members {
981 if !member.trim().is_empty() {
982 continue;
983 }
984 let at = offset_within(trimmed, member);
985 return Err(Error::UnparsableQuery {
986 kind: "logic tree",
987 text: trimmed.to_string(),
988 column: negated as usize * "not.".len()
989 + match op {
990 LogicOperator::And => 3,
991 LogicOperator::Or => 2,
992 }
993 + at
994 + 1,
995 expected: format!(
996 "unexpected \"{}\" expecting field name (* or [a..z0..9_$]), \
997 negation operator (not) or logic operator (and, or)",
998 trimmed[at..].chars().next().unwrap_or_default()
999 ),
1000 });
1001 }
1002
1003 Ok(LogicTree::Expr {
1004 negated,
1005 op,
1006 children: members
1007 .into_iter()
1008 .map(parse_logic_child)
1009 .collect::<Result<Vec<_>>>()?,
1010 })
1011}
1012
1013fn offset_within(whole: &str, part: &str) -> usize {
1019 (part.as_ptr() as usize).saturating_sub(whole.as_ptr() as usize)
1020}
1021
1022fn balanced_group(input: &str) -> Option<&str> {
1027 let body = input.strip_prefix('(')?;
1028
1029 let mut depth = 0usize;
1030 let mut quoted = false;
1031 let mut escaped = false;
1032
1033 for (idx, ch) in body.char_indices() {
1034 if quoted {
1035 match ch {
1036 _ if escaped => escaped = false,
1037 '\\' => escaped = true,
1038 '"' => quoted = false,
1039 _ => {}
1040 }
1041 continue;
1042 }
1043 match ch {
1044 '"' => quoted = true,
1045 '(' => depth += 1,
1046 ')' if depth == 0 => return Some(&body[..idx]),
1047 ')' => depth -= 1,
1048 _ => {}
1049 }
1050 }
1051
1052 None
1053}
1054
1055fn split_top_level(input: &str) -> Vec<&str> {
1061 let mut parts = Vec::new();
1062 let mut depth = 0usize;
1063 let mut quoted = false;
1064 let mut escaped = false;
1065 let mut start = 0usize;
1066
1067 for (idx, ch) in input.char_indices() {
1068 if quoted {
1069 match ch {
1070 _ if escaped => escaped = false,
1071 '\\' => escaped = true,
1072 '"' => quoted = false,
1073 _ => {}
1074 }
1075 continue;
1076 }
1077 match ch {
1078 '"' => quoted = true,
1079 '(' | '{' | '[' => depth += 1,
1080 ')' | '}' | ']' => depth = depth.saturating_sub(1),
1081 ',' if depth == 0 => {
1082 parts.push(&input[start..idx]);
1083 start = idx + ch.len_utf8();
1084 }
1085 _ => {}
1086 }
1087 }
1088 parts.push(&input[start..]);
1089 parts
1090}
1091
1092fn parse_logic_child(item: &str) -> Result<LogicTree> {
1094 let item = item.trim();
1095
1096 let (body, negated) = match item.strip_prefix("not.") {
1100 Some(rest) if rest.starts_with("and(") || rest.starts_with("or(") => (rest, true),
1101 _ => (item, false),
1102 };
1103
1104 for (name, op) in [("and", LogicOperator::And), ("or", LogicOperator::Or)] {
1105 if let Some(rest) = body.strip_prefix(name) {
1106 let rest = rest.trim_start();
1107 if rest.starts_with('(') && rest.ends_with(')') {
1108 return parse_logic_param(op, negated, rest);
1109 }
1110 }
1111 }
1112
1113 let (key, val) = body
1114 .split_once('.')
1115 .ok_or_else(|| Error::InvalidQueryParam(item.into()))?;
1116 let (_, filter) = parse_filter_param(key, &unquote_logic_operand(val))?;
1117 Ok(LogicTree::Stmt(filter))
1118}
1119
1120fn unquote_logic_operand(value: &str) -> String {
1128 let Some(open) = value.find('"') else {
1129 return value.to_string();
1130 };
1131 if open != 0 && !value[..open].ends_with('.') {
1134 return value.to_string();
1135 }
1136 if !value.ends_with('"') || value.len() < open + 2 {
1137 return value.to_string();
1138 }
1139
1140 let mut unquoted = String::from(&value[..open]);
1141 let mut chars = value[open + 1..value.len() - 1].chars();
1142 while let Some(ch) = chars.next() {
1143 match ch {
1144 '\\' => {
1145 if let Some(escaped) = chars.next() {
1146 unquoted.push(escaped);
1147 }
1148 }
1149 other => unquoted.push(other),
1150 }
1151 }
1152 unquoted
1153}
1154
1155enum Modifier {
1157 Order,
1158 Limit,
1159 Offset,
1160 Logic(LogicOperator, bool),
1161}
1162
1163fn parse_modifier_key(key: &str) -> Option<(EmbedPath, Modifier)> {
1170 let mut parts: Vec<&str> = key.split('.').collect();
1171 let last = parts.pop()?;
1172
1173 let modifier = match last {
1174 "order" => Modifier::Order,
1175 "limit" => Modifier::Limit,
1176 "offset" => Modifier::Offset,
1177 "and" | "or" => {
1178 let op = if last == "and" {
1179 LogicOperator::And
1180 } else {
1181 LogicOperator::Or
1182 };
1183 let negated = parts.last() == Some(&"not");
1185 if negated {
1186 parts.pop();
1187 }
1188 Modifier::Logic(op, negated)
1189 }
1190 _ => return None,
1191 };
1192
1193 Some((parts.into_iter().map(String::from).collect(), modifier))
1194}
1195
1196fn parse_identifier(input: &str) -> IResult<&str, &str> {
1207 let (rest, matched) =
1208 take_while1(|c: char| c.is_alphanumeric() || c == '_' || c == '$' || c == ' ')(input)?;
1209 Ok((rest, matched.trim()))
1210}
1211
1212fn parse_field_name(input: &str) -> IResult<&str, String> {
1222 if let Ok(quoted) = parse_quoted_name(input) {
1223 return Ok(quoted);
1224 }
1225
1226 let (mut rest, first) = parse_identifier(input)?;
1227 let mut name = first.to_string();
1228
1229 while let Some(after_dash) = rest.strip_prefix('-') {
1230 if after_dash.starts_with('>') {
1231 break;
1232 }
1233 let Ok((next, segment)) = parse_identifier(after_dash) else {
1234 break;
1235 };
1236 name.push('-');
1237 name.push_str(segment);
1238 rest = next;
1239 }
1240
1241 Ok((rest, name))
1242}
1243
1244fn parse_quoted_name(input: &str) -> IResult<&str, String> {
1246 let (rest, _) = char('"')(input)?;
1247
1248 let mut name = String::new();
1249 let mut chars = rest.char_indices();
1250 while let Some((index, ch)) = chars.next() {
1251 match ch {
1252 '\\' => {
1253 if let Some((_, escaped)) = chars.next() {
1254 name.push(escaped);
1255 }
1256 }
1257 '"' => return Ok((&rest[index + 1..], name)),
1258 other => name.push(other),
1259 }
1260 }
1261
1262 Err(nom::Err::Error(nom::error::Error::new(
1263 input,
1264 nom::error::ErrorKind::Verify,
1265 )))
1266}
1267
1268fn parse_json_path(input: &str) -> IResult<&str, JsonPath> {
1269 many0(alt((parse_double_arrow, parse_arrow)))(input)
1272}
1273
1274fn parse_json_operand(input: &str) -> IResult<&str, JsonOperand> {
1286 let mut end = input.len();
1287 for (idx, ch) in input.char_indices() {
1288 if matches!(ch, ',' | '(' | ')' | ':') || input[idx..].starts_with("->") {
1291 end = idx;
1292 break;
1293 }
1294 }
1295
1296 let (key, rest) = input.split_at(end);
1297 if key.is_empty() {
1298 return Err(nom::Err::Error(nom::error::Error::new(
1299 input,
1300 nom::error::ErrorKind::TakeWhile1,
1301 )));
1302 }
1303
1304 let operand = match key.parse::<i32>() {
1305 Ok(index) => JsonOperand::Idx(index),
1306 Err(_) if key.starts_with('-') => {
1316 return Err(nom::Err::Failure(nom::error::Error::new(
1317 &input[1..],
1318 nom::error::ErrorKind::Digit,
1319 )))
1320 }
1321 Err(_) => JsonOperand::Key(key.to_string()),
1322 };
1323 Ok((rest, operand))
1324}
1325
1326fn parse_arrow(input: &str) -> IResult<&str, JsonOperation> {
1327 let (input, _) = tag("->")(input)?;
1328 let (input, operand) = parse_json_operand(input)?;
1329 Ok((input, JsonOperation::Arrow(operand)))
1330}
1331
1332fn parse_double_arrow(input: &str) -> IResult<&str, JsonOperation> {
1333 let (input, _) = tag("->>")(input)?;
1334 let (input, operand) = parse_json_operand(input)?;
1335 Ok((input, JsonOperation::DoubleArrow(operand)))
1336}
1337
1338#[cfg(test)]
1339mod tests {
1340 use super::*;
1341
1342 #[test]
1343 fn test_parse_simple_filter() {
1344 let params = parse_query_params("name=eq.John", false).unwrap();
1345 assert_eq!(params.filters_root.len(), 1);
1346 assert_eq!(params.filters_root[0].field.name, "name");
1347 }
1348
1349 #[test]
1350 fn test_parse_negated_filter() {
1351 let params = parse_query_params("status=not.eq.active", false).unwrap();
1352 assert!(params.filters_root[0].op_expr.negated);
1353 }
1354
1355 #[test]
1356 fn test_parse_in_filter() {
1357 let params = parse_query_params("id=in.(1,2,3)", false).unwrap();
1358 match ¶ms.filters_root[0].op_expr.operation {
1359 Operation::In(values) => {
1360 assert_eq!(values, &vec!["1", "2", "3"]);
1361 }
1362 _ => panic!("Expected In operation"),
1363 }
1364 }
1365
1366 #[test]
1367 fn test_json_path_double_arrow_wins_over_single() {
1368 let items = parse_select("settings->foo->>bar").unwrap();
1369 match &items[0] {
1370 SelectItem::Field { field, .. } => {
1371 assert_eq!(
1372 field.json_path,
1373 vec![
1374 JsonOperation::Arrow(JsonOperand::Key("foo".into())),
1375 JsonOperation::DoubleArrow(JsonOperand::Key("bar".into())),
1376 ]
1377 );
1378 }
1379 other => panic!("expected a field, got {:?}", other),
1380 }
1381 }
1382
1383 #[test]
1384 fn test_json_path_accepts_awkward_keys() {
1385 let items = parse_select("data->23-xy-45->>!@#$%^&*_e").unwrap();
1388 match &items[0] {
1389 SelectItem::Field { field, .. } => {
1390 assert_eq!(
1391 field.json_path,
1392 vec![
1393 JsonOperation::Arrow(JsonOperand::Key("23-xy-45".into())),
1394 JsonOperation::DoubleArrow(JsonOperand::Key("!@#$%^&*_e".into())),
1395 ]
1396 );
1397 }
1398 other => panic!("expected a field, got {:?}", other),
1399 }
1400 }
1401
1402 #[test]
1403 fn test_json_path_digits_are_an_index_but_only_when_whole() {
1404 let items = parse_select("data->0,other->0xy1").unwrap();
1405 let paths: Vec<_> = items
1406 .iter()
1407 .map(|i| match i {
1408 SelectItem::Field { field, .. } => field.json_path.clone(),
1409 other => panic!("expected a field, got {:?}", other),
1410 })
1411 .collect();
1412 assert_eq!(paths[0], vec![JsonOperation::Arrow(JsonOperand::Idx(0))]);
1413 assert_eq!(
1414 paths[1],
1415 vec![JsonOperation::Arrow(JsonOperand::Key("0xy1".into()))]
1416 );
1417 }
1418
1419 #[test]
1420 fn test_json_path_stops_at_a_cast() {
1421 let items = parse_select("settings->>foo::json").unwrap();
1422 match &items[0] {
1423 SelectItem::Field { field, cast, .. } => {
1424 assert_eq!(
1425 field.json_path,
1426 vec![JsonOperation::DoubleArrow(JsonOperand::Key("foo".into()))]
1427 );
1428 assert_eq!(cast.as_deref(), Some("json"));
1429 }
1430 other => panic!("expected a field, got {:?}", other),
1431 }
1432 }
1433
1434 #[test]
1435 fn test_parse_spread_relation_keeps_its_columns() {
1436 let items = parse_select("title,...directors(first_name,last_name)").unwrap();
1437 assert_eq!(items.len(), 2);
1438 match &items[1] {
1439 SelectItem::SpreadRelation {
1440 relation, select, ..
1441 } => {
1442 assert_eq!(relation, "directors");
1443 let names: Vec<_> = select
1444 .iter()
1445 .map(|item| match item {
1446 SelectItem::Field { field, .. } => field.name.clone(),
1447 other => panic!("expected a field, got {:?}", other),
1448 })
1449 .collect();
1450 assert_eq!(names, vec!["first_name", "last_name"]);
1451 }
1452 other => panic!("expected a spread relation, got {:?}", other),
1453 }
1454 }
1455
1456 #[test]
1457 fn test_parse_spread_relation_does_not_swallow_later_items() {
1458 let items = parse_select("...directors(name),year").unwrap();
1461 assert_eq!(items.len(), 2);
1462 assert!(matches!(items[0], SelectItem::SpreadRelation { .. }));
1463 match &items[1] {
1464 SelectItem::Field { field, .. } => assert_eq!(field.name, "year"),
1465 other => panic!("expected a field, got {:?}", other),
1466 }
1467 }
1468
1469 #[test]
1470 fn test_parse_nested_spread_relation() {
1471 let items = parse_select("id,films(title,...directors(name))").unwrap();
1472 match &items[1] {
1473 SelectItem::Relation { select, .. } => {
1474 assert_eq!(select.len(), 2);
1475 assert!(matches!(select[1], SelectItem::SpreadRelation { .. }));
1476 }
1477 other => panic!("expected a relation, got {:?}", other),
1478 }
1479 }
1480
1481 #[test]
1482 fn test_parse_in_filter_with_quoted_commas() {
1483 let params = parse_query_params(r#"name=in.("hi,there","yes,you")"#, false).unwrap();
1484 match ¶ms.filters_root[0].op_expr.operation {
1485 Operation::In(values) => {
1486 assert_eq!(values, &vec!["hi,there".to_string(), "yes,you".to_string()]);
1487 }
1488 other => panic!("expected an In operation, got {:?}", other),
1489 }
1490 }
1491
1492 #[test]
1493 fn test_parse_in_filter_with_escapes() {
1494 let params = parse_query_params(r#"name=in.("a\"b","c\\d")"#, false).unwrap();
1495 match ¶ms.filters_root[0].op_expr.operation {
1496 Operation::In(values) => {
1497 assert_eq!(values, &vec![r#"a"b"#.to_string(), r#"c\d"#.to_string()]);
1498 }
1499 other => panic!("expected an In operation, got {:?}", other),
1500 }
1501 }
1502
1503 #[test]
1504 fn test_parse_quantified_filter() {
1505 for (query, expected) in [
1506 ("id=eq(any).{1,2,3}", OpQuantifier::Any),
1507 ("id=eq(all).{1,2,3}", OpQuantifier::All),
1508 ] {
1509 let params = parse_query_params(query, false).unwrap();
1510 match ¶ms.filters_root[0].op_expr.operation {
1511 Operation::Quant {
1512 op,
1513 quantifier,
1514 value,
1515 } => {
1516 assert_eq!(op, &QuantOperator::Equal);
1517 assert_eq!(quantifier.as_ref(), Some(&expected));
1518 assert_eq!(value, "{1,2,3}");
1519 }
1520 other => panic!("expected a quantified operation, got {:?}", other),
1521 }
1522 }
1523 }
1524
1525 #[test]
1526 fn test_parse_quantified_like_keeps_array_literal() {
1527 let params = parse_query_params("name=like(any).{foo*,bar*}", false).unwrap();
1528 match ¶ms.filters_root[0].op_expr.operation {
1529 Operation::Quant {
1530 op,
1531 quantifier,
1532 value,
1533 } => {
1534 assert_eq!(op, &QuantOperator::Like);
1535 assert_eq!(quantifier.as_ref(), Some(&OpQuantifier::Any));
1536 assert_eq!(value, "{foo*,bar*}");
1539 }
1540 other => panic!("expected a quantified operation, got {:?}", other),
1541 }
1542 }
1543
1544 #[test]
1545 fn test_parse_negated_quantified_filter() {
1546 let params = parse_query_params("id=not.eq(any).{1,2}", false).unwrap();
1547 assert!(params.filters_root[0].op_expr.negated);
1548 assert!(matches!(
1549 params.filters_root[0].op_expr.operation,
1550 Operation::Quant {
1551 quantifier: Some(OpQuantifier::Any),
1552 ..
1553 }
1554 ));
1555 }
1556
1557 #[test]
1558 fn test_quantifier_form_does_not_capture_fts_language() {
1559 let params = parse_query_params("body=fts(english).cat", false).unwrap();
1562 match ¶ms.filters_root[0].op_expr.operation {
1563 Operation::Fts { language, .. } => {
1564 assert_eq!(language.as_deref(), Some("english"));
1565 }
1566 other => panic!("expected an fts operation, got {:?}", other),
1567 }
1568 }
1569
1570 #[test]
1571 fn test_parse_is_null() {
1572 let params = parse_query_params("deleted_at=is.null", false).unwrap();
1573 match ¶ms.filters_root[0].op_expr.operation {
1574 Operation::Is(IsValue::Null) => {}
1575 _ => panic!("Expected Is Null"),
1576 }
1577 }
1578
1579 #[test]
1580 fn test_parse_order() {
1581 let params = parse_query_params("order=name.asc,age.desc.nullslast", false).unwrap();
1582 assert_eq!(params.order.len(), 1);
1583 let (_, terms) = ¶ms.order[0];
1584 assert_eq!(terms.len(), 2);
1585 }
1586
1587 #[test]
1588 fn test_parse_limit_offset() {
1589 let params = parse_query_params("limit=10&offset=20", false).unwrap();
1590 let range = params.ranges.get("").unwrap();
1591 assert_eq!(range.limit, Some(10));
1592 assert_eq!(range.offset, 20);
1593 }
1594
1595 #[test]
1596 fn test_parse_select() {
1597 let items = parse_select("id,name,orders(id,amount)").unwrap();
1598 assert_eq!(items.len(), 3);
1599 }
1600
1601 #[test]
1602 fn test_parse_fts() {
1603 let params = parse_query_params("content=fts(english).search+term", false).unwrap();
1604 match ¶ms.filters_root[0].op_expr.operation {
1605 Operation::Fts {
1606 op,
1607 language,
1608 value,
1609 } => {
1610 assert_eq!(*op, FtsOperator::Fts);
1611 assert_eq!(language.as_deref(), Some("english"));
1612 assert_eq!(value, "search+term");
1613 }
1614 _ => panic!("Expected FTS operation"),
1615 }
1616 }
1617 #[test]
1619 fn an_empty_columns_parameter_is_a_parse_error() {
1620 let error = parse_columns("").unwrap_err();
1621 assert_eq!(
1622 error.to_string(),
1623 "\"failed to parse columns parameter ()\" (line 1, column 1)"
1624 );
1625 match error {
1626 Error::UnparsableQuery { expected, .. } => assert_eq!(
1627 expected,
1628 "unexpected end of input expecting field name (* or [a..z0..9_$])"
1629 ),
1630 other => panic!("wrong variant: {:?}", other),
1631 }
1632 }
1633
1634 #[test]
1636 fn a_missing_field_in_columns_is_reported_where_it_is() {
1637 let error = parse_columns("a,,b").unwrap_err();
1638 assert_eq!(
1639 error.to_string(),
1640 "\"failed to parse columns parameter (a,,b)\" (line 1, column 3)"
1641 );
1642 }
1643
1644 #[test]
1645 fn columns_parses_a_plain_list() {
1646 assert_eq!(
1647 parse_columns("a, b ,c").unwrap(),
1648 vec!["a".to_string(), "b".to_string(), "c".to_string()]
1649 );
1650 }
1651
1652 #[test]
1655 fn a_json_path_index_that_is_not_a_number_is_refused() {
1656 assert!(parse_select("data->>--34").is_err());
1657 assert!(parse_select("data->>-34").is_ok());
1658 assert!(parse_select("data->>34").is_ok());
1659 assert!(parse_select("data->>key").is_ok());
1660 }
1661 #[test]
1665 fn an_empty_logic_tree_member_names_the_character_and_the_column() {
1666 let error = parse_logic_param(LogicOperator::Or, false, "()").unwrap_err();
1667 assert_eq!(
1668 error.to_string(),
1669 "\"failed to parse logic tree (())\" (line 1, column 4)"
1670 );
1671 match &error {
1672 Error::UnparsableQuery { expected, .. } => assert_eq!(
1673 expected,
1674 "unexpected \")\" expecting field name (* or [a..z0..9_$]), \
1675 negation operator (not) or logic operator (and, or)"
1676 ),
1677 other => panic!("wrong variant: {:?}", other),
1678 }
1679
1680 let error = parse_logic_param(LogicOperator::And, false, "()").unwrap_err();
1682 assert_eq!(
1683 error.to_string(),
1684 "\"failed to parse logic tree (())\" (line 1, column 5)"
1685 );
1686
1687 let error = parse_logic_param(LogicOperator::Or, false, "(,)").unwrap_err();
1689 assert_eq!(
1690 error.to_string(),
1691 "\"failed to parse logic tree ((,))\" (line 1, column 4)"
1692 );
1693 }
1694}