jsonpath_rust/
query.rs

1mod atom;
2mod comparable;
3mod comparison;
4mod filter;
5mod jp_query;
6pub mod queryable;
7mod segment;
8mod selector;
9pub mod state;
10mod test;
11mod test_function;
12
13use crate::parser::errors::JsonPathError;
14use crate::parser::parse_json_path;
15use crate::query::queryable::Queryable;
16use crate::query::state::{Data, Pointer};
17use state::State;
18use std::borrow::Cow;
19
20/// A type that can be queried with JSONPath, typically string
21pub type QueryPath = String;
22
23/// A type that can be queried with JSONPath, typically Result
24pub type Queried<T> = Result<T, JsonPathError>;
25
26/// Main internal trait to implement the logic of processing jsonpath.
27pub trait Query {
28    fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T>;
29}
30
31/// The resulting type of JSONPath query.
32/// It can either be a value or a reference to a value with its path.
33#[derive(Debug, Clone, PartialEq)]
34pub struct QueryRef<'a, T: Queryable>(&'a T, QueryPath);
35
36impl<'a, T: Queryable> From<(&'a T, QueryPath)> for QueryRef<'a, T> {
37    fn from((inner, path): (&'a T, QueryPath)) -> Self {
38        QueryRef(inner, path)
39    }
40}
41impl<'a, T: Queryable> From<(&'a T, &str)> for QueryRef<'a, T> {
42    fn from((inner, path): (&'a T, &str)) -> Self {
43        QueryRef(inner, path.to_string())
44    }
45}
46
47impl<'a, T: Queryable> QueryRef<'a, T> {
48    pub fn val(self) -> &'a T {
49        self.0
50    }
51    pub fn path(self) -> QueryPath {
52        self.1
53    }
54}
55
56impl<'a, T: Queryable> From<Pointer<'a, T>> for QueryRef<'a, T> {
57    fn from(pointer: Pointer<'a, T>) -> Self {
58        QueryRef(pointer.inner, pointer.path)
59    }
60}
61
62/// The main function to process a JSONPath query.
63/// It takes a path and a value, and returns a vector of `QueryResult` thus values + paths.
64pub fn js_path<'a, T: Queryable>(path: &str, value: &'a T) -> Queried<Vec<QueryRef<'a, T>>> {
65    match parse_json_path(path)?.process(State::root(value)).data {
66        Data::Ref(p) => Ok(vec![p.into()]),
67        Data::Refs(refs) => Ok(refs.into_iter().map(Into::into).collect()),
68        Data::Value(v) => Err(v.into()),
69        Data::Nothing => Ok(vec![]),
70    }
71}
72
73/// A convenience function to process a JSONPath query and return a vector of values, omitting the path.
74pub fn js_path_vals<'a, T: Queryable>(path: &str, value: &'a T) -> Queried<Vec<&'a T>> {
75    Ok(js_path(path, value)?
76        .into_iter()
77        .map(|r| r.val())
78        .collect::<Vec<_>>())
79}
80
81/// A convenience function to process a JSONPath query and return a vector of paths, omitting the values.
82pub fn js_path_path<T: Queryable>(path: &str, value: &T) -> Queried<Vec<QueryPath>> {
83    Ok(js_path(path, value)?
84        .into_iter()
85        .map(|r| r.path())
86        .collect::<Vec<_>>())
87}
88
89#[cfg(test)]
90mod tests {
91    use crate::parser::errors::JsonPathError;
92    use crate::parser::Parsed;
93    use crate::query::queryable::Queryable;
94    use crate::query::{js_path, Queried, QueryRef};
95    use crate::JsonPath;
96    use serde_json::{json, Value};
97
98    fn test<'a, R>(json: &'a str, path: &str, expected: Vec<R>) -> Parsed<()>
99    where
100        R: Into<QueryRef<'a, Value>>,
101    {
102        let json: Value = serde_json::from_str(json).map_err(|v| JsonPathError::NoRulePath)?;
103        let expected: Vec<QueryRef<'a, Value>> = expected.into_iter().map(|v| v.into()).collect();
104        assert_eq!(json.query_with_path(path)?, expected);
105
106        Ok(())
107    }
108
109    fn template_json<'a>() -> &'a str {
110        r#" {"store": { "book": [
111             {
112                 "category": "reference",
113                 "author": "Nigel Rees",
114                 "title": "Sayings of the Century",
115                 "price": 8.95
116             },
117             {
118                 "category": "fiction",
119                 "author": "Evelyn Waugh",
120                 "title": "Sword of Honour",
121                 "price": 12.99
122             },
123             {
124                 "category": "fiction",
125                 "author": "Herman Melville",
126                 "title": "Moby Dick",
127                 "isbn": "0-553-21311-3",
128                 "price": 8.99
129             },
130             {
131                 "category": "fiction",
132                 "author": "J. R. R. Tolkien",
133                 "title": "The Lord of the Rings",
134                 "isbn": "0-395-19395-8",
135                 "price": 22.99
136             }
137         ],
138         "bicycle": {
139             "color": "red",
140             "price": 19.95
141         }
142     },
143     "array":[0,1,2,3,4,5,6,7,8,9],
144     "orders":[
145         {
146             "ref":[1,2,3],
147             "id":1,
148             "filled": true
149         },
150         {
151             "ref":[4,5,6],
152             "id":2,
153             "filled": false
154         },
155         {
156             "ref":[7,8,9],
157             "id":3,
158             "filled": null
159         }
160      ],
161     "expensive": 10 }"#
162    }
163    fn update_by_path_test() -> Queried<()> {
164        let mut json = json!([
165            {"verb": "RUN","distance":[1]},
166            {"verb": "TEST"},
167            {"verb": "DO NOT RUN"}
168        ]);
169
170        let path = json.query_only_path("$.[?(@.verb == 'RUN')]")?;
171        let elem = path.first().cloned().unwrap_or_default();
172
173        if let Some(v) = json
174            .reference_mut(elem)
175            .and_then(|v| v.as_object_mut())
176            .and_then(|v| v.get_mut("distance"))
177            .and_then(|v| v.as_array_mut())
178        {
179            v.push(json!(2))
180        }
181
182        assert_eq!(
183            json,
184            json!([
185                {"verb": "RUN","distance":[1,2]},
186                {"verb": "TEST"},
187                {"verb": "DO NOT RUN"}
188            ])
189        );
190
191        Ok(())
192    }
193
194    #[test]
195    fn simple_test() {
196        let j1 = json!(2);
197        let _ = test("[1,2,3]", "$[1]", vec![(&j1, "$[1]".to_string())]);
198    }
199
200    #[test]
201    fn root_test() {
202        let js = serde_json::from_str(template_json()).unwrap();
203        let _ = test(template_json(), "$", vec![(&js, "$")]);
204    }
205
206    #[test]
207    fn descent_test() {
208        let v1 = json!("reference");
209        let v2 = json!("fiction");
210        let _ = test(
211            template_json(),
212            "$..category",
213            vec![
214                (&v1, "$['store']['book'][0]['category']"),
215                (&v2, "$['store']['book'][1]['category']"),
216                (&v2, "$['store']['book'][2]['category']"),
217                (&v2, "$['store']['book'][3]['category']"),
218            ],
219        );
220        let js1 = json!(19.95);
221        let js2 = json!(8.95);
222        let js3 = json!(12.99);
223        let js4 = json!(8.99);
224        let js5 = json!(22.99);
225        let _ = test(
226            template_json(),
227            "$.store..price",
228            vec![
229                (&js1, "$['store']['bicycle']['price']"),
230                (&js2, "$['store']['book'][0]['price']"),
231                (&js3, "$['store']['book'][1]['price']"),
232                (&js4, "$['store']['book'][2]['price']"),
233                (&js5, "$['store']['book'][3]['price']"),
234            ],
235        );
236        let js1 = json!("Nigel Rees");
237        let js2 = json!("Evelyn Waugh");
238        let js3 = json!("Herman Melville");
239        let js4 = json!("J. R. R. Tolkien");
240        let _ = test(
241            template_json(),
242            "$..author",
243            vec![
244                (&js1, "$['store']['book'][0]['author']"),
245                (&js2, "$['store']['book'][1]['author']"),
246                (&js3, "$['store']['book'][2]['author']"),
247                (&js4, "$['store']['book'][3]['author']"),
248            ],
249        );
250    }
251
252    #[test]
253    fn wildcard_test() {
254        let js1 = json!("reference");
255        let js2 = json!("fiction");
256        let _ = test(
257            template_json(),
258            "$..book.[*].category",
259            vec![
260                (&js1, "$['store']['book'][0].['category']"),
261                (&js2, "$['store']['book'][1].['category']"),
262                (&js2, "$['store']['book'][2].['category']"),
263                (&js2, "$['store']['book'][3].['category']"),
264            ],
265        );
266        let js1 = json!("Nigel Rees");
267        let js2 = json!("Evelyn Waugh");
268        let js3 = json!("Herman Melville");
269        let js4 = json!("J. R. R. Tolkien");
270        let _ = test(
271            template_json(),
272            "$.store.book[*].author",
273            vec![
274                (&js1, "$['store']['book'][0]['author']"),
275                (&js2, "$['store']['book'][1]['author']"),
276                (&js3, "$['store']['book'][2]['author']"),
277                (&js4, "$['store']['book'][3]['author']"),
278            ],
279        );
280    }
281
282    #[test]
283    fn descendent_wildcard_test() {
284        let js1 = json!("0-553-21311-3");
285        let js2 = json!("0-395-19395-8");
286        let _ = test(
287            template_json(),
288            "$..*.[?@].isbn",
289            vec![
290                (&js1, "$['store']['book'][2]['isbn']"),
291                (&js2, "$['store']['book'][3]['isbn']"),
292            ],
293        );
294    }
295
296    #[test]
297    fn field_test() {
298        let value = json!({"active":1});
299        let _ = test(
300            r#"{"field":{"field":[{"active":1},{"passive":1}]}}"#,
301            "$.field.field[?@.active]",
302            vec![(&value, "$['field']['field'][0]")],
303        );
304    }
305
306    #[test]
307    fn index_index_test() {
308        let value = json!("0-553-21311-3");
309        let _ = test(
310            template_json(),
311            "$..book[2].isbn",
312            vec![(&value, "$['store']['book'][2]['isbn']")],
313        );
314    }
315
316    #[test]
317    fn index_unit_index_test() {
318        let value = json!("0-553-21311-3");
319        let _ = test(
320            template_json(),
321            "$..book[2,4].isbn",
322            vec![(&value, "$['store']['book'][2]['isbn']")],
323        );
324        let value1 = json!("0-395-19395-8");
325        let _ = test(
326            template_json(),
327            "$..book[2,3].isbn",
328            vec![
329                (&value, "$['store']['book'][2]['isbn']"),
330                (&value1, "$['store']['book'][3]['isbn']"),
331            ],
332        );
333    }
334
335    #[test]
336    fn index_unit_keys_test() {
337        let js1 = json!("Moby Dick");
338        let js2 = json!(8.99);
339        let js3 = json!("The Lord of the Rings");
340        let js4 = json!(22.99);
341        let _ = test(
342            template_json(),
343            "$..book[2,3]['title','price']",
344            vec![
345                (&js1, "$['store']['book'][2]['title']"),
346                (&js3, "$['store']['book'][3]['title']"),
347                (&js2, "$['store']['book'][2]['price']"),
348                (&js4, "$['store']['book'][3]['price']"),
349            ],
350        );
351    }
352
353    #[test]
354    fn index_slice_test() -> Parsed<()> {
355        let i0 = "$['array'][0]";
356        let i1 = "$['array'][1]";
357        let i2 = "$['array'][2]";
358        let i3 = "$['array'][3]";
359        let i4 = "$['array'][4]";
360        let i5 = "$['array'][5]";
361        let i6 = "$['array'][6]";
362        let i7 = "$['array'][7]";
363        let i8 = "$['array'][8]";
364        let i9 = "$['array'][9]";
365
366        let j0 = json!(0);
367        let j1 = json!(1);
368        let j2 = json!(2);
369        let j3 = json!(3);
370        let j4 = json!(4);
371        let j5 = json!(5);
372        let j6 = json!(6);
373        let j7 = json!(7);
374        let j8 = json!(8);
375        let j9 = json!(9);
376        test(
377            template_json(),
378            "$.array[:]",
379            vec![
380                (&j0, i0),
381                (&j1, i1),
382                (&j2, i2),
383                (&j3, i3),
384                (&j4, i4),
385                (&j5, i5),
386                (&j6, i6),
387                (&j7, i7),
388                (&j8, i8),
389                (&j9, i9),
390            ],
391        )?;
392        test(
393            template_json(),
394            "$.array[1:4:2]",
395            vec![(&j1, i1), (&j3, i3)],
396        )?;
397        test(
398            template_json(),
399            "$.array[::3]",
400            vec![(&j0, i0), (&j3, i3), (&j6, i6), (&j9, i9)],
401        )?;
402        test(template_json(), "$.array[-1:]", vec![(&j9, i9)])?;
403        test(template_json(), "$.array[-2:-1]", vec![(&j8, i8)])?;
404
405        Ok(())
406    }
407
408    #[test]
409    fn index_filter_test() -> Parsed<()> {
410        let moby = json!("Moby Dick");
411        let rings = json!("The Lord of the Rings");
412        test(
413            template_json(),
414            "$..book[?@.isbn].title",
415            vec![
416                (&moby, "$['store']['book'][2]['title']"),
417                (&rings, "$['store']['book'][3]['title']"),
418            ],
419        )?;
420        let sword = json!("Sword of Honour");
421        test(
422            template_json(),
423            "$..book[?(@.price != 8.95)].title",
424            vec![
425                (&sword, "$['store']['book'][1]['title']"),
426                (&moby, "$['store']['book'][2]['title']"),
427                (&rings, "$['store']['book'][3]['title']"),
428            ],
429        )?;
430        let sayings = json!("Sayings of the Century");
431        test(
432            template_json(),
433            "$..book[?(@.price == 8.95)].title",
434            vec![(&sayings, "$['store']['book'][0]['title']")],
435        )?;
436
437        let js12 = json!(12.99);
438        let js899 = json!(8.99);
439        let js2299 = json!(22.99);
440        test(
441            template_json(),
442            "$..book[?@.price >= 8.99].price",
443            vec![
444                (&js12, "$['store']['book'][1]['price']"),
445                (&js899, "$['store']['book'][2]['price']"),
446                (&js2299, "$['store']['book'][3]['price']"),
447            ],
448        )?;
449
450        test(
451            template_json(),
452            "$..book[?(@.price >= $.expensive)].price",
453            vec![
454                (&js12, "$['store']['book'][1]['price']"),
455                (&js2299, "$['store']['book'][3]['price']"),
456            ],
457        )?;
458        Ok(())
459    }
460
461    #[test]
462    fn union_quotes() -> Queried<()> {
463        let json = json!({
464          "a": "ab",
465          "b": "bc"
466        });
467
468        let vec = js_path("$['a',\r'b']", &json)?;
469
470        assert_eq!(
471            vec,
472            vec![
473                (&json!("ab"), "$['a']".to_string()).into(),
474                (&json!("bc"), "$['b']".to_string()).into(),
475            ]
476        );
477
478        Ok(())
479    }
480
481    #[test]
482    fn space_between_selectors() -> Queried<()> {
483        let json = json!({
484          "a": {
485            "b": "ab"
486          }
487        });
488
489        let vec = js_path("$['a'] \r['b']", &json)?;
490
491        assert_eq!(vec, vec![(&json!("ab"), "$['a']['b']".to_string()).into(),]);
492
493        Ok(())
494    }
495    #[test]
496    fn space_in_search() -> Queried<()> {
497        let json = json!(["foo", "123"]);
498
499        let vec = js_path("$[?search(@\n,'[a-z]+')]", &json)?;
500
501        assert_eq!(vec, vec![(&json!("foo"), "$[0]".to_string()).into(),]);
502
503        Ok(())
504    }
505    #[test]
506    fn filter_key() -> Queried<()> {
507        let json = json!([
508          {
509            "a": "b",
510            "d": "e"
511          },
512          {
513            "a": 1,
514            "d": "f"
515          }
516        ]);
517
518        let vec = js_path("$[?@.a!=\"b\"]", &json)?;
519
520        assert_eq!(
521            vec,
522            vec![(&json!({"a":1, "d":"f"}), "$[1]".to_string()).into(),]
523        );
524
525        Ok(())
526    }
527
528    #[test]
529    fn regex_key() -> Queried<()> {
530        let json = json!({
531          "regex": "b.?b",
532          "values": [
533            "abc",
534            "bcd",
535            "bab",
536            "bba",
537            "bbab",
538            "b",
539            true,
540            [],
541            {}
542          ]
543        });
544
545        let vec = js_path("$.values[?match(@, $.regex)]", &json)?;
546
547        assert_eq!(
548            vec,
549            vec![(&json!("bab"), "$['values'][2]".to_string()).into(),]
550        );
551
552        Ok(())
553    }
554    #[test]
555    fn name_sel() -> Queried<()> {
556        let json = json!({
557          "/": "A"
558        });
559
560        let vec = js_path("$['\\/']", &json)?;
561
562        assert_eq!(vec, vec![(&json!("A"), "$['\\/']".to_string()).into(),]);
563
564        Ok(())
565    }
566    #[test]
567    fn unicode_fns() -> Queried<()> {
568        let json = json!(["ж", "Ж", "1", "жЖ", true, [], {}]);
569
570        let vec = js_path("$[?match(@, '\\\\p{Lu}')]", &json)?;
571
572        assert_eq!(vec, vec![(&json!("Ж"), "$[1]".to_string()).into(),]);
573
574        Ok(())
575    }
576    #[test]
577    fn fn_res_can_not_compare() -> Queried<()> {
578        let json = json!({});
579
580        let vec = js_path("$[?match(@.a, 'a.*')==true]", &json);
581
582        assert!(vec.is_err());
583
584        Ok(())
585    }
586    #[test]
587    fn too_small() -> Queried<()> {
588        let json = json!({});
589
590        let vec = js_path("$[-9007199254740992]", &json);
591
592        assert!(vec.is_err());
593
594        Ok(())
595    }
596    #[test]
597    fn filter_data() -> Queried<()> {
598        let json = json!({
599          "a": 1,
600          "b": 2,
601          "c": 3
602        });
603
604        let vec: Vec<String> = json.query_only_path("$[?@<3]")?.into_iter().collect();
605
606        assert_eq!(vec, vec!["$['a']".to_string(), "$['b']".to_string()]);
607
608        Ok(())
609    }
610    #[test]
611    fn exp_no_error() -> Queried<()> {
612        let json = json!([
613          {
614            "a": 100,
615            "d": "e"
616          },
617          {
618            "a": 100.1,
619            "d": "f"
620          },
621          {
622            "a": "100",
623            "d": "g"
624          }
625        ]);
626
627        let vec: Vec<&Value> = json.query("$[?@.a==1E2]")?;
628        assert_eq!(vec, vec![&json!({"a":100, "d":"e"})]);
629
630        Ok(())
631    }
632    #[test]
633    fn single_quote() -> Queried<()> {
634        let json = json!({
635          "a'": "A",
636          "b": "B"
637        });
638
639        let vec = js_path("$[\"a'\"]", &json)?;
640        assert_eq!(vec, vec![(&json!("A"), "$['\"a\'\"']".to_string()).into(),]);
641
642        Ok(())
643    }
644    #[test]
645    fn union() -> Queried<()> {
646        let json = json!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
647
648        let vec: Vec<QueryRef<Value>> = json.query_with_path("$[1,5:7]")?;
649        assert_eq!(
650            vec,
651            vec![
652                (&json!(1), "$[1]".to_string()).into(),
653                (&json!(5), "$[5]".to_string()).into(),
654                (&json!(6), "$[6]".to_string()).into(),
655            ]
656        );
657
658        Ok(())
659    }
660
661    #[test]
662    fn basic_descendent() -> Queried<()> {
663        let json = json!({
664          "o": [
665            0,
666            1,
667            [
668              2,
669              3
670            ]
671          ]
672        });
673
674        let vec = js_path("$..[1]", &json)?;
675        assert_eq!(
676            vec,
677            vec![
678                (&json!(1), "$['o'][1]".to_string()).into(),
679                (&json!(3), "$['o'][2][1]".to_string()).into(),
680            ]
681        );
682
683        Ok(())
684    }
685    #[test]
686    fn filter_absent() -> Queried<()> {
687        let json = json!([
688          {
689            "list": [
690              1
691            ]
692          }
693        ]);
694
695        let vec = js_path("$[?@.absent==@.list[9]]", &json)?;
696        assert_eq!(
697            vec,
698            vec![(&json!({"list": [1]}), "$[0]".to_string()).into(),]
699        );
700
701        Ok(())
702    }
703
704    #[test]
705    fn filter_star() -> Queried<()> {
706        let json = json!([1,[],[2],{},{"a": 3}]);
707
708        let vec = json.query_with_path("$[?@.*]")?;
709        assert_eq!(
710            vec,
711            vec![
712                (&json!([2]), "$[2]".to_string()).into(),
713                (&json!({"a": 3}), "$[4]".to_string()).into(),
714            ]
715        );
716
717        Ok(())
718    }
719
720    #[test]
721    fn space_test() -> Queried<()> {
722        let json = json!({ " ": "A"});
723
724        let vec = json.query_with_path("$[' ']")?;
725        assert_eq!(vec, vec![(&json!("A"), "$[\' \']".to_string()).into(),]);
726
727        Ok(())
728    }
729    #[test]
730    fn neg_idx() -> Queried<()> {
731        let json = json!(["first", "second"]);
732
733        let vec = json.query_with_path("$[-2]")?;
734        assert_eq!(vec, vec![(&json!("first"), "$[0]".to_string()).into(),]);
735
736        Ok(())
737    }
738
739    #[test]
740    fn filter_slice() -> Queried<()> {
741        let json = json!([
742          1,
743          [],
744          [
745            2
746          ],
747          [
748            2,
749            3,
750            4
751          ],
752          {},
753          {
754            "a": 3
755          }
756        ]);
757
758        let vec = json.query_with_path("$[?@[0:2]]")?;
759        assert_eq!(
760            vec,
761            vec![
762                (&json!([2]), "$[2]").into(),
763                (&json!([2, 3, 4]), "$[3]").into(),
764            ]
765        );
766
767        Ok(())
768    }
769
770    #[test]
771    fn surr_pairs() -> Queried<()> {
772        let json = json!({
773          "𝄞": "A"
774        });
775        let vec = json.query_with_path("$['𝄞']")?;
776        assert_eq!(vec, vec![(&json!("A"), "$['𝄞']".to_string()).into()]);
777
778        Ok(())
779    }
780    #[test]
781    fn tab_key() -> Queried<()> {
782        let json = json!({
783          "\\t": "A"
784        });
785        let vec = json.query_with_path("$['\\t']")?;
786        assert_eq!(vec, vec![(&json!("A"), "$['\\t']".to_string()).into()]);
787
788        Ok(())
789    }
790    #[test]
791    fn escaped_up_hex() -> Queried<()> {
792        let json = json!({
793          "☺": "A"
794        });
795        let vec = json.query_with_path("$['☺']")?;
796        assert_eq!(vec, vec![(&json!("A"), "$['☺']".to_string()).into()]);
797
798        Ok(())
799    }
800    #[test]
801    fn carr_return() -> Queried<()> {
802        let json = json!({
803          "\\r": "A"
804        });
805        let vec = json.query_with_path("$['\\r']")?;
806        assert_eq!(vec, vec![(&json!("A"), "$['\\r']".to_string()).into()]);
807
808        Ok(())
809    }
810}