mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-03 15:31:04 +00:00
apply clippy lints
This commit is contained in:
parent
f5717d6d26
commit
b910ed35f9
@ -109,7 +109,7 @@ fn bench_select_as(b: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn bench_delete(b: &mut Bencher) {
|
fn bench_delete(b: &mut Bencher) {
|
||||||
let json = get_json();
|
let json = get_json();
|
||||||
let mut selector = SelectorMut::new();
|
let mut selector = SelectorMut::default();
|
||||||
let _ = selector.str_path(get_path());
|
let _ = selector.str_path(get_path());
|
||||||
|
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
@ -123,13 +123,13 @@ fn bench_delete(b: &mut Bencher) {
|
|||||||
fn bench_select_to_compare_with_delete(b: &mut Bencher) {
|
fn bench_select_to_compare_with_delete(b: &mut Bencher) {
|
||||||
let json = &get_json();
|
let json = &get_json();
|
||||||
|
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
let _ = selector.str_path(get_path());
|
let _ = selector.str_path(get_path());
|
||||||
|
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
for _ in 1..100 {
|
for _ in 1..100 {
|
||||||
let json = json.clone();
|
let json = json.clone();
|
||||||
let mut s = Selector::new();
|
let mut s = Selector::default();
|
||||||
let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json);
|
let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json);
|
||||||
let _ = s.select();
|
let _ = s.select();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ fn _selector(b: &mut Bencher, index: usize) {
|
|||||||
let json = get_json();
|
let json = get_json();
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
for _ in 1..100 {
|
for _ in 1..100 {
|
||||||
let mut selector = jsonpath::Selector::new();
|
let mut selector = jsonpath::Selector::default();
|
||||||
let _ = selector.str_path(get_path(index));
|
let _ = selector.str_path(get_path(index));
|
||||||
selector.value(&json);
|
selector.value(&json);
|
||||||
let r = selector.select();
|
let r = selector.select();
|
||||||
|
17
src/lib.rs
17
src/lib.rs
@ -172,7 +172,7 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPath
|
|||||||
let node = Parser::compile(path);
|
let node = Parser::compile(path);
|
||||||
move |json| match &node {
|
move |json| match &node {
|
||||||
Ok(node) => {
|
Ok(node) => {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
selector.compiled_path(node).value(json).select()
|
selector.compiled_path(node).value(json).select()
|
||||||
}
|
}
|
||||||
Err(e) => Err(JsonPathError::Path(e.to_string())),
|
Err(e) => Err(JsonPathError::Path(e.to_string())),
|
||||||
@ -213,8 +213,9 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPath
|
|||||||
/// &json!({"name": "친구2", "age": 20})
|
/// &json!({"name": "친구2", "age": 20})
|
||||||
/// ]);
|
/// ]);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[allow(clippy::needless_lifetimes)]
|
||||||
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError> {
|
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError> {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
let _ = selector.value(json);
|
let _ = selector.value(json);
|
||||||
move |path: &str| selector.str_path(path)?.reset_value().select()
|
move |path: &str| selector.str_path(path)?.reset_value().select()
|
||||||
}
|
}
|
||||||
@ -268,7 +269,7 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value
|
|||||||
pub fn selector_as<T: serde::de::DeserializeOwned>(
|
pub fn selector_as<T: serde::de::DeserializeOwned>(
|
||||||
json: &Value,
|
json: &Value,
|
||||||
) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
|
) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
let _ = selector.value(json);
|
let _ = selector.value(json);
|
||||||
move |path: &str| selector.str_path(path)?.reset_value().select_as()
|
move |path: &str| selector.str_path(path)?.reset_value().select_as()
|
||||||
}
|
}
|
||||||
@ -299,7 +300,7 @@ pub fn selector_as<T: serde::de::DeserializeOwned>(
|
|||||||
/// ]);
|
/// ]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, JsonPathError> {
|
pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, JsonPathError> {
|
||||||
Selector::new().str_path(path)?.value(json).select()
|
Selector::default().str_path(path)?.value(json).select()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -327,7 +328,7 @@ pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, Json
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn select_as_str(json_str: &str, path: &str) -> Result<String, JsonPathError> {
|
pub fn select_as_str(json_str: &str, path: &str) -> Result<String, 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()))?;
|
||||||
let ret = Selector::new().str_path(path)?.value(&json).select()?;
|
let ret = Selector::default().str_path(path)?.value(&json).select()?;
|
||||||
serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string()))
|
serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +375,7 @@ 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::new().str_path(path)?.value(&json).select_as()
|
Selector::default().str_path(path)?.value(&json).select_as()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete(= replace with null) the JSON property using the jsonpath.
|
/// Delete(= replace with null) the JSON property using the jsonpath.
|
||||||
@ -410,7 +411,7 @@ pub fn select_as<T: serde::de::DeserializeOwned>(
|
|||||||
/// ]}));
|
/// ]}));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
|
pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
|
||||||
let mut selector = SelectorMut::new();
|
let mut selector = SelectorMut::default();
|
||||||
let ret = selector
|
let ret = selector
|
||||||
.str_path(path)?
|
.str_path(path)?
|
||||||
.value(value)
|
.value(value)
|
||||||
@ -466,7 +467,7 @@ pub fn replace_with<F>(value: Value, path: &str, fun: &mut F) -> Result<Value, J
|
|||||||
where
|
where
|
||||||
F: FnMut(&Value) -> Value,
|
F: FnMut(&Value) -> Value,
|
||||||
{
|
{
|
||||||
let mut selector = SelectorMut::new();
|
let mut selector = SelectorMut::default();
|
||||||
let ret = selector
|
let ret = selector
|
||||||
.str_path(path)?
|
.str_path(path)?
|
||||||
.value(value)
|
.value(value)
|
||||||
|
@ -9,11 +9,11 @@ type ParseResult<T> = Result<T, String>;
|
|||||||
mod utils {
|
mod utils {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub fn string_to_num<F, S: FromStr>(string: &String, msg_handler: F) -> Result<S, String>
|
pub fn string_to_num<F, S: FromStr>(string: &str, msg_handler: F) -> Result<S, String>
|
||||||
where
|
where
|
||||||
F: Fn() -> String,
|
F: Fn() -> String,
|
||||||
{
|
{
|
||||||
match string.as_str().parse() {
|
match string.parse() {
|
||||||
Ok(n) => Ok(n),
|
Ok(n) => Ok(n),
|
||||||
_ => Err(msg_handler()),
|
_ => Err(msg_handler()),
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ impl Parser {
|
|||||||
Ok(Token::Key(_, ref v))
|
Ok(Token::Key(_, ref v))
|
||||||
if {
|
if {
|
||||||
let b = v.as_bytes();
|
let b = v.as_bytes();
|
||||||
b.len() > 0 && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
|
!b.is_empty() && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
|
||||||
} =>
|
} =>
|
||||||
{
|
{
|
||||||
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
||||||
@ -379,16 +379,12 @@ impl Parser {
|
|||||||
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
debug!("#range_to");
|
debug!("#range_to");
|
||||||
|
|
||||||
match Self::range_value(tokenizer)? {
|
if let Some(step) = Self::range_value(tokenizer)? {
|
||||||
Some(step) => return Ok(Self::node(ParseToken::Range(None, None, Some(step)))),
|
return Ok(Self::node(ParseToken::Range(None, None, Some(step))));
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match tokenizer.peek_token() {
|
if let Ok(Token::CloseArray(_)) = tokenizer.peek_token() {
|
||||||
Ok(Token::CloseArray(_)) => {
|
return Ok(Self::node(ParseToken::Range(None, None, None)));
|
||||||
return Ok(Self::node(ParseToken::Range(None, None, None)));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match tokenizer.next_token() {
|
match tokenizer.next_token() {
|
||||||
@ -492,7 +488,7 @@ impl Parser {
|
|||||||
} else if has_prop_candidate {
|
} else if has_prop_candidate {
|
||||||
Ok(node)
|
Ok(node)
|
||||||
} else {
|
} else {
|
||||||
return Err(tokenizer.err_msg());
|
Err(tokenizer.err_msg())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,13 +506,13 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term_num_float(mut num: &str, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn term_num_float(num: &str, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
debug!("#term_num_float");
|
debug!("#term_num_float");
|
||||||
Self::eat_token(tokenizer);
|
Self::eat_token(tokenizer);
|
||||||
match tokenizer.next_token() {
|
match tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, frac)) => {
|
Ok(Token::Key(pos, frac)) => {
|
||||||
let mut f = String::new();
|
let mut f = String::new();
|
||||||
f.push_str(&mut num);
|
f.push_str(&num);
|
||||||
f.push('.');
|
f.push('.');
|
||||||
f.push_str(frac.as_str());
|
f.push_str(frac.as_str());
|
||||||
let number = utils::string_to_num(&f, || tokenizer.err_msg_with_pos(pos))?;
|
let number = utils::string_to_num(&f, || tokenizer.err_msg_with_pos(pos))?;
|
||||||
@ -563,7 +559,7 @@ impl Parser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(tokenizer.err_msg());
|
Err(tokenizer.err_msg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
@ -631,56 +627,49 @@ pub trait NodeVisitor {
|
|||||||
self.visit_token(&node.token);
|
self.visit_token(&node.token);
|
||||||
}
|
}
|
||||||
ParseToken::In | ParseToken::Leaves => {
|
ParseToken::In | ParseToken::Leaves => {
|
||||||
match &node.left {
|
if let Some(n) = &node.left {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_token(&node.token);
|
self.visit_token(&node.token);
|
||||||
|
|
||||||
match &node.right {
|
if let Some(n) = &node.right {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParseToken::Array => {
|
ParseToken::Array => {
|
||||||
match &node.left {
|
if let Some(n) = &node.left {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_token(&node.token);
|
self.visit_token(&node.token);
|
||||||
|
|
||||||
match &node.right {
|
if let Some(n) = &node.right {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_token(&ParseToken::ArrayEof);
|
self.visit_token(&ParseToken::ArrayEof);
|
||||||
}
|
}
|
||||||
ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => {
|
ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => {
|
||||||
match &node.left {
|
if let Some(n) = &node.left {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match &node.right {
|
if let Some(n) = &node.right {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_token(&node.token);
|
self.visit_token(&node.token);
|
||||||
}
|
}
|
||||||
ParseToken::Filter(_) => {
|
ParseToken::Filter(_) => {
|
||||||
match &node.left {
|
if let Some(n) = &node.left {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.end_term();
|
self.end_term();
|
||||||
|
|
||||||
match &node.right {
|
if let Some(n) = &node.right {
|
||||||
Some(n) => self.visit(&*n),
|
self.visit(&*n);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.end_term();
|
self.end_term();
|
||||||
|
@ -2,29 +2,29 @@ use std::result::Result;
|
|||||||
|
|
||||||
use super::path_reader::{PathReader, ReaderError};
|
use super::path_reader::{PathReader, ReaderError};
|
||||||
|
|
||||||
pub const ABSOLUTE: &'static str = "$";
|
pub const ABSOLUTE: &str = "$";
|
||||||
pub const DOT: &'static str = ".";
|
pub const DOT: &str = ".";
|
||||||
pub const AT: &'static str = "@";
|
pub const AT: &str = "@";
|
||||||
pub const OPEN_ARRAY: &'static str = "[";
|
pub const OPEN_ARRAY: &str = "[";
|
||||||
pub const CLOSE_ARRAY: &'static str = "]";
|
pub const CLOSE_ARRAY: &str = "]";
|
||||||
pub const ASTERISK: &'static str = "*";
|
pub const ASTERISK: &str = "*";
|
||||||
pub const QUESTION: &'static str = "?";
|
pub const QUESTION: &str = "?";
|
||||||
pub const COMMA: &'static str = ",";
|
pub const COMMA: &str = ",";
|
||||||
pub const SPLIT: &'static str = ":";
|
pub const SPLIT: &str = ":";
|
||||||
pub const OPEN_PARENTHESIS: &'static str = "(";
|
pub const OPEN_PARENTHESIS: &str = "(";
|
||||||
pub const CLOSE_PARENTHESIS: &'static str = ")";
|
pub const CLOSE_PARENTHESIS: &str = ")";
|
||||||
pub const KEY: &'static str = "Key";
|
pub const KEY: &str = "Key";
|
||||||
pub const DOUBLE_QUOTE: &'static str = "\"";
|
pub const DOUBLE_QUOTE: &str = "\"";
|
||||||
pub const SINGLE_QUOTE: &'static str = "'";
|
pub const SINGLE_QUOTE: &str = "'";
|
||||||
pub const EQUAL: &'static str = "==";
|
pub const EQUAL: &str = "==";
|
||||||
pub const GREATER_OR_EQUAL: &'static str = ">=";
|
pub const GREATER_OR_EQUAL: &str = ">=";
|
||||||
pub const GREATER: &'static str = ">";
|
pub const GREATER: &str = ">";
|
||||||
pub const LITTLE: &'static str = "<";
|
pub const LITTLE: &str = "<";
|
||||||
pub const LITTLE_OR_EQUAL: &'static str = "<=";
|
pub const LITTLE_OR_EQUAL: &str = "<=";
|
||||||
pub const NOT_EQUAL: &'static str = "!=";
|
pub const NOT_EQUAL: &str = "!=";
|
||||||
pub const AND: &'static str = "&&";
|
pub const AND: &str = "&&";
|
||||||
pub const OR: &'static str = "||";
|
pub const OR: &str = "||";
|
||||||
pub const WHITESPACE: &'static str = " ";
|
pub const WHITESPACE: &str = " ";
|
||||||
|
|
||||||
const CH_DOLLA: char = '$';
|
const CH_DOLLA: char = '$';
|
||||||
const CH_DOT: char = '.';
|
const CH_DOT: char = '.';
|
||||||
@ -321,7 +321,7 @@ impl<'a> TokenReader<'a> {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return TokenReader {
|
return TokenReader {
|
||||||
origin_input: input.clone(),
|
origin_input: input,
|
||||||
err: e,
|
err: e,
|
||||||
err_pos: tokenizer.current_pos(),
|
err_pos: tokenizer.current_pos(),
|
||||||
tokens,
|
tokens,
|
||||||
|
@ -17,13 +17,13 @@ fn to_f64(n: &Number) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trait Cmp {
|
trait Cmp {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool;
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool;
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool;
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool;
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool;
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool;
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value>;
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value>;
|
||||||
|
|
||||||
fn default(&self) -> bool {
|
fn default(&self) -> bool {
|
||||||
false
|
false
|
||||||
@ -33,59 +33,59 @@ trait Cmp {
|
|||||||
struct CmpEq;
|
struct CmpEq;
|
||||||
|
|
||||||
impl Cmp for CmpEq {
|
impl Cmp for CmpEq {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
v1 == v2
|
v1 == v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
|
(v1 - v2).abs() == 0_f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 == v2
|
v1 == v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1 == v2
|
v1.to_vec().intersect(v2.to_vec())
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> {
|
|
||||||
v1.intersect(v2.to_vec())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmpNe;
|
struct CmpNe;
|
||||||
|
|
||||||
impl Cmp for CmpNe {
|
impl Cmp for CmpNe {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
v1 != v2
|
v1 != v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
|
(v1 - v2).abs() != 0_f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 != v2
|
v1 != v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1 != v2
|
v1.to_vec().intersect_if(v2.to_vec(), |a, b| a != b)
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> {
|
|
||||||
v1.intersect_if(v2.to_vec(), |a, b| a != b)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmpGt;
|
struct CmpGt;
|
||||||
|
|
||||||
impl Cmp for CmpGt {
|
impl Cmp for CmpGt {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
v1 & !v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 > v2
|
v1 > v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 > v2
|
v1 > v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1 > v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,19 +93,19 @@ impl Cmp for CmpGt {
|
|||||||
struct CmpGe;
|
struct CmpGe;
|
||||||
|
|
||||||
impl Cmp for CmpGe {
|
impl Cmp for CmpGe {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
v1 >= v2
|
v1 >= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 >= v2
|
v1 >= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 >= v2
|
v1 >= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> {
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,19 +113,19 @@ impl Cmp for CmpGe {
|
|||||||
struct CmpLt;
|
struct CmpLt;
|
||||||
|
|
||||||
impl Cmp for CmpLt {
|
impl Cmp for CmpLt {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
!v1 & v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 < v2
|
v1 < v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 < v2
|
v1 < v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1 < v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,19 +133,19 @@ impl Cmp for CmpLt {
|
|||||||
struct CmpLe;
|
struct CmpLe;
|
||||||
|
|
||||||
impl Cmp for CmpLe {
|
impl Cmp for CmpLe {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
v1 <= v2
|
v1 <= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 <= v2
|
v1 <= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
v1 <= v2
|
v1 <= v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> {
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,40 +153,40 @@ impl Cmp for CmpLe {
|
|||||||
struct CmpAnd;
|
struct CmpAnd;
|
||||||
|
|
||||||
impl Cmp for CmpAnd {
|
impl Cmp for CmpAnd {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
*v1 && *v2
|
v1 && v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 > &0_f64 && v2 > &0_f64
|
v1 > 0_f64 && v2 > 0_f64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
!v1.is_empty() && !v2.is_empty()
|
!v1.is_empty() && !v2.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> {
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1.intersect(v2.to_vec())
|
v1.to_vec().intersect(v2.to_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmpOr;
|
struct CmpOr;
|
||||||
|
|
||||||
impl Cmp for CmpOr {
|
impl Cmp for CmpOr {
|
||||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
*v1 || *v2
|
v1 || v2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
v1 > &0_f64 || v2 > &0_f64
|
v1 > 0_f64 || v2 > 0_f64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
!v1.is_empty() || !v2.is_empty()
|
!v1.is_empty() || !v2.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> {
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
v1.union(v2.to_vec())
|
v1.to_vec().union(v2.to_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,12 +212,12 @@ impl<'a> ExprTerm<'a> {
|
|||||||
_ => ExprTerm::Bool(cmp_fn.default()),
|
_ => ExprTerm::Bool(cmp_fn.default()),
|
||||||
},
|
},
|
||||||
ExprTerm::Number(n1) => match &other {
|
ExprTerm::Number(n1) => match &other {
|
||||||
ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2))),
|
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(cmp_fn.default()),
|
||||||
},
|
},
|
||||||
ExprTerm::Bool(b1) => match &other {
|
ExprTerm::Bool(b1) => match &other {
|
||||||
ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(b1, b2)),
|
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::Bool(cmp_fn.default()),
|
||||||
},
|
},
|
||||||
@ -237,39 +237,39 @@ impl<'a> ExprTerm<'a> {
|
|||||||
}
|
}
|
||||||
_ => cmp_fn.default(),
|
_ => cmp_fn.default(),
|
||||||
})
|
})
|
||||||
.map(|v| *v)
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
ExprTerm::Number(n2) => vec1
|
ExprTerm::Number(n2) => vec1
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|v1| match v1 {
|
.filter(|v1| match v1 {
|
||||||
Value::Number(n1) => cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)),
|
Value::Number(n1) => cmp_fn.cmp_f64(to_f64(n1), to_f64(n2)),
|
||||||
Value::Object(map1) => {
|
Value::Object(map1) => {
|
||||||
if let Some(FilterKey::String(k)) = fk1 {
|
if let Some(FilterKey::String(k)) = fk1 {
|
||||||
if let Some(Value::Number(n1)) = map1.get(k) {
|
if let Some(Value::Number(n1)) = map1.get(k) {
|
||||||
return cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2));
|
return cmp_fn.cmp_f64(to_f64(n1), to_f64(n2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmp_fn.default()
|
cmp_fn.default()
|
||||||
}
|
}
|
||||||
_ => cmp_fn.default(),
|
_ => cmp_fn.default(),
|
||||||
})
|
})
|
||||||
.map(|v| *v)
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
ExprTerm::Bool(b2) => vec1
|
ExprTerm::Bool(b2) => vec1
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|v1| match v1 {
|
.filter(|v1| match v1 {
|
||||||
Value::Bool(b1) => cmp_fn.cmp_bool(b1, b2),
|
Value::Bool(b1) => cmp_fn.cmp_bool(*b1, *b2),
|
||||||
Value::Object(map1) => {
|
Value::Object(map1) => {
|
||||||
if let Some(FilterKey::String(k)) = fk1 {
|
if let Some(FilterKey::String(k)) = fk1 {
|
||||||
if let Some(Value::Bool(b1)) = map1.get(k) {
|
if let Some(Value::Bool(b1)) = map1.get(k) {
|
||||||
return cmp_fn.cmp_bool(b1, b2);
|
return cmp_fn.cmp_bool(*b1, *b2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmp_fn.default()
|
cmp_fn.default()
|
||||||
}
|
}
|
||||||
_ => cmp_fn.default(),
|
_ => cmp_fn.default(),
|
||||||
})
|
})
|
||||||
.map(|v| *v)
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
ExprTerm::Json(_, vec2) => cmp_fn.cmp_json(vec1, vec2),
|
ExprTerm::Json(_, vec2) => cmp_fn.cmp_json(vec1, vec2),
|
||||||
};
|
};
|
||||||
@ -363,12 +363,7 @@ impl<'a> Into<ExprTerm<'a>> for &Vec<&'a Value> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_all_with_str<'a>(
|
fn walk_all_with_str<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) {
|
||||||
vec: &Vec<&'a Value>,
|
|
||||||
tmp: &mut Vec<&'a Value>,
|
|
||||||
key: &str,
|
|
||||||
is_filter: bool,
|
|
||||||
) {
|
|
||||||
if is_filter {
|
if is_filter {
|
||||||
walk(vec, tmp, &|v| match v {
|
walk(vec, tmp, &|v| match v {
|
||||||
Value::Object(map) if map.contains_key(key) => Some(vec![v]),
|
Value::Object(map) if map.contains_key(key) => Some(vec![v]),
|
||||||
@ -385,7 +380,7 @@ fn walk_all_with_str<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_all<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>) {
|
fn walk_all<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>) {
|
||||||
walk(vec, tmp, &|v| match v {
|
walk(vec, tmp, &|v| match v {
|
||||||
Value::Array(vec) => Some(vec.iter().collect()),
|
Value::Array(vec) => Some(vec.iter().collect()),
|
||||||
Value::Object(map) => {
|
Value::Object(map) => {
|
||||||
@ -399,7 +394,7 @@ fn walk_all<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk<'a, F>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>, fun: &F)
|
fn walk<'a, F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F)
|
||||||
where
|
where
|
||||||
F: Fn(&Value) -> Option<Vec<&Value>>,
|
F: Fn(&Value) -> Option<Vec<&Value>>,
|
||||||
{
|
{
|
||||||
@ -431,11 +426,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs_index(n: &isize, len: usize) -> usize {
|
fn abs_index(n: isize, len: usize) -> usize {
|
||||||
if n < &0_isize {
|
if n < 0_isize {
|
||||||
(n + len as isize) as usize
|
(n + len as isize) as usize
|
||||||
} else {
|
} else {
|
||||||
*n as usize
|
n as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +464,7 @@ impl fmt::Display for JsonPathError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, 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>,
|
||||||
@ -482,15 +477,7 @@ pub struct Selector<'a, 'b> {
|
|||||||
|
|
||||||
impl<'a, 'b> Selector<'a, 'b> {
|
impl<'a, 'b> Selector<'a, 'b> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Selector {
|
Selector::default()
|
||||||
node: None,
|
|
||||||
node_ref: None,
|
|
||||||
value: None,
|
|
||||||
tokens: Vec::new(),
|
|
||||||
terms: Vec::new(),
|
|
||||||
current: None,
|
|
||||||
selectors: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> {
|
pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> {
|
||||||
@ -500,7 +487,7 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
self.node_ref.take();
|
self.node_ref.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.node = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?);
|
self.node = Some(Parser::compile(path).map_err(JsonPathError::Path)?);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,8 +580,8 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn in_filter<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>) -> FilterKey>(&mut self, fun: F) {
|
fn in_filter<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>) -> FilterKey>(&mut self, fun: F) {
|
||||||
match self.terms.pop() {
|
if let Some(peek) = self.terms.pop() {
|
||||||
Some(peek) => match peek {
|
match peek {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
debug!("in_filter 1.: {:?}", v);
|
debug!("in_filter 1.: {:?}", v);
|
||||||
|
|
||||||
@ -616,8 +603,7 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp)));
|
self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,7 +658,7 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
for c in current {
|
for c in current {
|
||||||
if let Value::Array(vec) = c {
|
if let Value::Array(vec) = c {
|
||||||
let index = abs_index(&(index as isize), vec.len());
|
let index = abs_index(index as isize, vec.len());
|
||||||
if let Some(v) = c.get(index) {
|
if let Some(v) = c.get(index) {
|
||||||
tmp.push(v);
|
tmp.push(v);
|
||||||
}
|
}
|
||||||
@ -687,19 +673,16 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_from_current_with_str(&mut self, keys: &Vec<String>) {
|
fn next_from_current_with_str(&mut self, keys: &[String]) {
|
||||||
if let Some(current) = self.current.take() {
|
if let Some(current) = self.current.take() {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
for c in current {
|
for c in current {
|
||||||
match c {
|
if let Value::Object(map) = c {
|
||||||
Value::Object(map) => {
|
for key in keys {
|
||||||
for key in keys {
|
if let Some(v) = map.get(key) {
|
||||||
if let Some(v) = map.get(key) {
|
tmp.push(v)
|
||||||
tmp.push(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.current = Some(tmp);
|
self.current = Some(tmp);
|
||||||
@ -752,12 +735,8 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
debug!("all_from_current_with_str: {}, {:?}", key, self.current);
|
debug!("all_from_current_with_str: {}, {:?}", key, self.current);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|
||||||
fn visit_token(&mut self, token: &ParseToken) {
|
|
||||||
debug!("token: {:?}, stack: {:?}", token, self.tokens);
|
|
||||||
|
|
||||||
|
fn compute_absolute_path_filter(&mut self, token: &ParseToken) -> bool {
|
||||||
if !self.selectors.is_empty() {
|
if !self.selectors.is_empty() {
|
||||||
match token {
|
match token {
|
||||||
ParseToken::Absolute | ParseToken::Relative | ParseToken::Filter(_) => {
|
ParseToken::Absolute | ParseToken::Relative | ParseToken::Filter(_) => {
|
||||||
@ -781,240 +760,262 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|||||||
|
|
||||||
if let Some(selector) = self.selectors.last_mut() {
|
if let Some(selector) = self.selectors.last_mut() {
|
||||||
selector.visit_token(token);
|
selector.visit_token(token);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Selector<'a, 'b> {
|
||||||
|
fn visit_absolute(&mut self) {
|
||||||
|
if self.current.is_some() {
|
||||||
|
let mut selector = Selector::default();
|
||||||
|
|
||||||
|
if let Some(value) = self.value {
|
||||||
|
selector.value = Some(value);
|
||||||
|
selector.current = Some(vec![value]);
|
||||||
|
self.selectors.push(selector);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &self.value {
|
||||||
|
self.current = Some(vec![v]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_relative(&mut self) {
|
||||||
|
if let Some(ParseToken::Array) = self.tokens.last() {
|
||||||
|
let array_token = self.tokens.pop();
|
||||||
|
if let Some(ParseToken::Leaves) = self.tokens.last() {
|
||||||
|
self.tokens.pop();
|
||||||
|
self.all_from_current();
|
||||||
|
}
|
||||||
|
self.tokens.push(array_token.unwrap());
|
||||||
|
}
|
||||||
|
self.new_filter_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_array_eof(&mut self) {
|
||||||
|
if let Some(Some(e)) = self.terms.pop() {
|
||||||
|
match e {
|
||||||
|
ExprTerm::Number(n) => {
|
||||||
|
self.next_from_current_with_num(to_f64(&n));
|
||||||
|
}
|
||||||
|
ExprTerm::String(key) => {
|
||||||
|
self.next_from_current_with_str(&[key]);
|
||||||
|
}
|
||||||
|
ExprTerm::Json(_, v) => {
|
||||||
|
if v.is_empty() {
|
||||||
|
self.current = Some(vec![&Value::Null]);
|
||||||
|
} else {
|
||||||
|
self.current = Some(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprTerm::Bool(false) => {
|
||||||
|
self.current = Some(vec![&Value::Null]);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tokens.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_all(&mut self) {
|
||||||
|
if let Some(ParseToken::Array) = self.tokens.last() {
|
||||||
|
self.tokens.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.tokens.last() {
|
||||||
|
Some(ParseToken::Leaves) => {
|
||||||
|
self.tokens.pop();
|
||||||
|
self.all_from_current();
|
||||||
|
}
|
||||||
|
Some(ParseToken::In) => {
|
||||||
|
self.tokens.pop();
|
||||||
|
self.next_all_from_current();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.next_all_from_current();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_key(&mut self, key: &str) {
|
||||||
|
if let Some(ParseToken::Array) = self.tokens.last() {
|
||||||
|
self.terms.push(Some(ExprTerm::String(key.to_string())));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(t) = self.tokens.pop() {
|
||||||
|
if self.terms.is_empty() {
|
||||||
|
match t {
|
||||||
|
ParseToken::Leaves => self.all_from_current_with_str(key),
|
||||||
|
ParseToken::In => self.next_from_current_with_str(&[key.to_string()]),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match t {
|
||||||
|
ParseToken::Leaves => {
|
||||||
|
self.all_in_filter_with_str(key);
|
||||||
|
}
|
||||||
|
ParseToken::In => {
|
||||||
|
self.next_in_filter_with_str(key);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_keys(&mut self, keys: &[String]) {
|
||||||
|
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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_filter(&mut self, ft: &FilterToken) {
|
||||||
|
let right = match self.terms.pop() {
|
||||||
|
Some(Some(right)) => right,
|
||||||
|
Some(None) => ExprTerm::Json(
|
||||||
|
None,
|
||||||
|
match &self.current {
|
||||||
|
Some(current) => current.to_vec(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => panic!("empty term right"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let left = match self.terms.pop() {
|
||||||
|
Some(Some(left)) => left,
|
||||||
|
Some(None) => ExprTerm::Json(
|
||||||
|
None,
|
||||||
|
match &self.current {
|
||||||
|
Some(current) => current.to_vec(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => panic!("empty term left"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ret = None;
|
||||||
|
match ft {
|
||||||
|
FilterToken::Equal => left.eq(&right, &mut ret),
|
||||||
|
FilterToken::NotEqual => left.ne(&right, &mut ret),
|
||||||
|
FilterToken::Greater => left.gt(&right, &mut ret),
|
||||||
|
FilterToken::GreaterOrEqual => left.ge(&right, &mut ret),
|
||||||
|
FilterToken::Little => left.lt(&right, &mut ret),
|
||||||
|
FilterToken::LittleOrEqual => left.le(&right, &mut ret),
|
||||||
|
FilterToken::And => left.and(&right, &mut ret),
|
||||||
|
FilterToken::Or => left.or(&right, &mut ret),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(e) = ret {
|
||||||
|
self.terms.push(Some(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_range(&mut self, from: &Option<isize>, to: &Option<isize>, step: &Option<usize>) {
|
||||||
|
if !self.terms.is_empty() {
|
||||||
|
unimplemented!("range syntax in filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ParseToken::Array) = self.tokens.pop() {
|
||||||
|
let mut tmp = Vec::new();
|
||||||
|
if let Some(current) = &self.current {
|
||||||
|
for v in current {
|
||||||
|
if let Value::Array(vec) = v {
|
||||||
|
let from = if let Some(from) = from {
|
||||||
|
abs_index(*from, vec.len())
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let to = if let Some(to) = to {
|
||||||
|
abs_index(*to, vec.len())
|
||||||
|
} else {
|
||||||
|
vec.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in (from..to).step_by(match step {
|
||||||
|
Some(step) => *step,
|
||||||
|
_ => 1,
|
||||||
|
}) {
|
||||||
|
if let Some(v) = vec.get(i) {
|
||||||
|
tmp.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.current = Some(tmp);
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_union(&mut self, indices: &[isize]) {
|
||||||
|
if !self.terms.is_empty() {
|
||||||
|
unimplemented!("union syntax in filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ParseToken::Array) = self.tokens.pop() {
|
||||||
|
let mut tmp = Vec::new();
|
||||||
|
if let Some(current) = &self.current {
|
||||||
|
for v in current {
|
||||||
|
if let Value::Array(vec) = v {
|
||||||
|
for i in indices {
|
||||||
|
if let Some(v) = vec.get(abs_index(*i, vec.len())) {
|
||||||
|
tmp.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current = Some(tmp);
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||||
|
fn visit_token(&mut self, token: &ParseToken) {
|
||||||
|
debug!("token: {:?}, stack: {:?}", token, self.tokens);
|
||||||
|
|
||||||
|
if self.compute_absolute_path_filter(token) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
ParseToken::Absolute => {
|
ParseToken::Absolute => self.visit_absolute(),
|
||||||
if self.current.is_some() {
|
ParseToken::Relative => self.visit_relative(),
|
||||||
let mut selector = Selector::new();
|
|
||||||
|
|
||||||
if let Some(value) = self.value {
|
|
||||||
selector.value = Some(value);
|
|
||||||
selector.current = Some(vec![value]);
|
|
||||||
self.selectors.push(selector);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match &self.value {
|
|
||||||
Some(v) => self.current = Some(vec![v]),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseToken::Relative => {
|
|
||||||
if let Some(ParseToken::Array) = self.tokens.last() {
|
|
||||||
let array_token = self.tokens.pop();
|
|
||||||
if let Some(ParseToken::Leaves) = self.tokens.last() {
|
|
||||||
self.tokens.pop();
|
|
||||||
self.all_from_current();
|
|
||||||
}
|
|
||||||
self.tokens.push(array_token.unwrap());
|
|
||||||
}
|
|
||||||
self.new_filter_context();
|
|
||||||
}
|
|
||||||
ParseToken::In | ParseToken::Leaves | ParseToken::Array => {
|
ParseToken::In | ParseToken::Leaves | ParseToken::Array => {
|
||||||
self.tokens.push(token.clone());
|
self.tokens.push(token.clone());
|
||||||
}
|
}
|
||||||
ParseToken::ArrayEof => {
|
ParseToken::ArrayEof => self.visit_array_eof(),
|
||||||
if let Some(Some(e)) = self.terms.pop() {
|
ParseToken::All => self.visit_all(),
|
||||||
match e {
|
|
||||||
ExprTerm::Number(n) => {
|
|
||||||
self.next_from_current_with_num(to_f64(&n));
|
|
||||||
}
|
|
||||||
ExprTerm::String(key) => {
|
|
||||||
self.next_from_current_with_str(&vec![key]);
|
|
||||||
}
|
|
||||||
ExprTerm::Json(_, v) => {
|
|
||||||
if v.is_empty() {
|
|
||||||
self.current = Some(vec![&Value::Null]);
|
|
||||||
} else {
|
|
||||||
self.current = Some(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprTerm::Bool(false) => {
|
|
||||||
self.current = Some(vec![&Value::Null]);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tokens.pop();
|
|
||||||
}
|
|
||||||
ParseToken::All => {
|
|
||||||
match self.tokens.last() {
|
|
||||||
Some(ParseToken::Array) => {
|
|
||||||
self.tokens.pop();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.tokens.last() {
|
|
||||||
Some(ParseToken::Leaves) => {
|
|
||||||
self.tokens.pop();
|
|
||||||
self.all_from_current();
|
|
||||||
}
|
|
||||||
Some(ParseToken::In) => {
|
|
||||||
self.tokens.pop();
|
|
||||||
self.next_all_from_current();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.next_all_from_current();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseToken::Bool(b) => {
|
ParseToken::Bool(b) => {
|
||||||
self.terms.push(Some(ExprTerm::Bool(*b)));
|
self.terms.push(Some(ExprTerm::Bool(*b)));
|
||||||
}
|
}
|
||||||
ParseToken::Key(key) => {
|
ParseToken::Key(key) => self.visit_key(key),
|
||||||
if let Some(ParseToken::Array) = self.tokens.last() {
|
ParseToken::Keys(keys) => self.visit_keys(keys),
|
||||||
self.terms.push(Some(ExprTerm::String(key.clone())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.tokens.pop() {
|
|
||||||
Some(t) => {
|
|
||||||
if self.terms.is_empty() {
|
|
||||||
match t {
|
|
||||||
ParseToken::Leaves => self.all_from_current_with_str(key.as_str()),
|
|
||||||
ParseToken::In => {
|
|
||||||
self.next_from_current_with_str(&vec![key.clone()])
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match t {
|
|
||||||
ParseToken::Leaves => {
|
|
||||||
self.all_in_filter_with_str(key.as_str());
|
|
||||||
}
|
|
||||||
ParseToken::In => {
|
|
||||||
self.next_in_filter_with_str(key.as_str());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) => {
|
ParseToken::Number(v) => {
|
||||||
self.terms
|
self.terms
|
||||||
.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
||||||
}
|
}
|
||||||
ParseToken::Filter(ref ft) => {
|
ParseToken::Filter(ref ft) => self.visit_filter(ft),
|
||||||
let ref right = match self.terms.pop() {
|
ParseToken::Range(from, to, step) => self.visit_range(from, to, step),
|
||||||
Some(Some(right)) => right,
|
ParseToken::Union(indices) => self.visit_union(indices),
|
||||||
Some(None) => ExprTerm::Json(
|
|
||||||
None,
|
|
||||||
match &self.current {
|
|
||||||
Some(current) => current.to_vec(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_ => panic!("empty term right"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let left = match self.terms.pop() {
|
|
||||||
Some(Some(left)) => left,
|
|
||||||
Some(None) => ExprTerm::Json(
|
|
||||||
None,
|
|
||||||
match &self.current {
|
|
||||||
Some(current) => current.to_vec(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_ => panic!("empty term left"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut ret = None;
|
|
||||||
match ft {
|
|
||||||
FilterToken::Equal => left.eq(right, &mut ret),
|
|
||||||
FilterToken::NotEqual => left.ne(right, &mut ret),
|
|
||||||
FilterToken::Greater => left.gt(right, &mut ret),
|
|
||||||
FilterToken::GreaterOrEqual => left.ge(right, &mut ret),
|
|
||||||
FilterToken::Little => left.lt(right, &mut ret),
|
|
||||||
FilterToken::LittleOrEqual => left.le(right, &mut ret),
|
|
||||||
FilterToken::And => left.and(right, &mut ret),
|
|
||||||
FilterToken::Or => left.or(right, &mut ret),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(e) = ret {
|
|
||||||
self.terms.push(Some(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseToken::Range(from, to, step) => {
|
|
||||||
if !self.terms.is_empty() {
|
|
||||||
unimplemented!("range syntax in filter");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ParseToken::Array) = self.tokens.pop() {
|
|
||||||
let mut tmp = Vec::new();
|
|
||||||
if let Some(current) = &self.current {
|
|
||||||
for v in current {
|
|
||||||
if let Value::Array(vec) = v {
|
|
||||||
let from = if let Some(from) = from {
|
|
||||||
abs_index(from, vec.len())
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let to = if let Some(to) = to {
|
|
||||||
abs_index(to, vec.len())
|
|
||||||
} else {
|
|
||||||
vec.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in (from..to).step_by(match step {
|
|
||||||
Some(step) => *step,
|
|
||||||
_ => 1,
|
|
||||||
}) {
|
|
||||||
if let Some(v) = vec.get(i) {
|
|
||||||
tmp.push(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.current = Some(tmp);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseToken::Union(indices) => {
|
|
||||||
if !self.terms.is_empty() {
|
|
||||||
unimplemented!("union syntax in filter");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ParseToken::Array) = self.tokens.pop() {
|
|
||||||
let mut tmp = Vec::new();
|
|
||||||
if let Some(current) = &self.current {
|
|
||||||
for v in current {
|
|
||||||
if let Value::Array(vec) = v {
|
|
||||||
for i in indices {
|
|
||||||
if let Some(v) = vec.get(abs_index(i, vec.len())) {
|
|
||||||
tmp.push(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.current = Some(tmp);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseToken::Eof => {
|
ParseToken::Eof => {
|
||||||
debug!("visit_token eof");
|
debug!("visit_token eof");
|
||||||
}
|
}
|
||||||
@ -1022,6 +1023,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct SelectorMut {
|
pub struct SelectorMut {
|
||||||
path: Option<Node>,
|
path: Option<Node>,
|
||||||
value: Option<Value>,
|
value: Option<Value>,
|
||||||
@ -1072,14 +1074,11 @@ fn replace_value<F: FnMut(&Value) -> Value>(tokens: Vec<String>, value: &mut Val
|
|||||||
|
|
||||||
impl SelectorMut {
|
impl SelectorMut {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SelectorMut {
|
Self::default()
|
||||||
path: None,
|
|
||||||
value: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> {
|
pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> {
|
||||||
self.path = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?);
|
self.path = Some(Parser::compile(path).map_err(JsonPathError::Path)?);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,7 +1138,7 @@ impl SelectorMut {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
@ -1165,7 +1164,7 @@ impl SelectorMut {
|
|||||||
|
|
||||||
fn select(&self) -> Result<Vec<&Value>, JsonPathError> {
|
fn select(&self) -> Result<Vec<&Value>, JsonPathError> {
|
||||||
if let Some(node) = &self.path {
|
if let Some(node) = &self.path {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
selector.compiled_path(&node);
|
selector.compiled_path(&node);
|
||||||
|
|
||||||
if let Some(value) = &self.value {
|
if let Some(value) = &self.value {
|
||||||
|
@ -31,7 +31,7 @@ pub fn read_contents(path: &str) -> String {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
|
pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
let result = selector
|
let result = selector
|
||||||
.str_path(path)
|
.str_path(path)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -12,7 +12,7 @@ mod common;
|
|||||||
fn selector_mut() {
|
fn selector_mut() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
let mut selector_mut = SelectorMut::new();
|
let mut selector_mut = SelectorMut::default();
|
||||||
|
|
||||||
let mut nums = Vec::new();
|
let mut nums = Vec::new();
|
||||||
let result = selector_mut
|
let result = selector_mut
|
||||||
@ -37,7 +37,7 @@ fn selector_mut() {
|
|||||||
vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]
|
vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
let result = selector
|
let result = selector
|
||||||
.str_path(r#"$.store..price"#)
|
.str_path(r#"$.store..price"#)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -173,7 +173,7 @@ fn readme_selector() {
|
|||||||
{"name": "친구4"}
|
{"name": "친구4"}
|
||||||
]});
|
]});
|
||||||
|
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::default();
|
||||||
|
|
||||||
let result = selector
|
let result = selector
|
||||||
.str_path("$..[?(@.age >= 30)]")
|
.str_path("$..[?(@.age >= 30)]")
|
||||||
@ -211,7 +211,7 @@ fn readme_selector_mut() {
|
|||||||
{"name": "친구4"}
|
{"name": "친구4"}
|
||||||
]});
|
]});
|
||||||
|
|
||||||
let mut selector_mut = SelectorMut::new();
|
let mut selector_mut = SelectorMut::default();
|
||||||
|
|
||||||
let result = selector_mut
|
let result = selector_mut
|
||||||
.str_path("$..[?(@.age == 20)].age")
|
.str_path("$..[?(@.age == 20)].age")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user