jsonpath_rust/query/
filter.rs

1use crate::parser::model::Filter;
2use crate::query::queryable::Queryable;
3use crate::query::state::{Data, Pointer, State};
4use crate::query::Query;
5
6impl Query for Filter {
7    fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> {
8        let root = state.root;
9        state.flat_map(|p| {
10            if p.is_internal() {
11                Data::Value(self.filter_item(p, root).into())
12            } else if let Some(items) = p.inner.as_array() {
13                Data::Refs(
14                    items
15                        .into_iter()
16                        .enumerate()
17                        .filter(|(_, item)| self.filter_item(Pointer::empty(*item), root))
18                        .map(|(idx, item)| Pointer::idx(item, p.path.clone(), idx))
19                        .collect(),
20                )
21            } else if let Some(items) = p.inner.as_object() {
22                Data::Refs(
23                    items
24                        .into_iter()
25                        .filter(|(_, item)| self.filter_item(Pointer::empty(*item), root))
26                        .map(|(key, item)| Pointer::key(item, p.path.clone(), key))
27                        .collect(),
28                )
29            } else {
30                return Data::Nothing;
31            }
32        })
33    }
34}
35
36impl Filter {
37    fn process_elem<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> {
38        let process_cond = |filter: &Filter| {
39            filter
40                .process(state.clone())
41                .ok_val()
42                .and_then(|v| v.as_bool())
43                .unwrap_or_default()
44        };
45        match self {
46            Filter::Or(ors) => State::bool(ors.iter().any(process_cond), state.root),
47            Filter::And(ands) => State::bool(ands.iter().all(process_cond), state.root),
48            Filter::Atom(atom) => atom.process(state),
49        }
50    }
51
52    fn filter_item<'a, T: Queryable>(&self, item: Pointer<'a, T>, root: &T) -> bool {
53        self.process_elem(State::data(root, Data::Ref(item.clone())))
54            .ok_val()
55            .and_then(|v| v.as_bool())
56            .unwrap_or_default()
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::query::js_path;
63    use serde_json::json;
64
65    #[test]
66    fn smoke_ok() {
67        let json = json!({"a" : [1,2,3]});
68
69        assert_eq!(
70            js_path("$.a[? @ > 1]", &json),
71            Ok(vec![
72                (&json!(2), "$['a'][1]".to_string()).into(),
73                (&json!(3), "$['a'][2]".to_string()).into(),
74            ])
75        );
76    }
77
78    #[test]
79    fn existence() {
80        let json = json!({
81          "a": {
82            "a":{"b":1},
83            "c": {
84              "b": 2
85            },
86            "d": {
87              "b1": 3
88            }
89          }
90        });
91        assert_eq!(
92            js_path("$.a[?@.b]", &json),
93            Ok(vec![
94                (&json!({"b":1}), "$['a']['a']".to_string()).into(),
95                (&json!({"b":2}), "$['a']['c']".to_string()).into(),
96            ])
97        );
98    }
99
100    #[test]
101    fn existence_or() {
102        let json = json!({
103          "a": {
104            "a":{"b":1},
105            "c": {
106              "b": 2
107            },
108            "d": {
109              "b1": 3
110            },
111            "e": {
112              "b2": 3
113            }
114          }
115        });
116        assert_eq!(
117            js_path("$.a[?@.b || @.b1]", &json),
118            Ok(vec![
119                (&json!({"b":1}), "$['a']['a']".to_string()).into(),
120                (&json!({"b":2}), "$['a']['c']".to_string()).into(),
121                (&json!({"b1":3}), "$['a']['d']".to_string()).into(),
122            ])
123        );
124    }
125}