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