1use super::types::*;
7use crate::error::{Error, Result};
8use nom::{
9 branch::alt,
10 bytes::complete::{tag, take_while1},
11 character::complete::{char, digit1},
12 combinator::{map, 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) -> Result<QueryParams> {
21 let mut params = QueryParams::default();
22
23 if query.is_empty() {
24 return Ok(params);
25 }
26
27 let mut pairs: Vec<(&str, &str)> = query
29 .split('&')
30 .filter_map(|pair| {
31 let mut parts = pair.splitn(2, '=');
32 Some((parts.next()?, parts.next().unwrap_or("")))
33 })
34 .collect();
35 pairs.sort_by_key(|(k, _)| *k);
36 params.canonical = pairs
37 .iter()
38 .map(|(k, v)| format!("{}={}", k, v))
39 .collect::<Vec<_>>()
40 .join("&");
41
42 for (key, value) in pairs {
43 let decoded_value = percent_decode_str(value)
44 .decode_utf8()
45 .map_err(|_| Error::InvalidQueryParam(key.into()))?
46 .to_string();
47
48 match key {
49 "select" => {
50 params.select = parse_select(&decoded_value)?;
51 }
52 "order" => {
53 let (path, terms) = parse_order_param(&decoded_value)?;
54 params.order.push((path, terms));
55 }
56 "limit" => {
57 let limit: i64 = decoded_value
58 .parse()
59 .map_err(|_| Error::InvalidQueryParam("limit".into()))?;
60 params.ranges.entry(String::new()).or_default().limit = Some(limit);
61 }
62 "offset" => {
63 let offset: i64 = decoded_value
64 .parse()
65 .map_err(|_| Error::InvalidQueryParam("offset".into()))?;
66 params.ranges.entry(String::new()).or_default().offset = offset;
67 }
68 "columns" => {
69 params.columns = Some(
70 decoded_value
71 .split(',')
72 .map(|s| s.trim().to_string())
73 .collect(),
74 );
75 }
76 "on_conflict" => {
77 params.on_conflict = Some(
78 decoded_value
79 .split(',')
80 .map(|s| s.trim().to_string())
81 .collect(),
82 );
83 }
84 "and" | "or" => {
85 let logic = parse_logic_param(key, &decoded_value)?;
86 params.logic.push((vec![], logic));
87 }
88 key if !key.starts_with('_') => {
89 let (path, filter) = parse_filter_param(key, &decoded_value)?;
91 if path.is_empty() {
92 params.filter_fields.insert(filter.field.name.clone());
93 params.filters_root.push(filter);
94 } else {
95 params.filters.push((path, filter));
96 }
97 }
98 _ => {
99 params.params.push((key.to_string(), decoded_value));
101 }
102 }
103 }
104
105 Ok(params)
106}
107
108pub fn parse_select(input: &str) -> Result<Vec<SelectItem>> {
114 if input.is_empty() {
115 return Ok(vec![]);
116 }
117
118 match parse_select_items(input) {
119 Ok((_, items)) => Ok(items),
120 Err(_) => Err(Error::InvalidQueryParam("select".into())),
121 }
122}
123
124fn parse_select_items(input: &str) -> IResult<&str, Vec<SelectItem>> {
125 separated_list0(char(','), parse_select_item)(input)
126}
127
128fn parse_select_item(input: &str) -> IResult<&str, SelectItem> {
129 alt((
130 parse_spread_relation,
131 parse_relation_select,
132 parse_field_select,
133 ))(input)
134}
135
136fn parse_spread_relation(input: &str) -> IResult<&str, SelectItem> {
138 let (input, _) = tag("...")(input)?;
139 let (input, relation) = parse_identifier(input)?;
140 let (input, hint) = opt(preceded(char('!'), parse_identifier))(input)?;
141 let (input, join_type) = opt(preceded(char('!'), parse_join_type))(input)?;
142
143 Ok((
144 input,
145 SelectItem::SpreadRelation {
146 relation: relation.to_string(),
147 hint: hint.map(|s| s.to_string()),
148 join_type,
149 },
150 ))
151}
152
153fn parse_nested_select(input: &str) -> IResult<&str, Vec<SelectItem>> {
159 let mut depth = 0usize;
160 let mut end = input.len();
161
162 for (idx, ch) in input.char_indices() {
163 match ch {
164 '(' => depth += 1,
165 ')' => {
166 if depth == 0 {
167 end = idx;
168 break;
169 }
170 depth -= 1;
171 }
172 _ => {}
173 }
174 }
175
176 let (body, rest) = input.split_at(end);
177
178 if body.is_empty() {
179 return Ok((rest, Vec::new()));
180 }
181
182 match parse_select_items(body) {
183 Ok(("", items)) => Ok((rest, items)),
184 _ => Err(nom::Err::Error(nom::error::Error::new(
185 input,
186 nom::error::ErrorKind::Verify,
187 ))),
188 }
189}
190
191fn parse_relation_select(input: &str) -> IResult<&str, SelectItem> {
193 let (input, name) = parse_identifier(input)?;
194 let (input, alias) = opt(preceded(char(':'), parse_identifier))(input)?;
195 let (input, hint) = opt(preceded(char('!'), parse_identifier))(input)?;
196 let (input, join_type) = opt(preceded(char('!'), parse_join_type))(input)?;
197 let (input, _) = char('(')(input)?;
201 let (input, nested) = parse_nested_select(input)?;
202 let (input, _) = char(')')(input)?;
203
204 Ok((
205 input,
206 SelectItem::Relation {
207 relation: name.to_string(),
208 alias: alias.map(|s| s.to_string()),
209 hint: hint.map(|s| s.to_string()),
210 join_type,
211 select: nested,
212 },
213 ))
214}
215
216fn parse_field_select(input: &str) -> IResult<&str, SelectItem> {
218 let (input, aggregate) = opt(parse_aggregate_prefix)(input)?;
220
221 let (input, name) = parse_identifier(input)?;
222 let (input, json_path) = parse_json_path(input)?;
223
224 let (input, aggregate_cast) = if aggregate.is_some() {
226 let (input, _) = char(')')(input)?;
227 let (input, cast) = opt(preceded(tag("::"), parse_identifier))(input)?;
228 (input, cast.map(|s| s.to_string()))
229 } else {
230 (input, None)
231 };
232
233 let (input, cast) = if aggregate.is_none() {
234 opt(preceded(tag("::"), parse_identifier))(input)?
235 } else {
236 (input, None)
237 };
238
239 let (input, alias) = opt(preceded(char(':'), parse_identifier))(input)?;
240
241 Ok((
242 input,
243 SelectItem::Field {
244 field: Field {
245 name: name.to_string(),
246 json_path,
247 },
248 aggregate,
249 aggregate_cast,
250 cast: cast.map(|s| s.to_string()),
251 alias: alias.map(|s| s.to_string()),
252 },
253 ))
254}
255
256fn parse_aggregate_prefix(input: &str) -> IResult<&str, AggregateFunction> {
257 alt((
258 value(AggregateFunction::Sum, tag("sum(")),
259 value(AggregateFunction::Avg, tag("avg(")),
260 value(AggregateFunction::Max, tag("max(")),
261 value(AggregateFunction::Min, tag("min(")),
262 value(AggregateFunction::Count, tag("count(")),
263 ))(input)
264}
265
266fn parse_join_type(input: &str) -> IResult<&str, JoinType> {
267 alt((
268 value(JoinType::Inner, tag("inner")),
269 value(JoinType::Left, tag("left")),
270 ))(input)
271}
272
273fn parse_filter_param(key: &str, value: &str) -> Result<(EmbedPath, Filter)> {
279 let (path, field_name) = parse_filter_key(key)?;
281
282 let op_expr = parse_filter_value(value)?;
284
285 let filter = Filter::new(Field::simple(field_name), op_expr);
286 Ok((path, filter))
287}
288
289fn parse_filter_key(key: &str) -> Result<(EmbedPath, String)> {
291 let parts: Vec<&str> = key.split('.').collect();
292 if parts.is_empty() {
293 return Err(Error::InvalidQueryParam(key.into()));
294 }
295
296 if parts.len() == 1 {
297 return Ok((vec![], parts[0].to_string()));
298 }
299
300 let path: Vec<String> = parts[..parts.len() - 1]
301 .iter()
302 .map(|s| s.to_string())
303 .collect();
304 let field = parts.last().unwrap().to_string();
305 Ok((path, field))
306}
307
308fn parse_filter_value(value: &str) -> Result<OpExpr> {
310 let (value, negated) = if let Some(rest) = value.strip_prefix("not.") {
311 (rest, true)
312 } else {
313 (value, false)
314 };
315
316 let operation = parse_operation(value)?;
317 Ok(OpExpr { negated, operation })
318}
319
320fn parse_operation(value: &str) -> Result<Operation> {
322 if let Some(rest) = value.strip_prefix("eq.") {
324 return Ok(Operation::Quant {
325 op: QuantOperator::Equal,
326 quantifier: None,
327 value: rest.to_string(),
328 });
329 }
330 if let Some(rest) = value.strip_prefix("neq.") {
331 return Ok(Operation::Simple {
332 op: SimpleOperator::NotEqual,
333 value: rest.to_string(),
334 });
335 }
336 if let Some(rest) = value.strip_prefix("gt.") {
337 return Ok(Operation::Quant {
338 op: QuantOperator::GreaterThan,
339 quantifier: None,
340 value: rest.to_string(),
341 });
342 }
343 if let Some(rest) = value.strip_prefix("gte.") {
344 return Ok(Operation::Quant {
345 op: QuantOperator::GreaterThanEqual,
346 quantifier: None,
347 value: rest.to_string(),
348 });
349 }
350 if let Some(rest) = value.strip_prefix("lt.") {
351 return Ok(Operation::Quant {
352 op: QuantOperator::LessThan,
353 quantifier: None,
354 value: rest.to_string(),
355 });
356 }
357 if let Some(rest) = value.strip_prefix("lte.") {
358 return Ok(Operation::Quant {
359 op: QuantOperator::LessThanEqual,
360 quantifier: None,
361 value: rest.to_string(),
362 });
363 }
364 if let Some(rest) = value.strip_prefix("like.") {
365 return Ok(Operation::Quant {
366 op: QuantOperator::Like,
367 quantifier: None,
368 value: rest.to_string(),
369 });
370 }
371 if let Some(rest) = value.strip_prefix("ilike.") {
372 return Ok(Operation::Quant {
373 op: QuantOperator::ILike,
374 quantifier: None,
375 value: rest.to_string(),
376 });
377 }
378 if let Some(rest) = value.strip_prefix("match.") {
379 return Ok(Operation::Quant {
380 op: QuantOperator::Match,
381 quantifier: None,
382 value: rest.to_string(),
383 });
384 }
385 if let Some(rest) = value.strip_prefix("imatch.") {
386 return Ok(Operation::Quant {
387 op: QuantOperator::IMatch,
388 quantifier: None,
389 value: rest.to_string(),
390 });
391 }
392
393 if let Some(rest) = value.strip_prefix("cs.") {
395 return Ok(Operation::Simple {
396 op: SimpleOperator::Contains,
397 value: rest.to_string(),
398 });
399 }
400 if let Some(rest) = value.strip_prefix("cd.") {
401 return Ok(Operation::Simple {
402 op: SimpleOperator::Contained,
403 value: rest.to_string(),
404 });
405 }
406 if let Some(rest) = value.strip_prefix("ov.") {
407 return Ok(Operation::Simple {
408 op: SimpleOperator::Overlap,
409 value: rest.to_string(),
410 });
411 }
412 if let Some(rest) = value.strip_prefix("sl.") {
413 return Ok(Operation::Simple {
414 op: SimpleOperator::StrictlyLeft,
415 value: rest.to_string(),
416 });
417 }
418 if let Some(rest) = value.strip_prefix("sr.") {
419 return Ok(Operation::Simple {
420 op: SimpleOperator::StrictlyRight,
421 value: rest.to_string(),
422 });
423 }
424 if let Some(rest) = value.strip_prefix("nxr.") {
425 return Ok(Operation::Simple {
426 op: SimpleOperator::NotExtendsRight,
427 value: rest.to_string(),
428 });
429 }
430 if let Some(rest) = value.strip_prefix("nxl.") {
431 return Ok(Operation::Simple {
432 op: SimpleOperator::NotExtendsLeft,
433 value: rest.to_string(),
434 });
435 }
436 if let Some(rest) = value.strip_prefix("adj.") {
437 return Ok(Operation::Simple {
438 op: SimpleOperator::Adjacent,
439 value: rest.to_string(),
440 });
441 }
442
443 if let Some(rest) = value.strip_prefix("in.") {
445 let values = parse_in_list(rest)?;
446 return Ok(Operation::In(values));
447 }
448
449 if let Some(rest) = value.strip_prefix("is.") {
451 let is_val = match rest {
452 "null" => IsValue::Null,
453 "true" => IsValue::True,
454 "false" => IsValue::False,
455 "unknown" => IsValue::Unknown,
456 _ => return Err(Error::InvalidQueryParam(format!("is.{}", rest))),
457 };
458 return Ok(Operation::Is(is_val));
459 }
460
461 if let Some(rest) = value.strip_prefix("isdistinct.") {
463 return Ok(Operation::IsDistinctFrom(rest.to_string()));
464 }
465
466 if let Some(rest) = value.strip_prefix("fts") {
468 return parse_fts(FtsOperator::Fts, rest);
469 }
470 if let Some(rest) = value.strip_prefix("plfts") {
471 return parse_fts(FtsOperator::Plain, rest);
472 }
473 if let Some(rest) = value.strip_prefix("phfts") {
474 return parse_fts(FtsOperator::Phrase, rest);
475 }
476 if let Some(rest) = value.strip_prefix("wfts") {
477 return parse_fts(FtsOperator::Websearch, rest);
478 }
479
480 Err(Error::InvalidQueryParam(value.into()))
481}
482
483fn parse_in_list(value: &str) -> Result<Vec<String>> {
485 let value = value
486 .strip_prefix('(')
487 .and_then(|s| s.strip_suffix(')'))
488 .ok_or_else(|| Error::InvalidQueryParam(format!("in.{}", value)))?;
489
490 Ok(value.split(',').map(|s| s.trim().to_string()).collect())
491}
492
493fn parse_fts(op: FtsOperator, rest: &str) -> Result<Operation> {
495 if let Some(rest) = rest.strip_prefix('(') {
496 let (lang, query) = rest
498 .split_once(").")
499 .ok_or_else(|| Error::InvalidQueryParam(format!("fts{}", rest)))?;
500 return Ok(Operation::Fts {
501 op,
502 language: Some(lang.to_string()),
503 value: query.to_string(),
504 });
505 }
506
507 let query = rest
508 .strip_prefix('.')
509 .ok_or_else(|| Error::InvalidQueryParam(format!("fts{}", rest)))?;
510 Ok(Operation::Fts {
511 op,
512 language: None,
513 value: query.to_string(),
514 })
515}
516
517fn parse_order_param(value: &str) -> Result<(EmbedPath, Vec<OrderTerm>)> {
523 let terms: Vec<OrderTerm> = value
524 .split(',')
525 .map(|s| parse_order_term(s.trim()))
526 .collect::<Result<Vec<_>>>()?;
527 Ok((vec![], terms))
528}
529
530fn parse_order_term(value: &str) -> Result<OrderTerm> {
531 let parts: Vec<&str> = value.split('.').collect();
532 if parts.is_empty() {
533 return Err(Error::InvalidQueryParam("order".into()));
534 }
535
536 let field_name = parts[0];
537 let mut direction = None;
538 let mut nulls = None;
539
540 for part in &parts[1..] {
541 match *part {
542 "asc" => direction = Some(OrderDirection::Asc),
543 "desc" => direction = Some(OrderDirection::Desc),
544 "nullsfirst" => nulls = Some(OrderNulls::First),
545 "nullslast" => nulls = Some(OrderNulls::Last),
546 _ => {}
547 }
548 }
549
550 Ok(OrderTerm::Field {
551 field: Field::simple(field_name),
552 direction,
553 nulls,
554 })
555}
556
557fn parse_logic_param(op: &str, value: &str) -> Result<LogicTree> {
563 let logic_op = match op {
564 "and" => LogicOperator::And,
565 "or" => LogicOperator::Or,
566 _ => return Err(Error::InvalidQueryParam(op.into())),
567 };
568
569 let value = value
571 .strip_prefix('(')
572 .and_then(|s| s.strip_suffix(')'))
573 .ok_or_else(|| Error::InvalidQueryParam(format!("{}={}", op, value)))?;
574
575 let children: Vec<LogicTree> = value
576 .split(',')
577 .map(|s| {
578 let (key, val) = s
579 .split_once('.')
580 .ok_or_else(|| Error::InvalidQueryParam(s.into()))?;
581 let (_, filter) = parse_filter_param(key, val)?;
582 Ok(LogicTree::Stmt(filter))
583 })
584 .collect::<Result<Vec<_>>>()?;
585
586 Ok(LogicTree::Expr {
587 negated: false,
588 op: logic_op,
589 children,
590 })
591}
592
593fn parse_identifier(input: &str) -> IResult<&str, &str> {
598 take_while1(|c: char| c.is_alphanumeric() || c == '_')(input)
599}
600
601fn parse_json_path(input: &str) -> IResult<&str, JsonPath> {
602 many0(alt((parse_arrow, parse_double_arrow)))(input)
603}
604
605fn parse_arrow(input: &str) -> IResult<&str, JsonOperation> {
606 let (input, _) = tag("->")(input)?;
607 let (input, operand) = alt((
608 map(digit1, |s: &str| JsonOperand::Idx(s.parse().unwrap_or(0))),
609 map(parse_identifier, |s| JsonOperand::Key(s.to_string())),
610 ))(input)?;
611 Ok((input, JsonOperation::Arrow(operand)))
612}
613
614fn parse_double_arrow(input: &str) -> IResult<&str, JsonOperation> {
615 let (input, _) = tag("->>")(input)?;
616 let (input, operand) = alt((
617 map(digit1, |s: &str| JsonOperand::Idx(s.parse().unwrap_or(0))),
618 map(parse_identifier, |s| JsonOperand::Key(s.to_string())),
619 ))(input)?;
620 Ok((input, JsonOperation::DoubleArrow(operand)))
621}
622
623#[cfg(test)]
624mod tests {
625 use super::*;
626
627 #[test]
628 fn test_parse_simple_filter() {
629 let params = parse_query_params("name=eq.John").unwrap();
630 assert_eq!(params.filters_root.len(), 1);
631 assert_eq!(params.filters_root[0].field.name, "name");
632 }
633
634 #[test]
635 fn test_parse_negated_filter() {
636 let params = parse_query_params("status=not.eq.active").unwrap();
637 assert!(params.filters_root[0].op_expr.negated);
638 }
639
640 #[test]
641 fn test_parse_in_filter() {
642 let params = parse_query_params("id=in.(1,2,3)").unwrap();
643 match ¶ms.filters_root[0].op_expr.operation {
644 Operation::In(values) => {
645 assert_eq!(values, &vec!["1", "2", "3"]);
646 }
647 _ => panic!("Expected In operation"),
648 }
649 }
650
651 #[test]
652 fn test_parse_is_null() {
653 let params = parse_query_params("deleted_at=is.null").unwrap();
654 match ¶ms.filters_root[0].op_expr.operation {
655 Operation::Is(IsValue::Null) => {}
656 _ => panic!("Expected Is Null"),
657 }
658 }
659
660 #[test]
661 fn test_parse_order() {
662 let params = parse_query_params("order=name.asc,age.desc.nullslast").unwrap();
663 assert_eq!(params.order.len(), 1);
664 let (_, terms) = ¶ms.order[0];
665 assert_eq!(terms.len(), 2);
666 }
667
668 #[test]
669 fn test_parse_limit_offset() {
670 let params = parse_query_params("limit=10&offset=20").unwrap();
671 let range = params.ranges.get("").unwrap();
672 assert_eq!(range.limit, Some(10));
673 assert_eq!(range.offset, 20);
674 }
675
676 #[test]
677 fn test_parse_select() {
678 let items = parse_select("id,name,orders(id,amount)").unwrap();
679 assert_eq!(items.len(), 3);
680 }
681
682 #[test]
683 fn test_parse_fts() {
684 let params = parse_query_params("content=fts(english).search+term").unwrap();
685 match ¶ms.filters_root[0].op_expr.operation {
686 Operation::Fts {
687 op,
688 language,
689 value,
690 } => {
691 assert_eq!(*op, FtsOperator::Fts);
692 assert_eq!(language.as_deref(), Some("english"));
693 assert_eq!(value, "search+term");
694 }
695 _ => panic!("Expected FTS operation"),
696 }
697 }
698}