1 | use crate::parser::model::FilterAtom;
|
2 | use crate::query::queryable::Queryable;
|
3 | use crate::query::state::{Data, State};
|
4 | use crate::query::Query;
|
5 |
|
6 | impl 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 |
|
58 | fn invert_bool<T: Queryable>(state: State<T>) -> State<T> {
|
59 | let root: &T = state.root;
|
60 | State::bool(
|
61 | !state.ok_val().and_then(|v: T| v.as_bool()).unwrap_or_default(),
|
62 | root,
|
63 | )
|
64 | }
|
65 |
|
66 | #[cfg (test)]
|
67 | mod 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 | }
|
123 | |