mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-26 18:02:14 +00:00
support iterator
This commit is contained in:
parent
f919a5305b
commit
538b433ae2
16
src/lib.rs
16
src/lib.rs
@ -305,6 +305,18 @@ pub fn select<'a>(json: &'a Value, path: &str) -> Result<Vec<&'a Value>, JsonPat
|
|||||||
Selector::default().str_path(path)?.value(json).select()
|
Selector::default().str_path(path)?.value(json).select()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn select_with_iter<'a>(
|
||||||
|
json: impl ExactSizeIterator<Item = &'a Value> + 'a,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<(Vec<&'a Value>, Vec<usize>), JsonPathError> {
|
||||||
|
let mut selector = Selector::default();
|
||||||
|
let json = selector.str_path(path)?.values_iter(json).select()?;
|
||||||
|
|
||||||
|
let chose_indices = selector.chose_indices();
|
||||||
|
|
||||||
|
Ok((json, chose_indices))
|
||||||
|
}
|
||||||
|
|
||||||
/// It is the same to `select` function but it return the result as string.
|
/// It is the same to `select` function but it return the result as string.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -377,7 +389,9 @@ pub fn select_as<T: serde::de::DeserializeOwned>(
|
|||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<Vec<T>, JsonPathError> {
|
) -> Result<Vec<T>, JsonPathError> {
|
||||||
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
||||||
Selector::default().str_path(path)?.value(&json).select_as()
|
let t = Selector::default().str_path(path)?.value(&json).select_as();
|
||||||
|
|
||||||
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete(= replace with null) the JSON property using the jsonpath.
|
/// Delete(= replace with null) the JSON property using the jsonpath.
|
||||||
|
@ -543,21 +543,15 @@ impl Parser {
|
|||||||
_ => Self::paths(node, tokenizer),
|
_ => Self::paths(node, tokenizer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Token::Absolute(_)) => {
|
Ok(Token::Absolute(_)) => Self::json_path(tokenizer),
|
||||||
Self::json_path(tokenizer)
|
|
||||||
},
|
|
||||||
Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => {
|
Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => {
|
||||||
Self::array_quote_value(tokenizer)
|
Self::array_quote_value(tokenizer)
|
||||||
},
|
}
|
||||||
Ok(Token::Key(_, key)) => {
|
Ok(Token::Key(_, key)) => match key.as_bytes()[0] {
|
||||||
match key.as_bytes()[0] {
|
|
||||||
b'-' | b'0'..=b'9' => Self::term_num(tokenizer),
|
b'-' | b'0'..=b'9' => Self::term_num(tokenizer),
|
||||||
_ => Self::boolean(tokenizer),
|
_ => Self::boolean(tokenizer),
|
||||||
}
|
},
|
||||||
}
|
_ => Err(tokenizer.err_msg()),
|
||||||
_ => {
|
|
||||||
Err(tokenizer.err_msg())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,95 +66,95 @@ impl Token {
|
|||||||
match self {
|
match self {
|
||||||
Token::Absolute(_) => match other {
|
Token::Absolute(_) => match other {
|
||||||
Token::Absolute(_) => true,
|
Token::Absolute(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Dot(_) => match other {
|
Token::Dot(_) => match other {
|
||||||
Token::Dot(_) => true,
|
Token::Dot(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::At(_) => match other {
|
Token::At(_) => match other {
|
||||||
Token::At(_) => true,
|
Token::At(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::OpenArray(_) => match other {
|
Token::OpenArray(_) => match other {
|
||||||
Token::OpenArray(_) => true,
|
Token::OpenArray(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::CloseArray(_) => match other {
|
Token::CloseArray(_) => match other {
|
||||||
Token::CloseArray(_) => true,
|
Token::CloseArray(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Asterisk(_) => match other {
|
Token::Asterisk(_) => match other {
|
||||||
Token::Asterisk(_) => true,
|
Token::Asterisk(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Question(_) => match other {
|
Token::Question(_) => match other {
|
||||||
Token::Question(_) => true,
|
Token::Question(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Comma(_) => match other {
|
Token::Comma(_) => match other {
|
||||||
Token::Comma(_) => true,
|
Token::Comma(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Split(_) => match other {
|
Token::Split(_) => match other {
|
||||||
Token::Split(_) => true,
|
Token::Split(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::OpenParenthesis(_) => match other {
|
Token::OpenParenthesis(_) => match other {
|
||||||
Token::OpenParenthesis(_) => true,
|
Token::OpenParenthesis(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::CloseParenthesis(_) => match other {
|
Token::CloseParenthesis(_) => match other {
|
||||||
Token::CloseParenthesis(_) => true,
|
Token::CloseParenthesis(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Key(_, _) => match other {
|
Token::Key(_, _) => match other {
|
||||||
Token::Key(_, _) => true,
|
Token::Key(_, _) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::DoubleQuoted(_, _) => match other {
|
Token::DoubleQuoted(_, _) => match other {
|
||||||
Token::DoubleQuoted(_, _) => true,
|
Token::DoubleQuoted(_, _) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::SingleQuoted(_, _) => match other {
|
Token::SingleQuoted(_, _) => match other {
|
||||||
Token::SingleQuoted(_, _) => true,
|
Token::SingleQuoted(_, _) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Equal(_) => match other {
|
Token::Equal(_) => match other {
|
||||||
Token::Equal(_) => true,
|
Token::Equal(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::GreaterOrEqual(_) => match other {
|
Token::GreaterOrEqual(_) => match other {
|
||||||
Token::GreaterOrEqual(_) => true,
|
Token::GreaterOrEqual(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Greater(_) => match other {
|
Token::Greater(_) => match other {
|
||||||
Token::Greater(_) => true,
|
Token::Greater(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Little(_) => match other {
|
Token::Little(_) => match other {
|
||||||
Token::Little(_) => true,
|
Token::Little(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::LittleOrEqual(_) => match other {
|
Token::LittleOrEqual(_) => match other {
|
||||||
Token::LittleOrEqual(_) => true,
|
Token::LittleOrEqual(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::NotEqual(_) => match other {
|
Token::NotEqual(_) => match other {
|
||||||
Token::NotEqual(_) => true,
|
Token::NotEqual(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::And(_) => match other {
|
Token::And(_) => match other {
|
||||||
Token::And(_) => true,
|
Token::And(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Or(_) => match other {
|
Token::Or(_) => match other {
|
||||||
Token::Or(_) => true,
|
Token::Or(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
Token::Whitespace(_, _) => match other {
|
Token::Whitespace(_, _) => match other {
|
||||||
Token::Whitespace(_, _) => true,
|
Token::Whitespace(_, _) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,23 +174,9 @@ impl<'a> Tokenizer<'a> {
|
|||||||
|
|
||||||
fn dolla(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
fn dolla(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||||
let fun = |c: &char| match c {
|
let fun = |c: &char| match c {
|
||||||
&CH_DOT
|
&CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN | &CH_RPAREN | &CH_AT
|
||||||
| &CH_ASTERISK
|
| &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE | &CH_GREATER | &CH_EQUAL
|
||||||
| &CH_LARRAY
|
| &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false,
|
||||||
| &CH_RARRAY
|
|
||||||
| &CH_LPAREN
|
|
||||||
| &CH_RPAREN
|
|
||||||
| &CH_AT
|
|
||||||
| &CH_QUESTION
|
|
||||||
| &CH_COMMA
|
|
||||||
| &CH_SEMICOLON
|
|
||||||
| &CH_LITTLE
|
|
||||||
| &CH_GREATER
|
|
||||||
| &CH_EQUAL
|
|
||||||
| &CH_AMPERSAND
|
|
||||||
| &CH_PIPE
|
|
||||||
| &CH_EXCLAMATION
|
|
||||||
=> false,
|
|
||||||
_ => !c.is_whitespace(),
|
_ => !c.is_whitespace(),
|
||||||
};
|
};
|
||||||
let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?;
|
let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?;
|
||||||
@ -312,24 +298,9 @@ impl<'a> Tokenizer<'a> {
|
|||||||
|
|
||||||
fn other(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
fn other(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||||
let fun = |c: &char| match c {
|
let fun = |c: &char| match c {
|
||||||
&CH_DOLLA
|
&CH_DOLLA | &CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN
|
||||||
| &CH_DOT
|
| &CH_RPAREN | &CH_AT | &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE
|
||||||
| &CH_ASTERISK
|
| &CH_GREATER | &CH_EQUAL | &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false,
|
||||||
| &CH_LARRAY
|
|
||||||
| &CH_RARRAY
|
|
||||||
| &CH_LPAREN
|
|
||||||
| &CH_RPAREN
|
|
||||||
| &CH_AT
|
|
||||||
| &CH_QUESTION
|
|
||||||
| &CH_COMMA
|
|
||||||
| &CH_SEMICOLON
|
|
||||||
| &CH_LITTLE
|
|
||||||
| &CH_GREATER
|
|
||||||
| &CH_EQUAL
|
|
||||||
| &CH_AMPERSAND
|
|
||||||
| &CH_PIPE
|
|
||||||
| &CH_EXCLAMATION
|
|
||||||
=> false,
|
|
||||||
_ => !c.is_whitespace(),
|
_ => !c.is_whitespace(),
|
||||||
};
|
};
|
||||||
let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?;
|
let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?;
|
||||||
|
@ -175,7 +175,6 @@ impl Cmp for CmpOr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod cmp_inner_tests {
|
mod cmp_inner_tests {
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use serde_json::{Number, Value};
|
|
||||||
use select::cmp::*;
|
use select::cmp::*;
|
||||||
use select::{FilterKey, to_f64};
|
use select::{to_f64, FilterKey};
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
|
||||||
|
// Parsed form of a json path.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(super) enum ExprTerm<'a> {
|
pub(super) enum ExprTerm<'a> {
|
||||||
String(String),
|
String(String),
|
||||||
@ -11,6 +12,7 @@ pub(super) enum ExprTerm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExprTerm<'a> {
|
impl<'a> ExprTerm<'a> {
|
||||||
|
// tries to match current json path with provided
|
||||||
fn cmp<C1: Cmp, C2: Cmp>(
|
fn cmp<C1: Cmp, C2: Cmp>(
|
||||||
&self,
|
&self,
|
||||||
other: &Self,
|
other: &Self,
|
||||||
@ -201,11 +203,10 @@ impl<'a> Into<ExprTerm<'a>> for &Vec<&'a Value> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod expr_term_inner_tests {
|
mod expr_term_inner_tests {
|
||||||
use serde_json::{Number, Value};
|
|
||||||
use select::expr_term::ExprTerm;
|
use select::expr_term::ExprTerm;
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn value_vec_into() {
|
fn value_vec_into() {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use serde_json::{Number, Value};
|
|
||||||
use serde_json::map::Entry;
|
use serde_json::map::Entry;
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
|
||||||
use parser::*;
|
use parser::*;
|
||||||
|
|
||||||
use self::expr_term::*;
|
use self::expr_term::*;
|
||||||
use self::value_walker::ValueWalker;
|
use self::value_walker::JValueWalker;
|
||||||
|
|
||||||
mod cmp;
|
mod cmp;
|
||||||
mod expr_term;
|
mod expr_term;
|
||||||
@ -83,7 +83,9 @@ impl<'a> FilterTerms<'a> {
|
|||||||
self.0.pop()
|
self.0.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_json_term<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey>(
|
fn filter_json_term<
|
||||||
|
F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey,
|
||||||
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
e: ExprTerm<'a>,
|
e: ExprTerm<'a>,
|
||||||
fun: F,
|
fun: F,
|
||||||
@ -94,36 +96,46 @@ impl<'a> FilterTerms<'a> {
|
|||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
let mut not_matched = HashSet::new();
|
let mut not_matched = HashSet::new();
|
||||||
let filter_key = if let Some(FilterKey::String(key)) = fk {
|
let filter_key = if let Some(FilterKey::String(key)) = fk {
|
||||||
let key_contained = &vec.iter().map(|v| match v {
|
let key_contained = &vec
|
||||||
|
.iter()
|
||||||
|
.map(|v| match v {
|
||||||
Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(),
|
Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(),
|
||||||
_ => v,
|
_ => v,
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
fun(key_contained, &mut tmp, &mut not_matched)
|
fun(key_contained, &mut tmp, &mut not_matched)
|
||||||
} else {
|
} else {
|
||||||
fun(&vec, &mut tmp, &mut not_matched)
|
fun(&vec, &mut tmp, &mut not_matched)
|
||||||
};
|
};
|
||||||
|
|
||||||
if rel.is_some() {
|
if rel.is_some() {
|
||||||
self.0.push(Some(ExprTerm::Json(rel, Some(filter_key), tmp)));
|
self.0
|
||||||
|
.push(Some(ExprTerm::Json(rel, Some(filter_key), tmp)));
|
||||||
} else {
|
} else {
|
||||||
let filtered: Vec<&Value> = vec.iter().enumerate()
|
let filtered: Vec<&Value> = vec
|
||||||
.filter(
|
.iter()
|
||||||
|(idx, _)| !not_matched.contains(idx)
|
.enumerate()
|
||||||
)
|
.filter(|(idx, _)| !not_matched.contains(idx))
|
||||||
.map(|(_, v)| *v)
|
.map(|(_, v)| *v)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.0.push(Some(ExprTerm::Json(Some(filtered), Some(filter_key), tmp)));
|
self.0
|
||||||
|
.push(Some(ExprTerm::Json(Some(filtered), Some(filter_key), tmp)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("unexpected: ExprTerm: {:?}", e);
|
unreachable!("unexpected: ExprTerm: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_json_term<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey>(
|
fn push_json_term<
|
||||||
|
F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey,
|
||||||
|
FF: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey,
|
||||||
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
current: &Option<Vec<&'a Value>>,
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
fun: F,
|
fun: F,
|
||||||
|
fun_flattened: FF,
|
||||||
) {
|
) {
|
||||||
debug!("push_json_term: {:?}", ¤t);
|
debug!("push_json_term: {:?}", ¤t);
|
||||||
|
|
||||||
@ -131,35 +143,68 @@ impl<'a> FilterTerms<'a> {
|
|||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
let mut not_matched = HashSet::new();
|
let mut not_matched = HashSet::new();
|
||||||
let filter_key = fun(current, &mut tmp, &mut not_matched);
|
let filter_key = fun(current, &mut tmp, &mut not_matched);
|
||||||
self.0.push(Some(ExprTerm::Json(None, Some(filter_key), tmp)));
|
self.0
|
||||||
|
.push(Some(ExprTerm::Json(None, Some(filter_key), tmp)));
|
||||||
|
} else {
|
||||||
|
if let Some(values) = values {
|
||||||
|
let mut tmp = Vec::new();
|
||||||
|
let mut not_matched = HashSet::new();
|
||||||
|
let values = values.collect();
|
||||||
|
let filter_key = fun_flattened(&values, &mut tmp, &mut not_matched);
|
||||||
|
self.0
|
||||||
|
.push(Some(ExprTerm::Json(None, Some(filter_key), tmp)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey>(
|
fn filter<
|
||||||
|
F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey,
|
||||||
|
FF: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey,
|
||||||
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
current: &Option<Vec<&'a Value>>,
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
fun: F,
|
fun: F,
|
||||||
|
fun_flattened: FF,
|
||||||
) {
|
) {
|
||||||
if let Some(peek) = self.0.pop() {
|
if let Some(peek) = self.0.pop() {
|
||||||
if let Some(e) = peek {
|
if let Some(e) = peek {
|
||||||
self.filter_json_term(e, fun);
|
self.filter_json_term(e, fun);
|
||||||
} else {
|
} else {
|
||||||
self.push_json_term(current, fun);
|
self.push_json_term(current, values, fun, fun_flattened);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_all_with_str(&mut self, current: &Option<Vec<&'a Value>>, key: &str) {
|
fn filter_all_with_str(
|
||||||
self.filter(current, |vec, tmp, _| {
|
&mut self,
|
||||||
ValueWalker::all_with_str(&vec, tmp, key, true);
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
key: &str,
|
||||||
|
) {
|
||||||
|
self.filter(
|
||||||
|
current,
|
||||||
|
values,
|
||||||
|
|vec, tmp, _| {
|
||||||
|
JValueWalker::all_with_str(&vec, tmp, key, true);
|
||||||
FilterKey::All
|
FilterKey::All
|
||||||
});
|
},
|
||||||
|
|_, _, _| FilterKey::All,
|
||||||
|
);
|
||||||
|
|
||||||
debug!("filter_all_with_str : {}, {:?}", key, self.0);
|
debug!("filter_all_with_str : {}, {:?}", key, self.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_next_with_str(&mut self, current: &Option<Vec<&'a Value>>, key: &str) {
|
fn filter_next_with_str(
|
||||||
self.filter(current, |vec, tmp, not_matched| {
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
key: &str,
|
||||||
|
) {
|
||||||
|
self.filter(
|
||||||
|
current,
|
||||||
|
values,
|
||||||
|
|vec, tmp, not_matched| {
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
for (idx, v) in vec.iter().enumerate() {
|
for (idx, v) in vec.iter().enumerate() {
|
||||||
match v {
|
match v {
|
||||||
@ -177,7 +222,7 @@ impl<'a> FilterTerms<'a> {
|
|||||||
Value::Array(vec) => {
|
Value::Array(vec) => {
|
||||||
not_matched.insert(idx);
|
not_matched.insert(idx);
|
||||||
for v in vec {
|
for v in vec {
|
||||||
ValueWalker::walk_dedup(v, tmp, key, &mut visited);
|
JValueWalker::walk_dedup(v, tmp, key, &mut visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -187,12 +232,27 @@ impl<'a> FilterTerms<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FilterKey::String(key.to_owned())
|
FilterKey::String(key.to_owned())
|
||||||
});
|
},
|
||||||
|
|vec, tmp, not_matched| {
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
for (idx, v) in vec.iter().enumerate() {
|
||||||
|
not_matched.insert(idx);
|
||||||
|
JValueWalker::walk_dedup(v, tmp, key, &mut visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterKey::String(key.to_owned())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
debug!("filter_next_with_str : {}, {:?}", key, self.0);
|
debug!("filter_next_with_str : {}, {:?}", key, self.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_next_with_num(&mut self, current: &Option<Vec<&'a Value>>, index: f64) -> Option<Vec<&'a Value>> {
|
fn collect_next_with_num(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
index: f64,
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
fn _collect<'a>(tmp: &mut Vec<&'a Value>, vec: &'a [Value], index: f64) {
|
fn _collect<'a>(tmp: &mut Vec<&'a Value>, vec: &'a [Value], index: f64) {
|
||||||
let index = abs_index(index as isize, vec.len());
|
let index = abs_index(index as isize, vec.len());
|
||||||
if let Some(v) = vec.get(index) {
|
if let Some(v) = vec.get(index) {
|
||||||
@ -220,21 +280,34 @@ impl<'a> FilterTerms<'a> {
|
|||||||
|
|
||||||
if tmp.is_empty() {
|
if tmp.is_empty() {
|
||||||
self.0.pop();
|
self.0.pop();
|
||||||
return Some(vec![]);
|
return (Some(vec![]), None);
|
||||||
} else {
|
} else {
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
if let Some(mut values) = values {
|
||||||
"collect_next_with_num : {:?}, {:?}",
|
let index = abs_index(index as isize, values.len());
|
||||||
&index, ¤t
|
|
||||||
);
|
|
||||||
|
|
||||||
None
|
match values.nth(index) {
|
||||||
|
Some(value) => return (Some(vec![value]), Some(vec![index])),
|
||||||
|
None => {
|
||||||
|
self.0.pop();
|
||||||
|
return (Some(vec![]), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_next_all(&mut self, current: &Option<Vec<&'a Value>>) -> Option<Vec<&'a Value>> {
|
debug!("collect_next_with_num : {:?}, {:?}", &index, ¤t);
|
||||||
|
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_next_all(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
for c in current {
|
for c in current {
|
||||||
@ -252,15 +325,27 @@ impl<'a> FilterTerms<'a> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(current) = values {
|
||||||
|
let values = current.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let values_len = values.len();
|
||||||
|
return (Some(values), Some((0..values_len).collect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("collect_next_all : {:?}", ¤t);
|
debug!("collect_next_all : {:?}", ¤t);
|
||||||
|
|
||||||
None
|
(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_next_with_str(&mut self, current: &Option<Vec<&'a Value>>, keys: &[String]) -> Option<Vec<&'a Value>> {
|
fn collect_next_with_str(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
keys: &[String],
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
for c in current {
|
for c in current {
|
||||||
@ -275,63 +360,99 @@ impl<'a> FilterTerms<'a> {
|
|||||||
|
|
||||||
if tmp.is_empty() {
|
if tmp.is_empty() {
|
||||||
self.0.pop();
|
self.0.pop();
|
||||||
return Some(vec![]);
|
return (Some(vec![]), None);
|
||||||
} else {
|
} else {
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
if values.is_some() {
|
||||||
"collect_next_with_str : {:?}, {:?}",
|
// values has array-like structure
|
||||||
keys, ¤t
|
self.0.pop();
|
||||||
);
|
return (Some(vec![]), None);
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_all(&mut self, current: &Option<Vec<&'a Value>>) -> Option<Vec<&'a Value>> {
|
debug!("collect_next_with_str : {:?}, {:?}", keys, ¤t);
|
||||||
|
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_all(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
ValueWalker::all(¤t, &mut tmp);
|
JValueWalker::all(¤t, &mut tmp);
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(values) = values {
|
||||||
|
let values = values.collect::<Vec<_>>();
|
||||||
|
let values_len = values.len();
|
||||||
|
return (Some(values), Some((0..values_len).collect()));
|
||||||
}
|
}
|
||||||
debug!("collect_all: {:?}", ¤t);
|
debug!("collect_all: {:?}", ¤t);
|
||||||
|
|
||||||
None
|
(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_all_with_str(&mut self, current: &Option<Vec<&'a Value>>, key: &str) -> Option<Vec<&'a Value>> {
|
fn collect_all_with_str(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
key: &str,
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
ValueWalker::all_with_str(¤t, &mut tmp, key, false);
|
JValueWalker::all_with_str(¤t, &mut tmp, key, false);
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if values.is_some() {
|
||||||
|
return (Some(vec![]), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("collect_all_with_str: {}, {:?}", key, ¤t);
|
debug!("collect_all_with_str: {}, {:?}", key, ¤t);
|
||||||
|
|
||||||
None
|
(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_all_with_num(&mut self, current: &Option<Vec<&'a Value>>, index: f64) -> Option<Vec<&'a Value>> {
|
fn collect_all_with_num(
|
||||||
|
&mut self,
|
||||||
|
current: &Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
index: f64,
|
||||||
|
) -> (Option<Vec<&'a Value>>, Option<Vec<usize>>) {
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
ValueWalker::all_with_num(¤t, &mut tmp, index);
|
JValueWalker::all_with_num(¤t, &mut tmp, index);
|
||||||
return Some(tmp);
|
return (Some(tmp), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut values) = values {
|
||||||
|
match values.nth(index as usize) {
|
||||||
|
Some(value) => return (Some(vec![value]), Some(vec![index as usize])),
|
||||||
|
None => return (Some(vec![]), None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("collect_all_with_num: {}, {:?}", index, ¤t);
|
debug!("collect_all_with_num: {}, {:?}", index, ¤t);
|
||||||
|
|
||||||
None
|
(None, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Default)]
|
||||||
pub struct Selector<'a, 'b> {
|
pub struct Selector<'a, 'b> {
|
||||||
node: Option<Node>,
|
node: Option<Node>,
|
||||||
node_ref: Option<&'b Node>,
|
node_ref: Option<&'b Node>,
|
||||||
value: Option<&'a Value>,
|
value: Option<&'a Value>,
|
||||||
tokens: Vec<ParseToken>,
|
tokens: Vec<ParseToken>,
|
||||||
current: Option<Vec<&'a Value>>,
|
current: Option<Vec<&'a Value>>,
|
||||||
|
values: Option<Box<dyn ExactSizeIterator<Item = &'a Value> + 'a>>,
|
||||||
|
chose_indices: Vec<usize>,
|
||||||
selectors: Vec<Selector<'a, 'b>>,
|
selectors: Vec<Selector<'a, 'b>>,
|
||||||
selector_filter: FilterTerms<'a>,
|
selector_filter: FilterTerms<'a>,
|
||||||
}
|
}
|
||||||
@ -376,6 +497,14 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn values_iter(
|
||||||
|
&mut self,
|
||||||
|
values: impl Iterator<Item = &'a Value> + ExactSizeIterator + 'a,
|
||||||
|
) -> &mut Self {
|
||||||
|
self.values = Some(Box::new(values));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn _select(&mut self) -> Result<(), JsonPathError> {
|
fn _select(&mut self) -> Result<(), JsonPathError> {
|
||||||
if self.node_ref.is_some() {
|
if self.node_ref.is_some() {
|
||||||
let node_ref = self.node_ref.take().unwrap();
|
let node_ref = self.node_ref.take().unwrap();
|
||||||
@ -432,6 +561,15 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn select_(&mut self) -> Result<Vec<&'a Value>, JsonPathError> {
|
||||||
|
self._select()?;
|
||||||
|
|
||||||
|
match &self.current {
|
||||||
|
Some(r) => Ok(r.to_vec()),
|
||||||
|
_ => Err(JsonPathError::EmptyValue),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_absolute_path_filter(&mut self, token: &ParseToken) -> bool {
|
fn compute_absolute_path_filter(&mut self, token: &ParseToken) -> bool {
|
||||||
if !self.selectors.is_empty() {
|
if !self.selectors.is_empty() {
|
||||||
match token {
|
match token {
|
||||||
@ -471,11 +609,17 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
if let Some(value) = self.value {
|
if let Some(value) = self.value {
|
||||||
selector.value = Some(value);
|
selector.value = Some(value);
|
||||||
selector.current = Some(vec![value]);
|
selector.current = Some(vec![value]);
|
||||||
|
|
||||||
|
println!("current.is_some: {:?}", selector.current);
|
||||||
self.selectors.push(selector);
|
self.selectors.push(selector);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.values.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(v) = &self.value {
|
if let Some(v) = &self.value {
|
||||||
self.current = Some(vec![v]);
|
self.current = Some(vec![v]);
|
||||||
}
|
}
|
||||||
@ -485,8 +629,13 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
if let Some(ParseToken::Array) = self.tokens.last() {
|
if let Some(ParseToken::Array) = self.tokens.last() {
|
||||||
let array_token = self.tokens.pop();
|
let array_token = self.tokens.pop();
|
||||||
if let Some(ParseToken::Leaves) = self.tokens.last() {
|
if let Some(ParseToken::Leaves) = self.tokens.last() {
|
||||||
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
self.current = self.selector_filter.collect_all(&self.current);
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter.collect_all(&self.current, values);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
self.tokens.push(array_token.unwrap());
|
self.tokens.push(array_token.unwrap());
|
||||||
}
|
}
|
||||||
@ -496,8 +645,10 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
fn visit_array_eof(&mut self) {
|
fn visit_array_eof(&mut self) {
|
||||||
if self.is_last_before_token_match(ParseToken::Array) {
|
if self.is_last_before_token_match(ParseToken::Array) {
|
||||||
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
||||||
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
if let ExprTerm::String(key) = e {
|
if let ExprTerm::String(key) = e {
|
||||||
self.selector_filter.filter_next_with_str(&self.current, &key);
|
self.selector_filter
|
||||||
|
.filter_next_with_str(&self.current, values, &key);
|
||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -510,15 +661,29 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
||||||
let selector_filter_consumed = match &e {
|
let selector_filter_consumed =
|
||||||
|
match &e {
|
||||||
ExprTerm::Number(n) => {
|
ExprTerm::Number(n) => {
|
||||||
self.current = self.selector_filter.collect_all_with_num(&self.current, to_f64(n));
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) = self
|
||||||
|
.selector_filter
|
||||||
|
.collect_all_with_num(&self.current, values, to_f64(n));
|
||||||
|
|
||||||
self.selector_filter.pop_term();
|
self.selector_filter.pop_term();
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
ExprTerm::String(key) => {
|
ExprTerm::String(key) => {
|
||||||
self.current = self.selector_filter.collect_all_with_str(&self.current, key);
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) = self
|
||||||
|
.selector_filter
|
||||||
|
.collect_all_with_str(&self.current, values, key);
|
||||||
|
|
||||||
self.selector_filter.pop_term();
|
self.selector_filter.pop_term();
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -536,10 +701,25 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
if let Some(Some(e)) = self.selector_filter.pop_term() {
|
||||||
match e {
|
match e {
|
||||||
ExprTerm::Number(n) => {
|
ExprTerm::Number(n) => {
|
||||||
self.current = self.selector_filter.collect_next_with_num(&self.current, to_f64(&n));
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) = self.selector_filter.collect_next_with_num(
|
||||||
|
&self.current,
|
||||||
|
values,
|
||||||
|
to_f64(&n),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
ExprTerm::String(key) => {
|
ExprTerm::String(key) => {
|
||||||
self.current = self.selector_filter.collect_next_with_str(&self.current, &[key]);
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
|
||||||
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter
|
||||||
|
.collect_next_with_str(&self.current, values, &[key]);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
ExprTerm::Json(rel, _, v) => {
|
ExprTerm::Json(rel, _, v) => {
|
||||||
if v.is_empty() {
|
if v.is_empty() {
|
||||||
@ -573,24 +753,38 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
match self.tokens.last() {
|
match self.tokens.last() {
|
||||||
Some(ParseToken::Leaves) => {
|
Some(ParseToken::Leaves) => {
|
||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
self.current = self.selector_filter.collect_all(&self.current);
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter.collect_all(&self.current, values);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
Some(ParseToken::In) => {
|
Some(ParseToken::In) => {
|
||||||
self.tokens.pop();
|
self.tokens.pop();
|
||||||
self.current = self.selector_filter.collect_next_all(&self.current);
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter.collect_next_all(&self.current, values);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.current = self.selector_filter.collect_next_all(&self.current);
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter.collect_next_all(&self.current, values);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_key(&mut self, key: &str) {
|
fn visit_key(&mut self, key: &str) {
|
||||||
if let Some(ParseToken::Array) = self.tokens.last() {
|
if let Some(ParseToken::Array) = self.tokens.last() {
|
||||||
self.selector_filter.push_term(Some(ExprTerm::String(key.to_string())));
|
self.selector_filter
|
||||||
|
.push_term(Some(ExprTerm::String(key.to_string())));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,20 +792,38 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
if self.selector_filter.is_term_empty() {
|
if self.selector_filter.is_term_empty() {
|
||||||
match t {
|
match t {
|
||||||
ParseToken::Leaves => {
|
ParseToken::Leaves => {
|
||||||
self.current = self.selector_filter.collect_all_with_str(&self.current, key)
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter
|
||||||
|
.collect_all_with_str(&self.current, values, key);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
ParseToken::In => {
|
ParseToken::In => {
|
||||||
self.current = self.selector_filter.collect_next_with_str(&self.current, &[key.to_string()])
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) = self.selector_filter.collect_next_with_str(
|
||||||
|
&self.current,
|
||||||
|
values,
|
||||||
|
&[key.to_string()],
|
||||||
|
);
|
||||||
|
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match t {
|
match t {
|
||||||
ParseToken::Leaves => {
|
ParseToken::Leaves => {
|
||||||
self.selector_filter.filter_all_with_str(&self.current, key);
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
self.selector_filter
|
||||||
|
.filter_all_with_str(&self.current, values, key);
|
||||||
}
|
}
|
||||||
ParseToken::In => {
|
ParseToken::In => {
|
||||||
self.selector_filter.filter_next_with_str(&self.current, key);
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
self.selector_filter
|
||||||
|
.filter_next_with_str(&self.current, values, key);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -625,7 +837,12 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ParseToken::Array) = self.tokens.pop() {
|
if let Some(ParseToken::Array) = self.tokens.pop() {
|
||||||
self.current = self.selector_filter.collect_next_with_str(&self.current, keys);
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
let (current, chose_indices) =
|
||||||
|
self.selector_filter
|
||||||
|
.collect_next_with_str(&self.current, values, keys);
|
||||||
|
self.current = current;
|
||||||
|
self.chose_indices.extend(chose_indices.unwrap_or_default());
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@ -685,28 +902,54 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
if let Some(current) = &self.current {
|
if let Some(current) = &self.current {
|
||||||
for v in current {
|
for v in current {
|
||||||
if let Value::Array(vec) = v {
|
if let Value::Array(vec) = v {
|
||||||
let from = if let Some(from) = from {
|
let from = match from {
|
||||||
abs_index(*from, vec.len())
|
Some(from) => abs_index(*from, vec.len()),
|
||||||
} else {
|
None => 0,
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let to = if let Some(to) = to {
|
let to = match to {
|
||||||
abs_index(*to, vec.len())
|
Some(to) => abs_index(*to, vec.len()),
|
||||||
} else {
|
None => vec.len(),
|
||||||
vec.len()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in (from..to).step_by(match step {
|
let step = match step {
|
||||||
Some(step) => *step,
|
Some(step) => *step,
|
||||||
_ => 1,
|
None => 1,
|
||||||
}) {
|
};
|
||||||
|
|
||||||
|
for i in (from..to).step_by(step) {
|
||||||
if let Some(v) = vec.get(i) {
|
if let Some(v) = vec.get(i) {
|
||||||
tmp.push(v);
|
tmp.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
if let Some(values) = values {
|
||||||
|
let from = match from {
|
||||||
|
Some(from) => abs_index(*from, values.len()),
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let to = match to {
|
||||||
|
Some(to) => abs_index(*to, values.len()),
|
||||||
|
None => values.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let step = match step {
|
||||||
|
Some(step) => *step,
|
||||||
|
None => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let take_count = if from > to { 0 } else { to - from };
|
||||||
|
|
||||||
|
let matched_values = values.skip(from).step_by(step).take(take_count);
|
||||||
|
tmp.extend(matched_values);
|
||||||
|
|
||||||
|
self.chose_indices
|
||||||
|
.extend((from..to).step_by(step).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.current = Some(tmp);
|
self.current = Some(tmp);
|
||||||
} else {
|
} else {
|
||||||
@ -731,6 +974,21 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let indices = indices.iter().map(|&v| v as usize).collect::<HashSet<_>>();
|
||||||
|
let values = std::mem::replace(&mut self.values, None);
|
||||||
|
if let Some(values) = values {
|
||||||
|
let new_values = values
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(id, _)| indices.contains(id))
|
||||||
|
.map(|(id, value)| {
|
||||||
|
self.chose_indices.push(id);
|
||||||
|
value
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
tmp.extend(new_values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current = Some(tmp);
|
self.current = Some(tmp);
|
||||||
@ -738,6 +996,10 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chose_indices(self) -> Vec<usize> {
|
||||||
|
self.chose_indices
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||||
@ -762,7 +1024,8 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|||||||
ParseToken::Key(key) => self.visit_key(key),
|
ParseToken::Key(key) => self.visit_key(key),
|
||||||
ParseToken::Keys(keys) => self.visit_keys(keys),
|
ParseToken::Keys(keys) => self.visit_keys(keys),
|
||||||
ParseToken::Number(v) => {
|
ParseToken::Number(v) => {
|
||||||
self.selector_filter.push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
self.selector_filter
|
||||||
|
.push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
||||||
}
|
}
|
||||||
ParseToken::Filter(ref ft) => self.visit_filter(ft),
|
ParseToken::Filter(ref ft) => self.visit_filter(ft),
|
||||||
ParseToken::Range(from, to, step) => self.visit_range(from, to, step),
|
ParseToken::Range(from, to, step) => self.visit_range(from, to, step),
|
||||||
@ -961,7 +1224,6 @@ impl SelectorMut {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod select_inner_tests {
|
mod select_inner_tests {
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub(super) struct ValueWalker;
|
pub(super) struct JValueWalker;
|
||||||
|
|
||||||
impl<'a> ValueWalker {
|
impl<'a> JValueWalker {
|
||||||
pub fn all_with_num(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) {
|
pub fn all_with_num(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) {
|
||||||
Self::walk(vec, tmp, &|v| if v.is_array() {
|
Self::walk(vec, tmp, &|v| {
|
||||||
|
if v.is_array() {
|
||||||
if let Some(item) = v.get(index as usize) {
|
if let Some(item) = v.get(index as usize) {
|
||||||
Some(vec![item])
|
Some(vec![item])
|
||||||
} else {
|
} else {
|
||||||
@ -13,6 +14,7 @@ impl<'a> ValueWalker {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,13 +49,19 @@ impl<'a> ValueWalker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk<F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option<Vec<&Value>> {
|
fn walk<F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F)
|
||||||
|
where
|
||||||
|
F: Fn(&Value) -> Option<Vec<&Value>>,
|
||||||
|
{
|
||||||
for v in vec {
|
for v in vec {
|
||||||
Self::_walk(v, tmp, fun);
|
Self::_walk(v, tmp, fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _walk<F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option<Vec<&Value>> {
|
fn _walk<F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F)
|
||||||
|
where
|
||||||
|
F: Fn(&Value) -> Option<Vec<&Value>>,
|
||||||
|
{
|
||||||
if let Some(mut ret) = fun(v) {
|
if let Some(mut ret) = fun(v) {
|
||||||
tmp.append(&mut ret);
|
tmp.append(&mut ret);
|
||||||
}
|
}
|
||||||
@ -73,10 +81,12 @@ impl<'a> ValueWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_dedup(v: &'a Value,
|
pub fn walk_dedup(
|
||||||
|
v: &'a Value,
|
||||||
tmp: &mut Vec<&'a Value>,
|
tmp: &mut Vec<&'a Value>,
|
||||||
key: &str,
|
key: &str,
|
||||||
visited: &mut HashSet<*const Value>, ) {
|
visited: &mut HashSet<*const Value>,
|
||||||
|
) {
|
||||||
match v {
|
match v {
|
||||||
Value::Object(map) => {
|
Value::Object(map) => {
|
||||||
if map.contains_key(key) {
|
if map.contains_key(key) {
|
||||||
@ -96,4 +106,3 @@ impl<'a> ValueWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
tests/op.rs
45
tests/op.rs
@ -174,14 +174,14 @@ fn op_ge_for_number() {
|
|||||||
select_and_then_compare("$.[?(@.a >= 0)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
select_and_then_compare("$.[?(@.a >= 0)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_eq_for_string_value() {
|
fn op_eq_for_string_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(
|
||||||
r#"$.[?(@.a == "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]),
|
r#"$.[?(@.a == "b")]"#,
|
||||||
|
json!({ "a": "b" }),
|
||||||
|
json!([{ "a": "b" }]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,18 +190,17 @@ fn op_ne_for_string_value() {
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(
|
||||||
r#"$.[?(@.a != "c")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]),
|
r#"$.[?(@.a != "c")]"#,
|
||||||
|
json!({ "a": "b" }),
|
||||||
|
json!([{ "a": "b" }]),
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_lt_for_string_value() {
|
fn op_lt_for_string_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([]));
|
||||||
r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -209,7 +208,9 @@ fn op_le_for_string_value() {
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(
|
||||||
r#"$.[?(@.a <= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]),
|
r#"$.[?(@.a <= "b")]"#,
|
||||||
|
json!({ "a": "b" }),
|
||||||
|
json!([{ "a": "b" }]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,9 +218,7 @@ fn op_le_for_string_value() {
|
|||||||
fn op_gt_for_string_value() {
|
fn op_gt_for_string_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([]));
|
||||||
r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -227,7 +226,9 @@ fn op_ge_for_string_value() {
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(
|
||||||
r#"$.[?(@.a >= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]),
|
r#"$.[?(@.a >= "b")]"#,
|
||||||
|
json!({ "a": "b" }),
|
||||||
|
json!([{ "a": "b" }]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,11 +302,7 @@ fn op_ge_for_object_value() {
|
|||||||
fn op_eq_for_complex_value() {
|
fn op_eq_for_complex_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(r#"$.[?(1 == @.a)]"#, json!({ "a": { "b": 1 } }), json!([]));
|
||||||
r#"$.[?(1 == @.a)]"#,
|
|
||||||
json!({ "a": { "b": 1 } }),
|
|
||||||
json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -323,22 +320,14 @@ fn op_ne_for_complex_value() {
|
|||||||
fn op_le_for_complex_value() {
|
fn op_le_for_complex_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(r#"$.[?(@.a <= 1)]"#, json!({ "a": { "b": 1 } }), json!([]));
|
||||||
r#"$.[?(@.a <= 1)]"#,
|
|
||||||
json!({ "a": { "b": 1 } }),
|
|
||||||
json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_gt_for_complex_value() {
|
fn op_gt_for_complex_value() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(r#"$.[?(@.a > "1")]"#, json!({ "a": { "b": 1 } }), json!([]));
|
||||||
r#"$.[?(@.a > "1")]"#,
|
|
||||||
json!({ "a": { "b": 1 } }),
|
|
||||||
json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -100,9 +100,5 @@ fn return_type_for_array_filter_true() {
|
|||||||
fn return_type_empty() {
|
fn return_type_empty() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare("$[?(@.key==43)]", json!([{"key": 42}]), json!([]));
|
||||||
"$[?(@.key==43)]",
|
|
||||||
json!([{"key": 42}]),
|
|
||||||
json!([]),
|
|
||||||
);
|
|
||||||
}
|
}
|
@ -120,12 +120,58 @@ fn selector_remove() {
|
|||||||
.select()
|
.select()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(result, vec![&json!(8.95), &json!(12.99), &json!(8.99)]);
|
||||||
result,
|
}
|
||||||
vec![
|
|
||||||
&json!(8.95),
|
#[test]
|
||||||
&json!(12.99),
|
fn iter_test() {
|
||||||
&json!(8.99)
|
use std::rc::Rc;
|
||||||
]
|
|
||||||
);
|
struct T {
|
||||||
|
pub value: Rc<Value>,
|
||||||
|
pub tt: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
let t = Value::Array(vec![
|
||||||
|
Value::String(String::from("vv")),
|
||||||
|
Value::Array(vec![]),
|
||||||
|
]);
|
||||||
|
let t1 = T {
|
||||||
|
value: Rc::new(t.clone()),
|
||||||
|
tt: 1,
|
||||||
|
};
|
||||||
|
let t2 = T {
|
||||||
|
value: Rc::new(t.clone()),
|
||||||
|
tt: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let values = vec![t1, t2];
|
||||||
|
|
||||||
|
let mut selector = Selector::default();
|
||||||
|
|
||||||
|
let path = "$.[0]";
|
||||||
|
let result = selector
|
||||||
|
.str_path(path)
|
||||||
|
.unwrap()
|
||||||
|
.values_iter(values.iter().map(|v| v.value.as_ref()))
|
||||||
|
.select()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, vec![&json!(["vv", []])]);
|
||||||
|
|
||||||
|
let result = jsonpath::select_with_iter(values.iter().map(|v| v.value.as_ref()), path).unwrap();
|
||||||
|
assert_eq!(result.0, vec![&json!(["vv", []])]);
|
||||||
|
assert_eq!(result.1, vec![0]);
|
||||||
|
|
||||||
|
let values = vec![json!([1, 2, 3, 4]), json!([2, 2]), json!(3)];
|
||||||
|
|
||||||
|
let mut selector = Selector::default();
|
||||||
|
let result = selector
|
||||||
|
.str_path(path)
|
||||||
|
.unwrap()
|
||||||
|
.values_iter(values.iter())
|
||||||
|
.select()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, vec![&json!([1, 2, 3, 4])]);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user