diff --git a/src/select/mod.rs b/src/select/mod.rs index 34f73fc..ca2fc4d 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -196,7 +196,7 @@ enum ExprTerm<'a> { String(String), Number(Number), Bool(bool), - Json(Option, Vec<&'a Value>), + Json(Option>, Option, Vec<&'a Value>), } impl<'a> ExprTerm<'a> { @@ -209,20 +209,20 @@ impl<'a> ExprTerm<'a> { match &self { ExprTerm::String(s1) => match &other { ExprTerm::String(s2) => ExprTerm::Bool(cmp_fn.cmp_string(s1, s2)), - ExprTerm::Json(_, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), + ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), _ => ExprTerm::Bool(cmp_fn.default()), }, ExprTerm::Number(n1) => match &other { ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(to_f64(n1), to_f64(n2))), - ExprTerm::Json(_, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), + ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), _ => ExprTerm::Bool(cmp_fn.default()), }, ExprTerm::Bool(b1) => match &other { ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(*b1, *b2)), - ExprTerm::Json(_, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), + ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn), _ => ExprTerm::Bool(cmp_fn.default()), }, - ExprTerm::Json(fk1, vec1) => { + ExprTerm::Json(rel, fk1, vec1) => { let ret: Vec<&Value> = match &other { ExprTerm::String(s2) => vec1 .iter() @@ -272,13 +272,15 @@ impl<'a> ExprTerm<'a> { }) .cloned() .collect(), - ExprTerm::Json(_, vec2) => cmp_fn.cmp_json(vec1, vec2), + ExprTerm::Json(_, _, vec2) => cmp_fn.cmp_json(vec1, vec2), }; if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) + } else if let Some(rel) = rel { + ExprTerm::Json(Some(rel.to_vec()), None, ret) } else { - ExprTerm::Json(None, ret) + ExprTerm::Json(None, None, ret) } } } @@ -360,7 +362,7 @@ impl<'a> Into> for &Vec<&'a Value> { } } - ExprTerm::Json(None, self.to_vec()) + ExprTerm::Json(None, None, self.to_vec()) } } @@ -584,10 +586,27 @@ impl<'a, 'b> Selector<'a, 'b> { debug!("in_filter 1.: {:?}", v); match v { - ExprTerm::Json(_, vec) => { + ExprTerm::Json(rel, fk, vec) => { let mut tmp = Vec::new(); - let filter_key = fun(&vec, &mut tmp); - self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); + let filter_key = if let Some(FilterKey::String(key)) = fk { + fun( + &vec.iter() + .map(|v| match v { + Value::Object(map) if map.contains_key(&key) => { + map.get(&key).unwrap() + } + _ => v, + }) + .collect(), + &mut tmp, + ) + } else { + fun(&vec, &mut tmp) + }; + + let parent = if rel.is_some() { rel } else { Some(vec) }; + self.terms + .push(Some(ExprTerm::Json(parent, Some(filter_key), tmp))); } _ => unreachable!(), }; @@ -598,7 +617,8 @@ impl<'a, 'b> Selector<'a, 'b> { if let Some(current) = &self.current { let mut tmp = Vec::new(); let filter_key = fun(current, &mut tmp); - self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); + self.terms + .push(Some(ExprTerm::Json(None, Some(filter_key), tmp))); } } } @@ -803,9 +823,11 @@ impl<'a, 'b> Selector<'a, 'b> { ExprTerm::String(key) => { self.next_from_current_with_str(&[key]); } - ExprTerm::Json(_, v) => { + ExprTerm::Json(rel, _, v) => { if v.is_empty() { self.current = Some(vec![&Value::Null]); + } else if let Some(vec) = rel { + self.current = Some(vec); } else { self.current = Some(v); } @@ -883,6 +905,7 @@ impl<'a, 'b> Selector<'a, 'b> { let right = match self.terms.pop() { Some(Some(right)) => right, Some(None) => ExprTerm::Json( + None, None, match &self.current { Some(current) => current.to_vec(), @@ -895,6 +918,7 @@ impl<'a, 'b> Selector<'a, 'b> { let left = match self.terms.pop() { Some(Some(left)) => left, Some(None) => ExprTerm::Json( + None, None, match &self.current { Some(current) => current.to_vec(), @@ -1027,7 +1051,11 @@ pub struct SelectorMut { value: Option, } -fn replace_value Option>(mut tokens: Vec, value: &mut Value, fun: &mut F) { +fn replace_value Option>( + mut tokens: Vec, + value: &mut Value, + fun: &mut F, +) { let mut target = value; let last_index = tokens.len() - 1; diff --git a/tests/filter.rs b/tests/filter.rs index 112cfd3..c73aa05 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -663,3 +663,43 @@ fn all_filter() { ); } } + +#[test] +fn current_path() { + setup(); + select_and_then_compare( + "$.a[?(@.b.c == 1)]", + json!({ + "a": { + "b": { + "c": 1 + } + } + }), + json!([ + { + "b" : { + "c" : 1 + } + } + ]), + ); + + select_and_then_compare( + "$.a[?(@.b.c)]", + json!({ + "a": { + "b": { + "c": 1 + } + } + }), + json!([ + { + "b" : { + "c" : 1 + } + } + ]), + ); +} \ No newline at end of file