| 1 | use crate::parser::model::Filter; | 
| 2 | use crate::query::queryable::Queryable; | 
|---|
| 3 | use crate::query::state::{Data, Pointer, State}; | 
|---|
| 4 | use crate::query::Query; | 
|---|
| 5 |  | 
|---|
| 6 | impl 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 |  | 
|---|
| 36 | impl Filter { | 
|---|
| 37 | fn process_elem<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> { | 
|---|
| 38 | let process_cond: impl Fn(&Filter) -> bool = |filter: &Filter| { | 
|---|
| 39 | filterOption | 
|---|
| 40 | .process(state.clone()) | 
|---|
| 41 | .ok_val() | 
|---|
| 42 | .and_then(|v: T| v.as_bool()) | 
|---|
| 43 | .unwrap_or_default() | 
|---|
| 44 | }; | 
|---|
| 45 | match self { | 
|---|
| 46 | Filter::Or(ors: &Vec) => State::bool(b:ors.iter().any(process_cond), state.root), | 
|---|
| 47 | Filter::And(ands: &Vec) => State::bool(b:ands.iter().all(process_cond), state.root), | 
|---|
| 48 | Filter::Atom(atom: &FilterAtom) => 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: T| v.as_bool()) | 
|---|
| 56 | .unwrap_or_default() | 
|---|
| 57 | } | 
|---|
| 58 | } | 
|---|
| 59 |  | 
|---|
| 60 | #[ cfg(test)] | 
|---|
| 61 | mod 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 | } | 
|---|
| 126 |  | 
|---|