jsonpath_rust/query/
atom.rs

1use crate::parser::model::FilterAtom;
2use crate::query::queryable::Queryable;
3use crate::query::state::{Data, State};
4use crate::query::Query;
5
6impl Query for FilterAtom {
7    fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> {
8        match self {
9            FilterAtom::Filter { expr, not } => {
10                let bool_res = expr.process(state);
11                if *not {
12                    invert_bool(bool_res)
13                } else {
14                    bool_res
15                }
16            }
17            FilterAtom::Test { expr, not } => {
18                let new_state = |b| State::bool(b, state.root);
19                let res = expr.process(state.clone());
20                if expr.is_res_bool() {
21                    if *not {
22                        invert_bool(res)
23                    } else {
24                        res
25                    }
26                } else {
27                    let struct_check = |s: &T| {
28                        if let Some(arr) = s.as_array() {
29                            !arr.is_empty()
30                        } else if let Some(obj) = s.as_object() {
31                            !obj.is_empty()
32                        } else if let Some(str) = s.as_str() {
33                            !str.is_empty()
34                        } else {
35                            true
36                        }
37                    };
38
39                    let struct_presented = match res.data {
40                        Data::Ref(v) => struct_check(v.inner),
41                        Data::Refs(e) if e.is_empty() => false,
42                        Data::Refs(elems) => elems.iter().map(|v| v.inner).all(struct_check),
43                        _ => false,
44                    };
45
46                    if struct_presented {
47                        new_state(!*not)
48                    } else {
49                        new_state(*not)
50                    }
51                }
52            }
53            FilterAtom::Comparison(cmp) => cmp.process(state),
54        }
55    }
56}
57
58fn invert_bool<T: Queryable>(state: State<T>) -> State<T> {
59    let root = state.root;
60    State::bool(
61        !state.ok_val().and_then(|v| v.as_bool()).unwrap_or_default(),
62        root,
63    )
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::parser::model::Comparable;
69    use crate::parser::model::Literal;
70    use crate::parser::model::SingularQuery;
71    use crate::parser::model::SingularQuerySegment;
72    use crate::parser::model::{Comparison, FilterAtom};
73    use crate::q_segment;
74    use crate::query::queryable::Queryable;
75    use crate::query::state::State;
76    use crate::query::Query;
77    use crate::{atom, comparable, lit};
78    use crate::{cmp, singular_query};
79    use crate::{filter_, q_segments};
80    use serde_json::json;
81
82    #[test]
83    fn test_comparison() {
84        let json = json!({"i": 1});
85        let atom = atom!(comparable!(lit!(i 1)), ">=", comparable!(lit!(i 1)));
86        let state = State::root(&json);
87        let res = atom.process(state);
88        assert_eq!(res.ok_val().and_then(|v| v.as_bool()), Some(true));
89    }
90
91    #[test]
92    fn test_not_filter_atom() {
93        let json = json!({"a": 1 , "b": 2});
94        let state = State::root(&json);
95
96        let f1 = filter_!(atom!(
97            comparable!(> SingularQuery::Current(vec![])),
98            ">",
99            comparable!(lit!(i 2))
100        ));
101        let f2 = filter_!(atom!(
102            comparable!(> singular_query!(b)),
103            "!=",
104            comparable!(> singular_query!(a))
105        ));
106
107        let atom_or = atom!(!filter_!(or f1.clone(), f2.clone()));
108        let atom_and = atom!(!filter_!(and f1, f2));
109
110        assert_eq!(
111            atom_or
112                .process(state.clone())
113                .ok_val()
114                .and_then(|v| v.as_bool()),
115            Some(true)
116        );
117        assert_eq!(
118            atom_and.process(state).ok_val().and_then(|v| v.as_bool()),
119            Some(true)
120        );
121    }
122}