mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 01:12:17 +00:00
array keys
This commit is contained in:
parent
74666d264e
commit
de97e2f95a
@ -215,6 +215,13 @@ mod parser_tests {
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$["a", 'b']"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Keys(vec!["a".to_string(), "b".to_string()]),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?(1>2)]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
|
@ -33,6 +33,7 @@ pub enum ParseToken {
|
||||
All,
|
||||
|
||||
Key(String),
|
||||
Keys(Vec<String>),
|
||||
// []
|
||||
Array,
|
||||
// 메타토큰
|
||||
@ -232,12 +233,39 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn array_quota_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quota_value");
|
||||
fn array_keys(tokenizer: &mut TokenReader, first_key: String) -> ParseResult<Node> {
|
||||
let mut keys = vec![first_key];
|
||||
while tokenizer.peek_is(COMMA) {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
if !(tokenizer.peek_is(SINGLE_QUOTE) || tokenizer.peek_is(DOUBLE_QUOTE)) {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val))
|
||||
| Ok(Token::DoubleQuoted(_, val)) => {
|
||||
keys.push(val);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
|
||||
Ok(Self::node(ParseToken::Keys(keys)))
|
||||
}
|
||||
|
||||
fn array_quote_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quote_value");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val))
|
||||
| Ok(Token::DoubleQuoted(_, val)) => {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
if !tokenizer.peek_is(COMMA) {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
} else {
|
||||
Self::array_keys(tokenizer, val)
|
||||
}
|
||||
}
|
||||
Err(TokenError::Eof) => {
|
||||
Ok(Self::node(ParseToken::Eof))
|
||||
@ -322,7 +350,7 @@ impl Parser {
|
||||
}
|
||||
Ok(Token::DoubleQuoted(_, _))
|
||||
| Ok(Token::SingleQuoted(_, _)) => {
|
||||
Self::array_quota_value(tokenizer)
|
||||
Self::array_quote_value(tokenizer)
|
||||
}
|
||||
Err(TokenError::Eof) => {
|
||||
Ok(Self::node(ParseToken::Eof))
|
||||
@ -602,8 +630,8 @@ impl Parser {
|
||||
return Self::json_path(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(DOUBLE_QUOTA) || tokenizer.peek_is(SINGLE_QUOTA) {
|
||||
return Self::array_quota_value(tokenizer);
|
||||
if tokenizer.peek_is(DOUBLE_QUOTE) || tokenizer.peek_is(SINGLE_QUOTE) {
|
||||
return Self::array_quote_value(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(KEY) {
|
||||
@ -694,6 +722,7 @@ pub trait NodeVisitor {
|
||||
| ParseToken::Relative
|
||||
| ParseToken::All
|
||||
| ParseToken::Key(_)
|
||||
| ParseToken::Keys(_)
|
||||
| ParseToken::Range(_, _, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_)
|
||||
|
@ -15,8 +15,8 @@ pub const SPLIT: &'static str = ":";
|
||||
pub const OPEN_PARENTHESIS: &'static str = "(";
|
||||
pub const CLOSE_PARENTHESIS: &'static str = ")";
|
||||
pub const KEY: &'static str = "Key";
|
||||
pub const DOUBLE_QUOTA: &'static str = "\"";
|
||||
pub const SINGLE_QUOTA: &'static str = "'";
|
||||
pub const DOUBLE_QUOTE: &'static str = "\"";
|
||||
pub const SINGLE_QUOTE: &'static str = "'";
|
||||
pub const EQUAL: &'static str = "==";
|
||||
pub const GREATER_OR_EQUAL: &'static str = ">=";
|
||||
pub const GREATER: &'static str = ">";
|
||||
@ -109,8 +109,8 @@ impl Token {
|
||||
Token::OpenParenthesis(_) => OPEN_PARENTHESIS,
|
||||
Token::CloseParenthesis(_) => CLOSE_PARENTHESIS,
|
||||
Token::Key(_, _) => KEY,
|
||||
Token::DoubleQuoted(_, _) => DOUBLE_QUOTA,
|
||||
Token::SingleQuoted(_, _) => SINGLE_QUOTA,
|
||||
Token::DoubleQuoted(_, _) => DOUBLE_QUOTE,
|
||||
Token::SingleQuoted(_, _) => SINGLE_QUOTE,
|
||||
Token::Equal(_) => EQUAL,
|
||||
Token::GreaterOrEqual(_) => GREATER_OR_EQUAL,
|
||||
Token::Greater(_) => GREATER,
|
||||
|
@ -693,20 +693,22 @@ impl<'a, 'b> Selector<'a, 'b> {
|
||||
debug!("next_from_current_with_num : {:?}, {:?}", &index, self.current);
|
||||
}
|
||||
|
||||
fn next_from_current_with_str(&mut self, key: &str) {
|
||||
fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, key: &str, visited: &mut HashSet<*const Value>) {
|
||||
fn next_from_current_with_str(&mut self, keys: &Vec<String>) {
|
||||
fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, keys: &Vec<String>, visited: &mut HashSet<*const Value>) {
|
||||
match v {
|
||||
Value::Object(map) => {
|
||||
if let Some(v) = map.get(key) {
|
||||
let ptr = v as *const Value;
|
||||
if !visited.contains(&ptr) {
|
||||
visited.insert(ptr);
|
||||
tmp.push(v)
|
||||
for key in keys {
|
||||
if let Some(v) = map.get(key) {
|
||||
let ptr = v as *const Value;
|
||||
if !visited.contains(&ptr) {
|
||||
visited.insert(ptr);
|
||||
tmp.push(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Array(vec) => for v in vec {
|
||||
_collect(v, tmp, key, visited);
|
||||
_collect(v, tmp, keys, visited);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -716,12 +718,12 @@ impl<'a, 'b> Selector<'a, 'b> {
|
||||
let mut tmp = Vec::new();
|
||||
let mut visited = HashSet::new();
|
||||
for c in current {
|
||||
_collect(c, &mut tmp, key, &mut visited);
|
||||
_collect(c, &mut tmp, keys, &mut visited);
|
||||
}
|
||||
self.current = Some(tmp);
|
||||
}
|
||||
|
||||
debug!("next_from_current_with_str : {}, {:?}", key, self.current);
|
||||
debug!("next_from_current_with_str : {:?}, {:?}", keys, self.current);
|
||||
}
|
||||
|
||||
fn next_all_from_current(&mut self) {
|
||||
@ -838,7 +840,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
self.next_from_current_with_num(to_f64(&n));
|
||||
}
|
||||
ExprTerm::String(key) => {
|
||||
self.next_from_current_with_str(&key);
|
||||
self.next_from_current_with_str(&vec![key]);
|
||||
}
|
||||
ExprTerm::Json(_, v) => {
|
||||
if v.is_empty() {
|
||||
@ -886,7 +888,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
self.all_from_current_with_str(key.as_str())
|
||||
}
|
||||
ParseToken::In => {
|
||||
self.next_from_current_with_str(key.as_str())
|
||||
self.next_from_current_with_str(&vec![key.clone()])
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -905,6 +907,17 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ParseToken::Keys(keys) => {
|
||||
if !self.terms.is_empty() {
|
||||
unimplemented!("keys in filter");
|
||||
}
|
||||
|
||||
if let Some(ParseToken::Array) = self.tokens.pop() {
|
||||
self.next_from_current_with_str(keys);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
ParseToken::Number(v) => {
|
||||
self.terms.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ fn array() {
|
||||
select_and_then_compare("$['school']['friends'][0].['name']", read_json("./benches/data_obj.json"), json!([
|
||||
"Millicent Norman"
|
||||
]));
|
||||
|
||||
select_and_then_compare(r#"$.["eyeColor", "name"]"#, read_json("./benches/data_obj.json"), json!([
|
||||
"blue", "Leonor Herman"
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
x
Reference in New Issue
Block a user