Skip to main content

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