diff --git a/src/select/mod.rs b/src/select/mod.rs index 1d297e2..d643a01 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -2,8 +2,8 @@ use std::collections::HashSet; use std::fmt; use array_tool::vec::{Intersect, Union}; -use serde_json::map::Entry; use serde_json::{Number, Value}; +use serde_json::map::Entry; use parser::*; @@ -390,6 +390,18 @@ impl<'a> Into> for &Vec<&'a Value> { } } +fn walk_all_with_num<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) { + walk(vec, tmp, &|v| if v.is_array() { + if let Some(item) = v.get(index as usize) { + Some(vec![item]) + } else { + None + } + } else { + None + }); +} + fn walk_all_with_str<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { if is_filter { walk(vec, tmp, &|v| match v { @@ -833,6 +845,16 @@ impl<'a, 'b> Selector<'a, 'b> { debug!("all_from_current_with_str: {}, {:?}", key, self.current); } + fn all_from_current_with_num(&mut self, index: f64) { + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + + walk_all_with_num(¤t, &mut tmp, index); + self.current = Some(tmp); + } + debug!("all_from_current_with_num: {}, {:?}", index, self.current); + } + fn compute_absolute_path_filter(&mut self, token: &ParseToken) -> bool { if !self.selectors.is_empty() { match token { @@ -895,7 +917,7 @@ impl<'a, 'b> Selector<'a, 'b> { } fn visit_array_eof(&mut self) { - if self.is_nested_array() { + if self.is_last_before_token_match(ParseToken::Array) { if let Some(Some(e)) = self.terms.pop() { if let ExprTerm::String(key) = e { self.next_in_filter_with_str(&key); @@ -907,6 +929,20 @@ impl<'a, 'b> Selector<'a, 'b> { } } + if self.is_last_before_token_match(ParseToken::Leaves) { + self.tokens.pop(); + self.tokens.pop(); + if let Some(Some(e)) = self.terms.pop() { + if let ExprTerm::Number(n) = &e { + self.all_from_current_with_num(to_f64(n)); + self.terms.pop(); + return; + } + + self.terms.push(Some(e)); + } + } + if let Some(Some(e)) = self.terms.pop() { match e { ExprTerm::Number(n) => { @@ -934,6 +970,14 @@ impl<'a, 'b> Selector<'a, 'b> { self.tokens.pop(); } + fn is_last_before_token_match(&mut self, token: ParseToken) -> bool { + if self.tokens.len() > 1 { + return &token == &self.tokens[self.tokens.len() - 2]; + } + + return false; + } + fn visit_all(&mut self) { if let Some(ParseToken::Array) = self.tokens.last() { self.tokens.pop(); @@ -954,21 +998,6 @@ impl<'a, 'b> Selector<'a, 'b> { } } - fn is_nested_array(&mut self) -> bool { - let mut is_nested_array = false; - - if let Some(t) = self.tokens.pop() { - if let ParseToken::Array = t { - if let Some(ParseToken::Array) = self.tokens.last() { - is_nested_array = true; - } - } - self.tokens.push(t); - } - - is_nested_array - } - fn visit_key(&mut self, key: &str) { if let Some(ParseToken::Array) = self.tokens.last() { self.terms.push(Some(ExprTerm::String(key.to_string()))); diff --git a/tests/array_filter.rs b/tests/array_filter.rs index 707336e..9ffa79e 100644 --- a/tests/array_filter.rs +++ b/tests/array_filter.rs @@ -216,3 +216,38 @@ fn array_multiple_key() { json!(["blue", "Leonor Herman"]), ); } + +#[test] +fn bugs40_bracket_notation_after_recursive_descent() { + setup(); + + select_and_then_compare( + "$..[0]", + json!([ + "first", + { + "key": [ + "first nested", + { + "more": [ + {"nested": ["deepest", "second"]}, + ["more", "values"] + ] + } + ] + } + ]), + json!([ + "first", + "first nested", + { + "nested" : [ + "deepest", + "second" + ] + }, + "deepest", + "more" + ]), + ); +} \ No newline at end of file