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