jsonpath_rust/query/
segment.rs

1use crate::parser::model::{Segment, Selector};
2use crate::query::queryable::Queryable;
3use crate::query::state::{Data, Pointer, State};
4use crate::query::Query;
5
6impl Query for Segment {
7    fn process<'a, T: Queryable>(&self, step: State<'a, T>) -> State<'a, T> {
8        match self {
9            Segment::Descendant(segment) => segment.process(step.flat_map(process_descendant)),
10            Segment::Selector(selector) => selector.process(step),
11            Segment::Selectors(selectors) => process_selectors(step, selectors),
12        }
13    }
14}
15
16fn process_selectors<'a, T: Queryable>(
17    step: State<'a, T>,
18    selectors: &Vec<Selector>,
19) -> State<'a, T> {
20    selectors
21        .into_iter()
22        .map(|s| s.process(step.clone()))
23        .reduce(State::reduce)
24        .unwrap_or(step.root.into())
25}
26
27fn process_descendant<T: Queryable>(data: Pointer<T>) -> Data<T> {
28    if let Some(array) = data.inner.as_array() {
29        Data::Ref(data.clone()).reduce(
30            Data::new_refs(
31                array
32                    .iter()
33                    .enumerate()
34                    .map(|(i, elem)| Pointer::idx(elem, data.path.clone(), i))
35                    .collect(),
36            )
37            .flat_map(process_descendant),
38        )
39    } else if let Some(object) = data.inner.as_object() {
40        Data::Ref(data.clone()).reduce(
41            Data::new_refs(
42                object
43                    .into_iter()
44                    .map(|(key, value)| Pointer::key(value, data.path.clone(), key))
45                    .collect(),
46            )
47            .flat_map(process_descendant),
48        )
49    } else {
50        Data::Nothing
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use crate::parser::model::{Segment, Selector};
57    use crate::query::state::{Pointer, State};
58    use crate::query::Query;
59    use serde_json::json;
60
61    #[test]
62    fn test_process_selectors() {
63        let value = json!({"firstName": "John", "lastName" : "doe",});
64        let segment = Segment::Selectors(vec![
65            Selector::Name("firstName".to_string()),
66            Selector::Name("lastName".to_string()),
67        ]);
68        let step = segment.process(State::root(&value));
69
70        assert_eq!(
71            step.ok_ref(),
72            Some(vec![
73                Pointer::new(&json!("John"), "$['firstName']".to_string()),
74                Pointer::new(&json!("doe"), "$['lastName']".to_string())
75            ])
76        );
77    }
78
79    #[test]
80    fn test_process_descendant() {
81        let value = json!([{"name": "John"}, {"name": "doe"}]);
82        let segment = Segment::Descendant(Box::new(Segment::Selector(Selector::Wildcard)));
83        let step = segment.process(State::root(&value));
84
85        assert_eq!(
86            step.ok_ref(),
87            Some(vec![
88                Pointer::new(&json!({"name": "John"}), "$[0]".to_string()),
89                Pointer::new(&json!({"name": "doe"}), "$[1]".to_string()),
90                Pointer::new(&json!("John"), "$[0]['name']".to_string()),
91                Pointer::new(&json!("doe"), "$[1]['name']".to_string()),
92            ])
93        );
94    }
95
96    #[test]
97    fn test_process_descendant2() {
98        let value = json!({"o": [0,1,[2,3]]});
99        let segment = Segment::Descendant(Box::new(Segment::Selector(Selector::Index(1))));
100        let step = segment.process(State::root(&value));
101
102        assert_eq!(
103            step.ok_ref(),
104            Some(vec![
105                Pointer::new(&json!(1), "$['o'][1]".to_string()),
106                Pointer::new(&json!(3), "$['o'][2][1]".to_string()),
107            ])
108        );
109    }
110}