1#![allow(clippy::empty_docs)]
2
3use crate::parser::errors::JsonPathParserError;
4use crate::parser::model::FilterExpression::{And, Not, Or};
5use crate::parser::model::{
6 FilterExpression, FilterSign, Function, JsonPath, JsonPathIndex, Operand,
7};
8use crate::path::JsonLike;
9use pest::iterators::{Pair, Pairs};
10use pest::Parser;
11
12#[derive(Parser)]
13#[grammar = "parser/grammar/json_path.pest"]
14struct JsonPathParser;
15
16pub fn parse_json_path<T>(jp_str: &str) -> Result<JsonPath<T>, JsonPathParserError>
22where
23 T: JsonLike,
24{
25 JsonPathParser::parse(Rule::path, jp_str)
26 .map_err(Box::new)?
27 .next()
28 .ok_or(JsonPathParserError::UnexpectedPestOutput)
29 .and_then(parse_internal)
30}
31
32fn parse_internal<T>(rule: Pair<'_, Rule>) -> Result<JsonPath<T>, JsonPathParserError>
38where
39 T: JsonLike,
40{
41 match rule.as_rule() {
42 Rule::path => rule
43 .into_inner()
44 .next()
45 .ok_or(JsonPathParserError::NoRulePath)
46 .and_then(parse_internal),
47 Rule::current => rule
48 .into_inner()
49 .next()
50 .map(parse_internal)
51 .unwrap_or(Ok(JsonPath::Empty))
52 .map(Box::new)
53 .map(JsonPath::Current),
54 Rule::chain => rule
55 .into_inner()
56 .map(parse_internal)
57 .collect::<Result<Vec<_>, _>>()
58 .map(JsonPath::Chain),
59 Rule::root => Ok(JsonPath::Root),
60 Rule::wildcard => Ok(JsonPath::Wildcard),
61 Rule::descent => parse_key(down(rule)?)?
62 .map(JsonPath::Descent)
63 .ok_or(JsonPathParserError::NoJsonPathDescent),
64 Rule::descent_w => Ok(JsonPath::DescentW),
65 Rule::function => Ok(JsonPath::Fn(Function::Length)),
66 Rule::field => parse_key(down(rule)?)?
67 .map(JsonPath::Field)
68 .ok_or(JsonPathParserError::NoJsonPathField),
69 Rule::index => parse_index(rule).map(JsonPath::Index),
70 rule => Err(JsonPathParserError::InvalidTopLevelRule(rule)),
71 }
72}
73
74fn parse_key(rule: Pair<Rule>) -> Result<Option<String>, JsonPathParserError> {
76 let parsed_key = match rule.as_rule() {
77 Rule::key | Rule::key_unlim | Rule::string_qt => parse_key(down(rule)?),
78 Rule::key_lim | Rule::inner => Ok(Some(String::from(rule.as_str()))),
79 _ => Ok(None),
80 };
81 parsed_key
82}
83
84fn parse_slice<T>(pairs: Pairs<Rule>) -> Result<JsonPathIndex<T>, JsonPathParserError> {
85 let mut start = 0;
86 let mut end = 0;
87 let mut step = 1;
88 for in_pair in pairs {
89 match in_pair.as_rule() {
90 Rule::start_slice => start = in_pair.as_str().parse::<i32>().unwrap_or(start),
91 Rule::end_slice => end = in_pair.as_str().parse::<i32>().unwrap_or(end),
92 Rule::step_slice => step = down(in_pair)?.as_str().parse::<usize>().unwrap_or(step),
93 _ => (),
94 }
95 }
96 Ok(JsonPathIndex::Slice(start, end, step))
97}
98
99fn parse_unit_keys<T>(pairs: Pairs<Rule>) -> Result<JsonPathIndex<T>, JsonPathParserError> {
100 let mut keys = vec![];
101
102 for pair in pairs {
103 keys.push(String::from(down(pair)?.as_str()));
104 }
105 Ok(JsonPathIndex::UnionKeys(keys))
106}
107
108fn number_to_value<T>(number: &str) -> Result<T, JsonPathParserError>
109where
110 T: From<i64> + From<f64>,
111{
112 match number
113 .parse::<i64>()
114 .ok()
115 .map(T::from)
116 .or_else(|| number.parse::<f64>().ok().map(T::from))
117 {
118 Some(value) => Ok(value),
119 None => Err(JsonPathParserError::InvalidNumber(number.to_string())),
120 }
121}
122
123fn bool_to_value<T>(boolean: &str) -> T
124where
125 T: From<bool>,
126{
127 boolean
128 .parse::<bool>()
129 .map(T::from)
130 .expect("unreachable: according to .pest this is either `true` or `false`")
131}
132
133fn parse_unit_indexes<T>(pairs: Pairs<Rule>) -> Result<JsonPathIndex<T>, JsonPathParserError>
134where
135 T: From<i64> + From<f64>,
136{
137 let mut keys = vec![];
138
139 for pair in pairs {
140 keys.push(number_to_value(pair.as_str())?);
141 }
142 Ok(JsonPathIndex::UnionIndex(keys))
143}
144
145fn parse_chain_in_operand<T>(rule: Pair<'_, Rule>) -> Result<Operand<T>, JsonPathParserError>
146where
147 T: JsonLike,
148{
149 let parsed_chain = match parse_internal::<T>(rule)? {
150 JsonPath::Chain(elems) => {
151 if elems.len() == 1 {
152 match elems.first() {
153 Some(JsonPath::Index(JsonPathIndex::UnionKeys(keys))) => {
154 Operand::val(T::from(keys.clone()))
155 }
156 Some(JsonPath::Index(JsonPathIndex::UnionIndex(keys))) => {
157 Operand::val(T::from(keys.clone()))
158 }
159 Some(JsonPath::Field(f)) => Operand::val(T::from(vec![f.to_string()])),
160 _ => Operand::Dynamic(Box::new(JsonPath::Chain(elems))),
161 }
162 } else {
163 Operand::Dynamic(Box::new(JsonPath::Chain(elems)))
164 }
165 }
166 jp => Operand::Dynamic(Box::new(jp)),
167 };
168 Ok(parsed_chain)
169}
170
171fn parse_filter_index<T>(pair: Pair<'_, Rule>) -> Result<JsonPathIndex<T>, JsonPathParserError>
172where
173 T: JsonLike,
174{
175 Ok(JsonPathIndex::Filter(parse_logic_or(pair.into_inner())?))
176}
177
178fn parse_logic_or<T>(pairs: Pairs<'_, Rule>) -> Result<FilterExpression<T>, JsonPathParserError>
179where
180 T: JsonLike,
181{
182 let mut expr: Option<FilterExpression<T>> = None;
183 if pairs.len() == 0 {
185 return Err(JsonPathParserError::UnexpectedNoneLogicError(
186 pairs.get_input().to_string(),
187 pairs.as_str().to_string(),
188 ));
189 }
190 for pair in pairs.into_iter() {
191 let next_expr = parse_logic_and(pair.into_inner())?;
192 match expr {
193 None => expr = Some(next_expr),
194 Some(e) => expr = Some(Or(Box::new(e), Box::new(next_expr))),
195 }
196 }
197 Ok(expr.expect("unreachable: above len() == 0 check should have catched this"))
198}
199
200fn parse_logic_and<T>(pairs: Pairs<'_, Rule>) -> Result<FilterExpression<T>, JsonPathParserError>
201where
202 T: JsonLike,
203{
204 let mut expr: Option<FilterExpression<T>> = None;
205 if pairs.len() == 0 {
207 return Err(JsonPathParserError::UnexpectedNoneLogicError(
208 pairs.get_input().to_string(),
209 pairs.as_str().to_string(),
210 ));
211 }
212 for pair in pairs {
213 let next_expr = parse_logic_not(pair.into_inner())?;
214 match expr {
215 None => expr = Some(next_expr),
216 Some(e) => expr = Some(And(Box::new(e), Box::new(next_expr))),
217 }
218 }
219 Ok(expr.expect("unreachable: above len() == 0 check should have catched this"))
220}
221
222fn parse_logic_not<T>(
223 mut pairs: Pairs<'_, Rule>,
224) -> Result<FilterExpression<T>, JsonPathParserError>
225where
226 T: JsonLike,
227{
228 if let Some(rule) = pairs.peek().map(|x| x.as_rule()) {
229 match rule {
230 Rule::not => {
231 pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)");
232 parse_logic_not(pairs)
233 .map(|expr|Not(Box::new(expr)))
234 },
235 Rule::logic_atom => parse_logic_atom(pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)").into_inner()),
236 rule => Err(JsonPathParserError::UnexpectedRuleLogicError(rule, pairs.get_input().to_string(), pairs.as_str().to_string())),
237 }
238 } else {
239 Err(JsonPathParserError::UnexpectedNoneLogicError(
240 pairs.get_input().to_string(),
241 pairs.as_str().to_string(),
242 ))
243 }
244}
245
246fn parse_logic_atom<T>(
247 mut pairs: Pairs<'_, Rule>,
248) -> Result<FilterExpression<T>, JsonPathParserError>
249where
250 T: JsonLike,
251{
252 if let Some(rule) = pairs.peek().map(|x| x.as_rule()) {
253 match rule {
254 Rule::logic_or => parse_logic_or(pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)").into_inner()),
255 Rule::atom => {
256 let left: Operand<T> = parse_atom(pairs.next().unwrap())?;
257 if pairs.peek().is_none() {
258 Ok(FilterExpression::exists(left))
259 } else {
260 let sign: FilterSign = FilterSign::new(pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)").as_str());
261 let right: Operand<T> =
262 parse_atom(pairs.next().expect("unreachable in arithemetic: should have a right side operand"))?;
263 Ok(FilterExpression::Atom(left, sign, right))
264 }
265 }
266 rule => Err(JsonPathParserError::UnexpectedRuleLogicError(rule, pairs.get_input().to_string(), pairs.as_str().to_string())),
267 }
268 } else {
269 Err(JsonPathParserError::UnexpectedNoneLogicError(
270 pairs.get_input().to_string(),
271 pairs.as_str().to_string(),
272 ))
273 }
274}
275
276fn parse_atom<T>(rule: Pair<'_, Rule>) -> Result<Operand<T>, JsonPathParserError>
277where
278 T: JsonLike,
279{
280 let atom = down(rule.clone())?;
281 let parsed_atom = match atom.as_rule() {
282 Rule::number => Operand::Static(number_to_value(rule.as_str())?),
283 Rule::string_qt => Operand::Static(T::from(down(atom)?.as_str())),
284 Rule::chain => parse_chain_in_operand(down(rule)?)?,
285 Rule::boolean => Operand::Static(bool_to_value(rule.as_str())),
286 _ => Operand::Static(T::null()),
287 };
288 Ok(parsed_atom)
289}
290
291fn parse_index<T>(rule: Pair<'_, Rule>) -> Result<JsonPathIndex<T>, JsonPathParserError>
292where
293 T: JsonLike,
294{
295 let next = down(rule)?;
296 let parsed_index = match next.as_rule() {
297 Rule::unsigned => JsonPathIndex::Single(number_to_value(next.as_str())?),
298 Rule::slice => parse_slice(next.into_inner())?,
299 Rule::unit_indexes => parse_unit_indexes(next.into_inner())?,
300 Rule::unit_keys => parse_unit_keys(next.into_inner())?,
301 Rule::filter => parse_filter_index(down(next)?)?,
302 _ => JsonPathIndex::Single(number_to_value(next.as_str())?),
303 };
304 Ok(parsed_index)
305}
306
307fn down(rule: Pair<Rule>) -> Result<Pair<Rule>, JsonPathParserError> {
308 let error_message = rule.to_string();
309 match rule.into_inner().next() {
310 Some(rule) => Ok(rule),
311 None => Err(JsonPathParserError::EmptyInner(error_message)),
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use crate::parser::macros::{chain, filter, idx, op};
319 use crate::path;
320 use serde_json::{json, Value};
321 use std::panic;
322
323 fn test_failed(input: &str) {
324 match parse_json_path::<Value>(input) {
325 Ok(elem) => panic!("should be false but got {:?}", elem),
326 Err(e) => println!("{}", e),
327 }
328 }
329
330 fn test<T>(input: &str, expected: Vec<JsonPath<T>>)
331 where
332 T: JsonLike,
333 {
334 match parse_json_path::<T>(input) {
335 Ok(JsonPath::Chain(elems)) => assert_eq!(elems, expected),
336 Ok(e) => panic!("unexpected value {:?}", e),
337 Err(e) => {
338 panic!("parsing error {}", e);
339 }
340 }
341 }
342
343 #[test]
344 fn path_test() {
345 test::<Value>("$.k.['k']['k']..k..['k'].*.[*][*][1][1,2]['k','k'][:][10:][:10][10:10:10][?(@)][?(@.abc >= 10)]",
346 vec![
347 path!($),
348 path!("k"),
349 path!("k"),
350 path!("k"),
351 path!(.."k"),
352 path!(.."k"),
353 path!(*),
354 path!(*),
355 path!(*),
356 path!(idx!(1)),
357 path!(idx!(idx 1,2)),
358 path!(idx!("k","k")),
359 path!(idx!([; ;])),
360 path!(idx!([10; ;])),
361 path!(idx!([;10;])),
362 path!(idx!([10;10;10])),
363 path!(idx!(?filter!(op!(chain!(path!(@path!()))), "exists", op!(path!())))),
364 path!(idx!(?filter!(op!(chain!(path!(@,path!("abc")))), ">=", op!(10)))),
365 ]);
366 test::<Value>(
367 "$..*[?(@.isbn)].title",
368 vec![
369 path!($),
371 path!(..*),
372 path!(idx!(?filter!(op!(chain!(path!(@,path!("isbn")))), "exists", op!(path!())))),
373 path!("title"),
374 ],
375 )
376 }
377
378 #[test]
379 fn descent_test() {
380 test::<Value>("..abc", vec![path!(.."abc")]);
381 test::<Value>("..['abc']", vec![path!(.."abc")]);
382 test_failed("...['abc']");
383 test_failed("...abc");
384 }
385
386 #[test]
387 fn field_test() {
388 test::<Value>(".abc", vec![path!("abc")]);
389 test::<Value>(".['abc']", vec![path!("abc")]);
390 test::<Value>("['abc']", vec![path!("abc")]);
391 test::<Value>(".['abc\\\"abc']", vec![path!("abc\\\"abc")]);
392 test_failed(".abc()abc");
393 test_failed("..[abc]");
394 test_failed(".'abc'");
395 }
396
397 #[test]
398 fn wildcard_test() {
399 test::<Value>(".*", vec![path!(*)]);
400 test::<Value>(".[*]", vec![path!(*)]);
401 test::<Value>(".abc.*", vec![path!("abc"), path!(*)]);
402 test::<Value>(".abc.[*]", vec![path!("abc"), path!(*)]);
403 test::<Value>(".abc[*]", vec![path!("abc"), path!(*)]);
404 test::<Value>("..*", vec![path!(..*)]);
405 test_failed("abc*");
406 }
407
408 #[test]
409 fn index_single_test() {
410 test::<Value>("[1]", vec![path!(idx!(1))]);
411 test_failed("[-1]");
412 test_failed("[1a]");
413 }
414
415 #[test]
416 fn index_slice_test() {
417 test::<Value>("[1:1000:10]", vec![path!(idx!([1; 1000; 10]))]);
418 test::<Value>("[:1000:10]", vec![path!(idx!([0; 1000; 10]))]);
419 test::<Value>("[:1000]", vec![path!(idx!([;1000;]))]);
420 test::<Value>("[:]", vec![path!(idx!([;;]))]);
421 test::<Value>("[::10]", vec![path!(idx!([;;10]))]);
422 test_failed("[::-1]");
423 test_failed("[:::0]");
424 }
425
426 #[test]
427 fn index_union_test() {
428 test::<Value>("[1,2,3]", vec![path!(idx!(idx 1,2,3))]);
429 test::<Value>("['abc','bcd']", vec![path!(idx!("abc", "bcd"))]);
430 test_failed("[]");
431 test::<Value>("[-1,-2]", vec![path!(idx!(idx - 1, -2))]);
432 test_failed("[abc,bcd]");
433 test::<Value>("[\"abc\",\"bcd\"]", vec![path!(idx!("abc", "bcd"))]);
434 }
435
436 #[test]
437 fn array_start_test() {
438 test::<Value>(
439 "$.[?(@.verb== \"TEST\")]",
440 vec![
441 path!($),
442 path!(idx!(?filter!(op!(chain!(path!(@,path!("verb")))),"==",op!("TEST")))),
443 ],
444 );
445 }
446
447 #[test]
448 fn logical_filter_test() {
449 test::<Value>(
450 "$.[?(@.verb == 'T' || @.size > 0 && @.size < 10)]",
451 vec![
452 path!($),
453 path!(idx!(?
454 filter!(
455 filter!(op!(chain!(path!(@,path!("verb")))), "==", op!("T")),
456 ||,
457 filter!(
458 filter!(op!(chain!(path!(@,path!("size")))), ">", op!(0)),
459 &&,
460 filter!(op!(chain!(path!(@,path!("size")))), "<", op!(10))
461 )
462 ))),
463 ],
464 );
465 test::<Value>(
466 "$.[?((@.verb == 'T' || @.size > 0) && @.size < 10)]",
467 vec![
468 path!($),
469 path!(idx!(?
470 filter!(
471 filter!(
472 filter!(op!(chain!(path!(@,path!("verb")))), "==", op!("T")),
473 ||,
474 filter!(op!(chain!(path!(@,path!("size")))), ">", op!(0))
475 ),
476 &&,
477 filter!(op!(chain!(path!(@,path!("size")))), "<", op!(10))
478 ))),
479 ],
480 );
481 test::<Value>(
482 "$.[?(@.verb == 'T' || @.size > 0 && @.size < 10 && @.elem == 0)]",
483 vec![
484 path!($),
485 path!(idx!(?filter!(
486 filter!(op!(chain!(path!(@,path!("verb")))), "==", op!("T")),
487 ||,
488 filter!(
489 filter!(
490 filter!(op!(chain!(path!(@,path!("size")))), ">", op!(0)),
491 &&,
492 filter!(op!(chain!(path!(@,path!("size")))), "<", op!(10))
493 ),
494 &&,
495 filter!(op!(chain!(path!(@,path!("elem")))), "==", op!(0))
496 )
497
498 ))),
499 ],
500 );
501 }
502
503 #[test]
504 fn index_filter_test() {
505 test::<Value>(
506 "[?('abc' == 'abc')]",
507 vec![path!(idx!(?filter!(op!("abc"),"==",op!("abc") )))],
508 );
509 test::<Value>(
510 "[?('abc' == 1)]",
511 vec![path!(idx!(?filter!( op!("abc"),"==",op!(1))))],
512 );
513 test::<Value>(
514 "[?('abc' == true)]",
515 vec![path!(idx!(?filter!( op!("abc"),"==",op!(true))))],
516 );
517 test::<Value>(
518 "[?('abc' == null)]",
519 vec![path!(
520 idx!(?filter!( op!("abc"),"==",Operand::Static(Value::Null)))
521 )],
522 );
523
524 test::<Value>(
525 "[?(@.abc in ['abc','bcd'])]",
526 vec![path!(
527 idx!(?filter!(op!(chain!(path!(@,path!("abc")))),"in",Operand::val(json!(["abc","bcd"]))))
528 )],
529 );
530
531 test::<Value>(
532 "[?(@.abc.[*] in ['abc','bcd'])]",
533 vec![path!(idx!(?filter!(
534 op!(chain!(path!(@,path!("abc"), path!(*)))),
535 "in",
536 op!(s json!(["abc","bcd"]))
537 )))],
538 );
539 test::<Value>(
540 "[?(@.[*]..next in ['abc','bcd'])]",
541 vec![path!(idx!(?filter!(
542 op!(chain!(path!(@,path!(*), path!(.."next")))),
543 "in",
544 op!(s json!(["abc","bcd"]))
545 )))],
546 );
547
548 test::<Value>(
549 "[?(@[1] in ['abc','bcd'])]",
550 vec![path!(idx!(?filter!(
551 op!(chain!(path!(@,path!(idx!(1))))),
552 "in",
553 op!(s json!(["abc","bcd"]))
554 )))],
555 );
556 test::<Value>(
557 "[?(@ == 'abc')]",
558 vec![path!(idx!(?filter!(
559 op!(chain!(path!(@path!()))),"==",op!("abc")
560 )))],
561 );
562 test::<Value>(
563 "[?(@ subsetOf ['abc'])]",
564 vec![path!(idx!(?filter!(
565 op!(chain!(path!(@path!()))),"subsetOf",op!(s json!(["abc"]))
566 )))],
567 );
568 test::<Value>(
569 "[?(@[1] subsetOf ['abc','abc'])]",
570 vec![path!(idx!(?filter!(
571 op!(chain!(path!(@,path!(idx!(1))))),
572 "subsetOf",
573 op!(s json!(["abc","abc"]))
574 )))],
575 );
576 test::<Value>(
577 "[?(@ subsetOf [1,2,3])]",
578 vec![path!(idx!(?filter!(
579 op!(chain!(path!(@path!()))),"subsetOf",op!(s json!([1,2,3]))
580 )))],
581 );
582
583 test_failed("[?(@[1] subsetof ['abc','abc'])]");
584 test_failed("[?(@ >< ['abc','abc'])]");
585 test_failed("[?(@ in {\"abc\":1})]");
586 }
587
588 #[test]
589 fn fn_size_test() {
590 test::<Value>(
591 "$.k.length()",
592 vec![path!($), path!("k"), JsonPath::Fn(Function::Length)],
593 );
594
595 test::<Value>(
596 "$.k.length.field",
597 vec![path!($), path!("k"), path!("length"), path!("field")],
598 )
599 }
600
601 #[test]
602 fn parser_error_test_invalid_rule() {
603 let result = parse_json_path::<Value>("notapath");
604
605 assert!(result.is_err());
606 assert!(result
607 .err()
608 .unwrap()
609 .to_string()
610 .starts_with("Failed to parse rule"));
611 }
612
613 #[test]
614 fn parser_error_test_empty_rule() {
615 let result = parse_json_path::<Value>("");
616
617 assert!(result.is_err());
618 assert!(result
619 .err()
620 .unwrap()
621 .to_string()
622 .starts_with("Failed to parse rule"));
623 }
624}