mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-24 17:02:16 +00:00
refactoring done default
This commit is contained in:
parent
9a35357ddb
commit
d2a5d9092e
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
|||||||
.vscode
|
.vscode
|
||||||
!.idea/runConfigurations/
|
!.idea/runConfigurations/
|
||||||
/target/
|
/target/
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
callgrind.out.*
|
@ -32,5 +32,5 @@ name = "jsonpath_lib"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
#debug = true
|
debug = true
|
||||||
#lto = false
|
#lto = false
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
extern crate bencher;
|
||||||
|
extern crate indexmap;
|
||||||
extern crate jsonpath_lib as jsonpath;
|
extern crate jsonpath_lib as jsonpath;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
extern crate bencher;
|
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use self::test::Bencher;
|
use self::test::Bencher;
|
||||||
use jsonpath::ref_value::model::RefValue;
|
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||||
use serde::ser::Serialize;
|
use jsonpath::ref_value::ser::RefValueSerializer;
|
||||||
|
|
||||||
fn read_json(path: &str) -> String {
|
fn read_json(path: &str) -> String {
|
||||||
let mut f = std::fs::File::open(path).unwrap();
|
let mut f = std::fs::File::open(path).unwrap();
|
||||||
@ -107,22 +109,55 @@ fn bench_select_as(b: &mut Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_serde_ser(b: &mut Bencher) {
|
fn refval_de(b: &mut Bencher) {
|
||||||
let json = get_json();
|
let json = get_json();
|
||||||
|
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
for _ in 1..100 {
|
for _ in 1..100 {
|
||||||
let _: RefValue = json.serialize(jsonpath::ref_value::ser::Serializer).unwrap().into();
|
let _ = RefValue::deserialize(&json).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_serde_de(b: &mut Bencher) {
|
fn refval_se(b: &mut Bencher) {
|
||||||
let json_string = get_string();
|
let json = get_json();
|
||||||
let json_str = json_string.as_str();
|
b.iter(move || {
|
||||||
|
for _ in 1..100 {
|
||||||
|
let _ = &json.serialize(RefValueSerializer).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
b.iter(move || for _ in 1..100 {
|
#[bench]
|
||||||
let _: RefValue = serde_json::from_str(json_str).unwrap();
|
fn refval_refcopy(b: &mut Bencher) {
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
let json = get_json();
|
||||||
|
let ref_json: RefValue = json.serialize(RefValueSerializer).unwrap();
|
||||||
|
let store = ref_json.get("store".to_string()).unwrap();
|
||||||
|
let book = store.get("book".to_string()).unwrap();
|
||||||
|
|
||||||
|
b.iter(move || {
|
||||||
|
for _ in 1..100 {
|
||||||
|
if let RefValue::Array(vec) = book.deref() {
|
||||||
|
let _: Vec<RefValueWrapper> = vec.iter().map(|v| v.clone()).collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn refval_copy(b: &mut Bencher) {
|
||||||
|
|
||||||
|
let json = get_json();
|
||||||
|
let store = json.get("store".to_string()).unwrap();
|
||||||
|
let book = store.get("book".to_string()).unwrap();
|
||||||
|
|
||||||
|
b.iter(move || {
|
||||||
|
for _ in 1..100 {
|
||||||
|
if let Value::Array(vec) = book {
|
||||||
|
let _: Vec<Value> = vec.iter().map(|v| v.clone()).collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
81
benches/bench_example.rs
Normal file
81
benches/bench_example.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate bencher;
|
||||||
|
extern crate indexmap;
|
||||||
|
extern crate jsonpath_lib as jsonpath;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use self::test::Bencher;
|
||||||
|
|
||||||
|
fn read_json(path: &str) -> String {
|
||||||
|
let mut f = std::fs::File::open(path).unwrap();
|
||||||
|
let mut contents = String::new();
|
||||||
|
f.read_to_string(&mut contents).unwrap();
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_string() -> String {
|
||||||
|
read_json("./benches/example.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_json() -> Value {
|
||||||
|
let string = get_string();
|
||||||
|
serde_json::from_str(string.as_str()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_path(i: usize) -> &'static str {
|
||||||
|
let paths = vec![
|
||||||
|
"$.store.book[*].author", //0
|
||||||
|
"$..author", //1
|
||||||
|
"$.store.*", //2
|
||||||
|
"$.store..price", //3
|
||||||
|
"$..book[2]", //4
|
||||||
|
"$..book[-2]", //5
|
||||||
|
"$..book[0,1]", //6
|
||||||
|
"$..book[:2]", //7
|
||||||
|
"$..book[1:2]", //8
|
||||||
|
"$..book[-2:]", //9
|
||||||
|
"$..book[2:]", //10
|
||||||
|
"$..book[?(@.isbn)]", //11
|
||||||
|
"$.store.book[?(@.price < 10)]", //12
|
||||||
|
"$..*", //13
|
||||||
|
"$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]" //14
|
||||||
|
];
|
||||||
|
paths[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! example {
|
||||||
|
($name:ident, $i:expr) => {
|
||||||
|
#[bench]
|
||||||
|
fn $name(b: &mut Bencher) {
|
||||||
|
let json = get_json();
|
||||||
|
b.iter(move || {
|
||||||
|
for _ in 1..100 {
|
||||||
|
let _ = jsonpath::select(&json, get_path($i));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
example!(example0, 0);
|
||||||
|
example!(example1, 1);
|
||||||
|
example!(example2, 2);
|
||||||
|
example!(example3, 3);
|
||||||
|
example!(example4, 4);
|
||||||
|
example!(example5, 5);
|
||||||
|
example!(example6, 6);
|
||||||
|
example!(example7, 7);
|
||||||
|
example!(example8, 8);
|
||||||
|
example!(example9, 9);
|
||||||
|
example!(example10, 10);
|
||||||
|
example!(example11, 11);
|
||||||
|
example!(example12, 12);
|
||||||
|
example!(example13, 13);
|
||||||
|
example!(example14, 14);
|
9
profiling.sh
Executable file
9
profiling.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
valgrind \
|
||||||
|
--tool=callgrind \
|
||||||
|
--dump-instr=yes \
|
||||||
|
--collect-jumps=yes \
|
||||||
|
--simulate-cache=yes $1 -- $2
|
@ -1,4 +1,6 @@
|
|||||||
mod cmp;
|
mod cmp;
|
||||||
mod term;
|
mod term;
|
||||||
pub mod value_filter;
|
pub mod value_filter;
|
||||||
pub mod value_wrapper;
|
pub mod value_manager;
|
||||||
|
#[deprecated(since = "0.1.14", note = "Please use the value_manager module instead")]
|
||||||
|
pub use self::value_manager as value_wrapper;
|
@ -1,15 +1,18 @@
|
|||||||
use super::cmp::*;
|
use super::cmp::*;
|
||||||
use super::value_filter::ValueFilterKey;
|
use super::value_filter::ValueFilterKey;
|
||||||
use super::value_wrapper::*;
|
use super::value_manager::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use select::path_map::PathMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TermContext {
|
pub enum TermContext {
|
||||||
Constants(ExprTerm),
|
Constants(ExprTerm),
|
||||||
Json(Option<ValueFilterKey>, ValueWrapper),
|
Json(Option<ValueFilterKey>, ValueManager),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermContext {
|
impl TermContext {
|
||||||
fn cmp<F: PrivCmp + IntoType>(&self, other: &TermContext, cmp_fn: F, default: bool) -> TermContext {
|
fn cmp<F: PrivCmp + IntoType>(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext {
|
||||||
match self {
|
match self {
|
||||||
TermContext::Constants(et) => {
|
TermContext::Constants(et) => {
|
||||||
match other {
|
match other {
|
||||||
@ -17,9 +20,9 @@ impl TermContext {
|
|||||||
trace!("const-const");
|
trace!("const-const");
|
||||||
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default)))
|
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default)))
|
||||||
}
|
}
|
||||||
TermContext::Json(key, v) => {
|
TermContext::Json(ref mut key, ref mut v) => {
|
||||||
trace!("const-json");
|
trace!("const-json");
|
||||||
TermContext::Json(None, v.take_with(key, et, cmp_fn, true))
|
TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,24 +38,24 @@ impl TermContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let c = v.into_term(key);
|
let mut c = v.into_term(key);
|
||||||
let oc = ov.into_term(key_other);
|
let mut oc = ov.into_term(key_other);
|
||||||
if is_json(&c) && is_json(&oc) {
|
if is_json(&c) && is_json(&oc) {
|
||||||
v.cmp(&ov, cmp_fn.into_type())
|
v.cmp(&ov, cmp_fn.into_type())
|
||||||
} else {
|
} else {
|
||||||
c.cmp(&oc, cmp_fn, default)
|
c.cmp(&mut oc, cmp_fn, default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermContext::Constants(et) => {
|
TermContext::Constants(et) => {
|
||||||
trace!("json-const");
|
trace!("json-const");
|
||||||
TermContext::Json(None, v.take_with(key, et, cmp_fn, false))
|
TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext {
|
fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType, path_map: Arc<RefCell<PathMap>>) -> TermContext {
|
||||||
match self {
|
match self {
|
||||||
TermContext::Constants(et) => {
|
TermContext::Constants(et) => {
|
||||||
match other {
|
match other {
|
||||||
@ -67,7 +70,7 @@ impl TermContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermContext::Json(_, v) => {
|
TermContext::Json(_, v) => {
|
||||||
TermContext::Json(None, ValueWrapper::new(v.get_val().clone(), false))
|
TermContext::Json(None, ValueManager::new(v.get_val().clone(), false, path_map))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,49 +83,49 @@ impl TermContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
TermContext::Json(None, ValueWrapper::new(v.get_val().clone(), false))
|
TermContext::Json(None, ValueManager::new(v.get_val().clone(), false, path_map))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq(&self, other: &TermContext) -> TermContext {
|
pub fn eq(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("eq");
|
trace!("eq");
|
||||||
self.cmp(other, CmpEq, false)
|
self.cmp(other, CmpEq, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ne(&self, other: &TermContext) -> TermContext {
|
pub fn ne(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("ne");
|
trace!("ne");
|
||||||
self.cmp(other, CmpNe, true)
|
self.cmp(other, CmpNe, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gt(&self, other: &TermContext) -> TermContext {
|
pub fn gt(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("gt");
|
trace!("gt");
|
||||||
self.cmp(other, CmpGt, false)
|
self.cmp(other, CmpGt, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ge(&self, other: &TermContext) -> TermContext {
|
pub fn ge(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("ge");
|
trace!("ge");
|
||||||
self.cmp(other, CmpGe, false)
|
self.cmp(other, CmpGe, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lt(&self, other: &TermContext) -> TermContext {
|
pub fn lt(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("lt");
|
trace!("lt");
|
||||||
self.cmp(other, CmpLt, false)
|
self.cmp(other, CmpLt, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn le(&self, other: &TermContext) -> TermContext {
|
pub fn le(&mut self, other: &mut TermContext) -> TermContext {
|
||||||
trace!("le");
|
trace!("le");
|
||||||
self.cmp(other, CmpLe, false)
|
self.cmp(other, CmpLe, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and(&self, other: &TermContext) -> TermContext {
|
pub fn and(&mut self, other: &mut TermContext, path_map: Arc<RefCell<PathMap>>) -> TermContext {
|
||||||
self.cmp_cond(other, CmpCondType::And)
|
self.cmp_cond(other, CmpCondType::And, path_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn or(&self, other: &TermContext) -> TermContext {
|
pub fn or(&mut self, other: &mut TermContext, path_map: Arc<RefCell<PathMap>>) -> TermContext {
|
||||||
self.cmp_cond(other, CmpCondType::Or)
|
self.cmp_cond(other, CmpCondType::Or, path_map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,51 +1,14 @@
|
|||||||
use std::error::Error;
|
use std::cell::RefCell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::result::Result;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use filter::term::*;
|
use filter::term::*;
|
||||||
use filter::value_wrapper::*;
|
use filter::value_manager::*;
|
||||||
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
|
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
|
||||||
use ref_value::model::*;
|
use ref_value::model::*;
|
||||||
|
use select::path_map::PathMap;
|
||||||
trait ArrayIndex {
|
|
||||||
fn index(&self, v: &RefValueWrapper) -> usize;
|
|
||||||
|
|
||||||
fn take_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
|
|
||||||
let idx = self.index(v);
|
|
||||||
match v.get(idx) {
|
|
||||||
Some(v) => v.clone(),
|
|
||||||
_ => RefValue::Null.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArrayIndex for f64 {
|
|
||||||
fn index(&self, v: &RefValueWrapper) -> usize {
|
|
||||||
if v.is_array() && self < &0_f64 {
|
|
||||||
(v.as_array().unwrap().len() as f64 + self) as usize
|
|
||||||
} else {
|
|
||||||
*self as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArrayIndex for isize {
|
|
||||||
fn index(&self, v: &RefValueWrapper) -> usize {
|
|
||||||
if v.is_array() && self < &0_isize {
|
|
||||||
(v.as_array().unwrap().len() as isize + self) as usize
|
|
||||||
} else {
|
|
||||||
*self as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArrayIndex for usize {
|
|
||||||
fn index(&self, _: &RefValueWrapper) -> usize {
|
|
||||||
*self as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ValueFilterKey {
|
pub enum ValueFilterKey {
|
||||||
@ -54,248 +17,136 @@ pub enum ValueFilterKey {
|
|||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> Vec<RefValueWrapper> {
|
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<RefValueWrapper>) {
|
||||||
iter
|
|
||||||
.map(|v| v.clone())
|
|
||||||
.filter(|v| !v.is_null())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_nested_array<F: ArrayIndex>(v: &RefValueWrapper, key: F, filter_mode: bool) -> RefValueWrapper {
|
|
||||||
if v.is_array() && v.as_array().unwrap().get(key.index(v)).is_some() {
|
|
||||||
if filter_mode {
|
|
||||||
v.clone()
|
|
||||||
} else {
|
|
||||||
let idx = key.index(v);
|
|
||||||
v.get(idx).unwrap().clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key.take_value(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_nested_object(v: &RefValueWrapper, key: &String, filter_mode: bool) -> RefValueWrapper {
|
|
||||||
if v.is_object() && v.as_object().unwrap().contains_key(key) {
|
|
||||||
if filter_mode {
|
|
||||||
v.clone()
|
|
||||||
} else {
|
|
||||||
v.get(key.clone()).unwrap().clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RefValue::Null.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn traverse(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<RefValueWrapper>) {
|
|
||||||
match v.deref() {
|
match v.deref() {
|
||||||
RefValue::Array(vec) => {
|
RefValue::Array(vec) => {
|
||||||
if key.is_none() {
|
if key.is_none() {
|
||||||
for v in vec {
|
for v in vec.iter() {
|
||||||
buf.push(v.clone());
|
buf.push(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i in vec {
|
|
||||||
traverse(key, i, buf);
|
for v in vec {
|
||||||
|
collect_all(key, v, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefValue::Object(v) => {
|
RefValue::Object(map) => {
|
||||||
for (k, v) in v.into_iter() {
|
if let Some(k) = key {
|
||||||
if match key {
|
if let Some(val) = map.get(k) {
|
||||||
Some(map_key) => map_key == k,
|
buf.push(val.clone());
|
||||||
_ => true
|
|
||||||
} {
|
|
||||||
buf.push(v.clone());
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let mut c = map.values().map(|v| v.clone()).collect();
|
||||||
|
buf.append(&mut c);
|
||||||
}
|
}
|
||||||
for (_, v) in v.into_iter() {
|
for (_, v) in map {
|
||||||
traverse(key, v, buf);
|
collect_all(key, v, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_all(key: Option<&String>, v: &RefValueWrapper) -> Vec<RefValueWrapper> {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
traverse(key, v, &mut buf);
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ValueFilter {
|
pub struct ValueFilter {
|
||||||
val_wrapper: ValueWrapper,
|
value_mgr: ValueManager,
|
||||||
last_key: Option<ValueFilterKey>,
|
last_key: Option<ValueFilterKey>,
|
||||||
filter_mode: bool,
|
is_relative: bool,
|
||||||
|
path_map: Arc<RefCell<PathMap>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueFilter {
|
impl ValueFilter {
|
||||||
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
|
pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool, path_map: Arc<RefCell<PathMap>>) -> Self {
|
||||||
ValueFilter { val_wrapper: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
ValueFilter {
|
||||||
|
value_mgr: ValueManager::new(v, is_leaves, path_map.clone()),
|
||||||
|
last_key: None,
|
||||||
|
is_relative,
|
||||||
|
path_map,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_leaves(&mut self, key: Option<&String>) {
|
fn step_leaves(&mut self, key: Option<&String>) {
|
||||||
let buf = collect_all(key, &self.val_wrapper.get_val());
|
let mut buf = Vec::new();
|
||||||
|
collect_all(key, &self.value_mgr.get_val(), &mut buf);
|
||||||
trace!("step_leaves - {:?}", buf);
|
trace!("step_leaves - {:?}", buf);
|
||||||
self.val_wrapper = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
self.value_mgr = ValueManager::new(RefValue::Array(buf).into(), true, self.path_map.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_leaves_all(&mut self) -> &ValueWrapper {
|
pub fn step_leaves_all(&mut self) -> &ValueManager {
|
||||||
debug!("step_leaves_all");
|
debug!("step_leaves_all");
|
||||||
self.step_leaves(None);
|
self.step_leaves(None);
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
&self.val_wrapper
|
&self.value_mgr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_leaves_str(&mut self, key: &str) -> &ValueWrapper {
|
pub fn step_leaves_str(&mut self, key: &str) -> &ValueManager {
|
||||||
self.step_leaves_string(&key.to_string())
|
self.step_leaves_string(&key.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_leaves_string(&mut self, key: &String) -> &ValueManager {
|
||||||
debug!("step_leaves_string");
|
debug!("step_leaves_string");
|
||||||
self.step_leaves(Some(key));
|
self.step_leaves(Some(key));
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
&self.val_wrapper
|
&self.value_mgr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
pub fn step_in_all(&mut self) -> &ValueManager {
|
||||||
debug!("step_in_all");
|
debug!("step_in_all");
|
||||||
|
|
||||||
let vec = match self.val_wrapper.get_val().deref() {
|
|
||||||
RefValue::Object(ref map) => {
|
|
||||||
iter_to_value_vec(map.values())
|
|
||||||
}
|
|
||||||
RefValue::Array(ref list) => {
|
|
||||||
iter_to_value_vec(list.iter())
|
|
||||||
}
|
|
||||||
RefValue::Null => Vec::new(),
|
|
||||||
_ => vec![self.val_wrapper.get_val().clone()]
|
|
||||||
};
|
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
self.val_wrapper.replace(RefValue::Array(vec).into());
|
self.value_mgr.replace(self.value_mgr.get_as_array());
|
||||||
trace!("step_in_all - {:?}", self.val_wrapper.get_val());
|
trace!("step_in_all - {:?}", self.value_mgr.get_val());
|
||||||
&self.val_wrapper
|
&self.value_mgr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
|
pub fn step_in_num(&mut self, key: &f64) -> &ValueManager {
|
||||||
debug!("step_in_num");
|
debug!("step_in_num");
|
||||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||||
, self.val_wrapper.is_leaves()
|
, self.value_mgr.is_leaves()
|
||||||
, self.filter_mode
|
, self.is_relative
|
||||||
, self.val_wrapper.get_val());
|
, self.value_mgr.get_val());
|
||||||
|
|
||||||
let v = if self.val_wrapper.is_leaves() {
|
|
||||||
let filter_mode = self.filter_mode;
|
|
||||||
match self.val_wrapper.get_val().deref() {
|
|
||||||
RefValue::Array(ref vec) => {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
for v in vec {
|
|
||||||
let wrapper = get_nested_array(v, *key, filter_mode);
|
|
||||||
if !wrapper.is_null() {
|
|
||||||
ret.push(wrapper.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RefValue::Array(ret).into()
|
|
||||||
}
|
|
||||||
_ => key.take_value(&self.val_wrapper.get_val())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key.take_value(&self.val_wrapper.get_val())
|
|
||||||
};
|
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
self.last_key = Some(ValueFilterKey::Num(self.value_mgr.get_index(*key)));
|
||||||
self.val_wrapper.replace(v);
|
let v = self.value_mgr.get_with_num(key, self.is_relative);
|
||||||
trace!("step_in_num - after: {:?}", self.val_wrapper.get_val());
|
self.value_mgr.replace(v);
|
||||||
&self.val_wrapper
|
trace!("step_in_num - after: {:?}", self.value_mgr.get_val());
|
||||||
|
&self.value_mgr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_str(&mut self, key: &str) -> &ValueWrapper {
|
pub fn step_in_str(&mut self, key: &str) -> &ValueManager {
|
||||||
self.step_in_string(&key.to_string())
|
self.step_in_string(&key.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_in_string(&mut self, key: &String) -> &ValueManager {
|
||||||
debug!("step_in_string");
|
debug!("step_in_string");
|
||||||
trace!("step_in_string - before: {},{},{:?}"
|
trace!("step_in_string - before: {},{},{:?}"
|
||||||
, self.val_wrapper.is_leaves()
|
, self.value_mgr.is_leaves()
|
||||||
, self.filter_mode
|
, self.is_relative
|
||||||
, self.val_wrapper.get_val());
|
, self.value_mgr.get_val());
|
||||||
|
|
||||||
let filter_mode = self.filter_mode;
|
|
||||||
let is_leaves = self.val_wrapper.is_leaves();
|
|
||||||
let val = match self.val_wrapper.get_val().deref() {
|
|
||||||
RefValue::Array(ref vec) if is_leaves => {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
for v in vec {
|
|
||||||
if v.is_array() {
|
|
||||||
let vec = v.as_array().unwrap();
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
for v in vec {
|
|
||||||
let nested_wrapper = get_nested_object(v, key, filter_mode);
|
|
||||||
if !nested_wrapper.is_null() {
|
|
||||||
ret.push(nested_wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.append(&mut ret);
|
|
||||||
} else if v.is_object() {
|
|
||||||
let nested_wrapper = get_nested_object(v, key, filter_mode);
|
|
||||||
if !nested_wrapper.is_null() {
|
|
||||||
buf.push(nested_wrapper);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match v.get(key.clone()) {
|
|
||||||
Some(v) => buf.push(v.clone()),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RefValue::Array(buf).into()
|
|
||||||
}
|
|
||||||
RefValue::Array(ref vec) if !is_leaves => {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
for v in vec {
|
|
||||||
let wrapper = get_nested_object(v, key, filter_mode);
|
|
||||||
if !wrapper.is_null() {
|
|
||||||
ret.push(wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RefValue::Array(ret).into()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
match self.val_wrapper.get_val().get(key.clone()) {
|
|
||||||
Some(v) => v.clone(),
|
|
||||||
_ => RefValue::Null.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
self.val_wrapper.replace(val);
|
self.value_mgr.replace(self.value_mgr.get_with_str(key, self.is_relative));
|
||||||
trace!("step_in_string - after: {},{},{:?}"
|
trace!("step_in_string - after: {},{},{:?}"
|
||||||
, self.val_wrapper.is_leaves()
|
, self.value_mgr.is_leaves()
|
||||||
, self.filter_mode
|
, self.is_relative
|
||||||
, self.val_wrapper.get_val());
|
, self.value_mgr.get_val());
|
||||||
&self.val_wrapper
|
&self.value_mgr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct JsonValueFilter {
|
pub struct JsonValueFilter {
|
||||||
json: RefValueWrapper,
|
json: RefValueWrapper,
|
||||||
|
path_map: Arc<RefCell<PathMap>>,
|
||||||
filter_stack: Vec<ValueFilter>,
|
filter_stack: Vec<ValueFilter>,
|
||||||
token_stack: Vec<ParseToken>,
|
token_stack: Vec<ParseToken>,
|
||||||
term_stack: Vec<TermContext>,
|
term_stack: Vec<TermContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsonValueFilter {
|
impl JsonValueFilter {
|
||||||
pub fn new(json: &str) -> Result<Self, String> {
|
pub fn new(json: RefValueWrapper, path_map: Arc<RefCell<PathMap>>) -> Self {
|
||||||
let json: RefValue = serde_json::from_str(json)
|
|
||||||
.map_err(|e| e.description().to_string())?;
|
|
||||||
Ok(JsonValueFilter::new_from_value(json.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_value(json: RefValueWrapper) -> Self {
|
|
||||||
JsonValueFilter {
|
JsonValueFilter {
|
||||||
json,
|
json,
|
||||||
|
path_map,
|
||||||
filter_stack: Vec::new(),
|
filter_stack: Vec::new(),
|
||||||
token_stack: Vec::new(),
|
token_stack: Vec::new(),
|
||||||
term_stack: Vec::new(),
|
term_stack: Vec::new(),
|
||||||
@ -303,90 +154,86 @@ impl JsonValueFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_peek_token_array(&self) -> bool {
|
fn is_peek_token_array(&self) -> bool {
|
||||||
if let Some(ParseToken::Array) = self.token_stack.last() {
|
if let Some(ParseToken::Array) = self.token_stack.last() { true } else { false }
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_value_filter(&mut self, from_current: bool) {
|
fn create_new_filter(&mut self, is_relative: bool) {
|
||||||
if from_current {
|
if is_relative {
|
||||||
self.filter_stack.last()
|
self.filter_stack.last()
|
||||||
.map(|vf| {
|
.map(|vf| {
|
||||||
ValueFilter::new(vf.val_wrapper.get_val().clone(), vf.val_wrapper.is_leaves(), from_current)
|
ValueFilter::new(vf.value_mgr.get_val().clone(),
|
||||||
|
vf.value_mgr.is_leaves(),
|
||||||
|
is_relative,
|
||||||
|
self.path_map.clone(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.and_then(|vf| {
|
.and_then(|vf| {
|
||||||
Some(self.filter_stack.push(vf))
|
Some(self.filter_stack.push(vf))
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.filter_stack.push({
|
let vf = ValueFilter::new(
|
||||||
ValueFilter::new(self.json.clone(), false, from_current)
|
self.json.clone(),
|
||||||
});
|
false,
|
||||||
|
is_relative,
|
||||||
|
self.path_map.clone(),
|
||||||
|
);
|
||||||
|
self.filter_stack.push(vf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_filter_stack(&mut self, v: RefValueWrapper, is_leaves: bool) {
|
fn append_to_current_filter(&mut self, v: RefValueWrapper, is_leaves: bool) {
|
||||||
if self.filter_stack.is_empty() {
|
if self.filter_stack.is_empty() {
|
||||||
self.filter_stack.push(ValueFilter::new(v, is_leaves, false));
|
self.filter_stack.push(ValueFilter::new(
|
||||||
} else {
|
v,
|
||||||
match self.filter_stack.last_mut() {
|
is_leaves,
|
||||||
Some(vf) => {
|
false,
|
||||||
vf.val_wrapper.set_leaves(is_leaves);
|
self.path_map.clone(),
|
||||||
if v.is_null() {
|
));
|
||||||
vf.val_wrapper.replace(v);
|
return;
|
||||||
} else if v.is_array() && v.as_array().unwrap().is_empty() {
|
}
|
||||||
vf.val_wrapper.replace(RefValue::Null.into());
|
|
||||||
} else if vf.val_wrapper.is_array() {
|
match self.filter_stack.last_mut() {
|
||||||
vf.val_wrapper.replace(v);
|
Some(vf) => {
|
||||||
}
|
vf.value_mgr.set_leaves(is_leaves);
|
||||||
|
if v.is_null() || v.is_empty() {
|
||||||
|
vf.value_mgr.replace(RefValue::Null.into());
|
||||||
|
} else if vf.value_mgr.is_array() {
|
||||||
|
vf.value_mgr.replace(v);
|
||||||
|
} else {
|
||||||
|
// ignore. the current filter context is object that include v: RefValueWrapper as a child.
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_value(&self) -> Value {
|
pub fn into_value(&self) -> Value {
|
||||||
match self.filter_stack.last() {
|
match self.filter_stack.last() {
|
||||||
Some(v) => v.val_wrapper.into_value(),
|
Some(v) => v.value_mgr.into_value(),
|
||||||
_ => Value::Null
|
_ => Value::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated(since = "0.1.14", note = "Please use the clone_value function instead")]
|
||||||
pub fn take_value(&mut self) -> RefValueWrapper {
|
pub fn take_value(&mut self) -> RefValueWrapper {
|
||||||
match self.filter_stack.last_mut() {
|
self.clone_value()
|
||||||
Some(v) => v.val_wrapper.get_val().clone(),
|
}
|
||||||
|
|
||||||
|
pub fn clone_value(&mut self) -> RefValueWrapper {
|
||||||
|
match self.filter_stack.last() {
|
||||||
|
Some(v) => v.value_mgr.get_val().clone(),
|
||||||
_ => RefValue::Null.into()
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_union<F: ArrayIndex>(&mut self, indices: Vec<F>) {
|
fn token_union(&mut self, indices: Vec<isize>) {
|
||||||
self.token_stack.pop();
|
self.token_stack.pop();
|
||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
Some(vf) => {
|
||||||
let mut ret = Vec::new();
|
if let Some(vec) = vf.value_mgr.pick_with_nums(indices) {
|
||||||
if let RefValue::Array(val) = vf.val_wrapper.get_val().deref() {
|
vf.value_mgr.replace(vec);
|
||||||
for v in val {
|
|
||||||
for i in &indices {
|
|
||||||
let v = i.take_value(v);
|
|
||||||
if !v.is_null() {
|
|
||||||
ret.push(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vf.val_wrapper.replace(RefValue::Array(ret).into());
|
|
||||||
}
|
|
||||||
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
for i in indices {
|
|
||||||
let wrapper = i.take_value(&vf.val_wrapper.get_val());
|
|
||||||
if !wrapper.is_null() {
|
|
||||||
ret.push(wrapper.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vf.val_wrapper.replace(RefValue::Array(ret).into());
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -395,50 +242,11 @@ impl JsonValueFilter {
|
|||||||
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
|
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
|
||||||
self.token_stack.pop();
|
self.token_stack.pop();
|
||||||
|
|
||||||
fn _from_to<F: ArrayIndex>(from: Option<F>, to: Option<F>, val: &RefValueWrapper) -> (usize, usize) {
|
|
||||||
let from = match from {
|
|
||||||
Some(v) => v.index(val),
|
|
||||||
_ => 0
|
|
||||||
};
|
|
||||||
let to = match to {
|
|
||||||
Some(v) => v.index(val),
|
|
||||||
_ => {
|
|
||||||
if let RefValue::Array(v) = val.deref() {
|
|
||||||
v.len()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(from, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<RefValueWrapper> {
|
|
||||||
trace!("range - {}:{}", from, to);
|
|
||||||
|
|
||||||
(from..to).into_iter()
|
|
||||||
.map(|i| i.take_value(v))
|
|
||||||
.filter(|v| !v.is_null())
|
|
||||||
.map(|v| v.clone())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
Some(ref mut vf) => {
|
||||||
let mut buf = Vec::new();
|
if let Some(vec) = vf.value_mgr.range_with(from, to) {
|
||||||
if let RefValue::Array(vec) = vf.val_wrapper.get_val().deref() {
|
vf.value_mgr.replace(vec);
|
||||||
for v in vec {
|
|
||||||
let (from, to) = _from_to(from, to, v);
|
|
||||||
let mut v: Vec<RefValueWrapper> = _range(from, to, v);
|
|
||||||
buf.append(&mut v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vf.val_wrapper.replace(RefValue::Array(buf).into());
|
|
||||||
}
|
|
||||||
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
|
|
||||||
let (from, to) = _from_to(from, to, &vf.val_wrapper.get_val());
|
|
||||||
let vec: Vec<RefValueWrapper> = _range(from, to, vf.val_wrapper.get_val());
|
|
||||||
vf.val_wrapper.replace(RefValue::Array(vec).into());
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -494,21 +302,25 @@ impl JsonValueFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(TermContext::Constants(ExprTerm::Bool(false))) => {
|
Some(TermContext::Constants(ExprTerm::Bool(false))) => {
|
||||||
self.replace_filter_stack(RefValue::Null.into(), false);
|
self.append_to_current_filter(RefValue::Null.into(), false);
|
||||||
}
|
}
|
||||||
Some(TermContext::Json(_, vw)) => {
|
Some(TermContext::Json(_, vw)) => {
|
||||||
self.replace_filter_stack(vw.get_val().clone(), vw.is_leaves());
|
self.append_to_current_filter(vw.get_val().clone(), vw.is_leaves());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
||||||
|
//
|
||||||
|
// None, TermContext::Constants(ExprTerm::Bool(true))
|
||||||
|
//
|
||||||
|
|
||||||
match self.filter_stack.pop() {
|
match self.filter_stack.pop() {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
let is_leaves = vf.val_wrapper.is_leaves();
|
match vf.value_mgr.get_val().deref() {
|
||||||
match vf.val_wrapper.get_val().deref() {
|
|
||||||
RefValue::Null | RefValue::Bool(false) => {
|
RefValue::Null | RefValue::Bool(false) => {
|
||||||
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
|
self.append_to_current_filter(RefValue::Null.into(), vf.value_mgr.is_leaves());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.replace_filter_stack(vf.val_wrapper.get_val().clone(), is_leaves);
|
self.append_to_current_filter(vf.value_mgr.get_val().clone(), vf.value_mgr.is_leaves());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,18 +338,18 @@ impl JsonValueFilter {
|
|||||||
trace!("right {:?}", right);
|
trace!("right {:?}", right);
|
||||||
|
|
||||||
if left.is_some() && right.is_some() {
|
if left.is_some() && right.is_some() {
|
||||||
let left = left.unwrap();
|
let mut left = left.unwrap();
|
||||||
let right = right.unwrap();
|
let mut right = right.unwrap();
|
||||||
|
|
||||||
let tc = match ft {
|
let tc = match ft {
|
||||||
FilterToken::Equal => left.eq(&right),
|
FilterToken::Equal => left.eq(&mut right),
|
||||||
FilterToken::NotEqual => left.ne(&right),
|
FilterToken::NotEqual => left.ne(&mut right),
|
||||||
FilterToken::Greater => left.gt(&right),
|
FilterToken::Greater => left.gt(&mut right),
|
||||||
FilterToken::GreaterOrEqual => left.ge(&right),
|
FilterToken::GreaterOrEqual => left.ge(&mut right),
|
||||||
FilterToken::Little => left.lt(&right),
|
FilterToken::Little => left.lt(&mut right),
|
||||||
FilterToken::LittleOrEqual => left.le(&right),
|
FilterToken::LittleOrEqual => left.le(&mut right),
|
||||||
FilterToken::And => left.and(&right),
|
FilterToken::And => left.and(&mut right, self.path_map.clone()),
|
||||||
FilterToken::Or => left.or(&right),
|
FilterToken::Or => left.or(&mut right, self.path_map.clone()),
|
||||||
};
|
};
|
||||||
self.term_stack.push(tc);
|
self.term_stack.push(tc);
|
||||||
}
|
}
|
||||||
@ -556,7 +368,7 @@ impl NodeVisitor for JsonValueFilter {
|
|||||||
if self.is_peek_token_array() {
|
if self.is_peek_token_array() {
|
||||||
self.token_stack.pop();
|
self.token_stack.pop();
|
||||||
}
|
}
|
||||||
self.push_value_filter(ParseToken::Relative == token);
|
self.create_new_filter(ParseToken::Relative == token);
|
||||||
}
|
}
|
||||||
ParseToken::In
|
ParseToken::In
|
||||||
| ParseToken::Leaves => {
|
| ParseToken::Leaves => {
|
||||||
@ -609,7 +421,7 @@ impl NodeVisitor for JsonValueFilter {
|
|||||||
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
||||||
match self.filter_stack.pop() {
|
match self.filter_stack.pop() {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
self.term_stack.push(TermContext::Json(vf.last_key, vf.val_wrapper));
|
self.term_stack.push(TermContext::Json(vf.last_key, vf.value_mgr));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
524
src/filter/value_manager.rs
Normal file
524
src/filter/value_manager.rs
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use ref_value::model::*;
|
||||||
|
use select::path_map::PathMap;
|
||||||
|
|
||||||
|
use super::cmp::*;
|
||||||
|
use super::term::*;
|
||||||
|
use super::value_filter::*;
|
||||||
|
|
||||||
|
pub trait ArrayIndex {
|
||||||
|
fn index(&self, v: &RefValueWrapper) -> usize;
|
||||||
|
|
||||||
|
fn ref_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
|
||||||
|
let idx = self.index(v);
|
||||||
|
match v.get(idx) {
|
||||||
|
Some(v) => v.clone(),
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayIndex for f64 {
|
||||||
|
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||||
|
if v.is_array() && self < &0_f64 {
|
||||||
|
(v.len() as f64 + self) as usize
|
||||||
|
} else {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayIndex for isize {
|
||||||
|
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||||
|
if v.is_array() && self < &0_isize {
|
||||||
|
(v.len() as isize + self) as usize
|
||||||
|
} else {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayIndex for usize {
|
||||||
|
fn index(&self, _: &RefValueWrapper) -> usize {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
||||||
|
match val.deref() {
|
||||||
|
RefValue::Bool(ref v1) => {
|
||||||
|
match et {
|
||||||
|
ExprTerm::Bool(v2) => if reverse {
|
||||||
|
cmp_fn.cmp_bool(v2, v1)
|
||||||
|
} else {
|
||||||
|
cmp_fn.cmp_bool(v1, v2)
|
||||||
|
},
|
||||||
|
_ => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RefValue::Number(ref v1) => match et {
|
||||||
|
ExprTerm::Number(v2) => if reverse {
|
||||||
|
cmp_fn.cmp_f64(v2, &v1.as_f64().unwrap())
|
||||||
|
} else {
|
||||||
|
cmp_fn.cmp_f64(&v1.as_f64().unwrap(), v2)
|
||||||
|
},
|
||||||
|
_ => default
|
||||||
|
},
|
||||||
|
RefValue::String(ref v1) => {
|
||||||
|
match et {
|
||||||
|
ExprTerm::String(v2) => if reverse {
|
||||||
|
cmp_fn.cmp_string(v2, v1)
|
||||||
|
} else {
|
||||||
|
cmp_fn.cmp_string(v1, v2)
|
||||||
|
},
|
||||||
|
_ => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_not_null<'a,
|
||||||
|
I: Iterator<Item=&'a RefValueWrapper>,
|
||||||
|
F: FnMut(&RefValueWrapper) -> RefValueWrapper>(iter: I, func: F) -> Vec<RefValueWrapper>
|
||||||
|
{
|
||||||
|
iter.map(func)
|
||||||
|
.filter(|v| !v.is_null())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_some<'a,
|
||||||
|
I: Iterator<Item=&'a RefValueWrapper>,
|
||||||
|
F: FnMut(&RefValueWrapper) -> Option<RefValueWrapper>>(iter: I, func: F) -> Vec<RefValueWrapper>
|
||||||
|
{
|
||||||
|
iter.map(func)
|
||||||
|
.filter(|v| v.is_some())
|
||||||
|
.map(|v| v.unwrap())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_in_array<I: ArrayIndex>(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option<RefValueWrapper> {
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Array(vec) if vec.get(key.index(v)).is_some() => {
|
||||||
|
Some(if is_relative { v.clone() } else { v.get(key.index(v)).unwrap().clone() })
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_in_object(v: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Object(map) if map.contains_key(key) => {
|
||||||
|
Some(if is_relative { v.clone() } else { v.get(key.to_string()).unwrap().clone() })
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_in_nested_array<I: ArrayIndex>(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option<RefValueWrapper> {
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
let ret = collect_some(vec.iter(), |v| { get_in_array(v, key, is_relative) });
|
||||||
|
Some(RefValue::Array(ret).into())
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_object_in_array(val: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||||
|
match val.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
let ret = collect_some(vec.iter(), |v| get_in_object(v, key, is_relative));
|
||||||
|
Some(RefValue::Array(ret).into())
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_in_nested_object(val: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||||
|
match val.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
let ret = vec.iter()
|
||||||
|
.map(|v| {
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
Some(collect_some(vec.iter(), |v| get_in_object(v, key, is_relative)))
|
||||||
|
}
|
||||||
|
RefValue::Object(_) => {
|
||||||
|
match get_in_object(v, key, is_relative) {
|
||||||
|
Some(v) => Some(vec![v]),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(|v| v.is_some())
|
||||||
|
.map(|v| v.unwrap())
|
||||||
|
.filter(|v| !v.is_empty())
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
Some(RefValue::Array(ret).into())
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(since = "0.1.14", note = "Please use the ValueManager instead")]
|
||||||
|
pub type ValueWrapper = ValueManager;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ValueManager {
|
||||||
|
val: RefValueWrapper,
|
||||||
|
path_map: Arc<RefCell<PathMap>>,
|
||||||
|
is_leaves: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueManager {
|
||||||
|
pub fn new(val: RefValueWrapper, is_leaves: bool, path_map: Arc<RefCell<PathMap>>) -> Self {
|
||||||
|
ValueManager { val, is_leaves, path_map }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_leaves(&self) -> bool {
|
||||||
|
self.is_leaves
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_leaves(&mut self, is_leaves: bool) {
|
||||||
|
self.is_leaves = is_leaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmp(&self, other: &Self, cmp_type: CmpType) -> TermContext {
|
||||||
|
match cmp_type {
|
||||||
|
CmpType::Eq => {
|
||||||
|
TermContext::Json(None, self.intersect(other))
|
||||||
|
}
|
||||||
|
CmpType::Ne => {
|
||||||
|
TermContext::Json(None, self.except(other))
|
||||||
|
}
|
||||||
|
CmpType::Gt | CmpType::Ge | CmpType::Lt | CmpType::Le => {
|
||||||
|
TermContext::Constants(ExprTerm::Bool(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_compare_with<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
|
||||||
|
match self.val.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
let mut set = IndexSet::new();
|
||||||
|
for v in vec {
|
||||||
|
if let Some(ValueFilterKey::String(key)) = key {
|
||||||
|
if let Some(ret_v) = get_in_object(v, key, false) {
|
||||||
|
if cmp_with_term(&ret_v, et, &cmp, false, reverse) {
|
||||||
|
set.insert(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if cmp_with_term(v, et, &cmp, false, reverse) {
|
||||||
|
set.insert(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = set.into_iter().collect();
|
||||||
|
Self::new(
|
||||||
|
RefValue::Array(ret).into(),
|
||||||
|
false,
|
||||||
|
self.path_map.clone())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if cmp_with_term(&self.val, et, &cmp, false, reverse) {
|
||||||
|
Self::new(self.val.clone(), false, self.path_map.clone())
|
||||||
|
} else {
|
||||||
|
Self::new(RefValue::Null.into(), false, self.path_map.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_index<I: ArrayIndex>(&self, i: I) -> usize {
|
||||||
|
i.index(&self.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_num<I: ArrayIndex>(&self, key: &I, is_relative: bool) -> RefValueWrapper {
|
||||||
|
if self.val.is_array() && self.is_leaves {
|
||||||
|
match get_in_nested_array(&self.val, key, is_relative) {
|
||||||
|
Some(v) => v,
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key.ref_value(&self.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_as_array(&self) -> RefValueWrapper {
|
||||||
|
let vec = match self.val.deref() {
|
||||||
|
RefValue::Object(ref map) => {
|
||||||
|
collect_not_null(map.values(), |v| v.clone())
|
||||||
|
}
|
||||||
|
RefValue::Array(ref vec) => {
|
||||||
|
vec.clone()
|
||||||
|
}
|
||||||
|
RefValue::Null => Vec::new(),
|
||||||
|
_ => vec![self.val.clone()]
|
||||||
|
};
|
||||||
|
RefValue::Array(vec).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_str(&self, key: &String, is_relative: bool) -> RefValueWrapper {
|
||||||
|
if self.val.is_array() && self.is_leaves {
|
||||||
|
match get_in_nested_object(&self.val, key, is_relative) {
|
||||||
|
Some(v) => v,
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
} else if self.val.is_array() && !self.is_leaves {
|
||||||
|
match get_object_in_array(&self.val, key, is_relative) {
|
||||||
|
Some(v) => v,
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.val.get(key.clone()) {
|
||||||
|
Some(v) => v.clone(),
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn range_with(&self, from: Option<isize>, to: Option<isize>) -> Option<RefValueWrapper> {
|
||||||
|
fn _from<F: ArrayIndex>(from: Option<F>, val: &RefValueWrapper) -> usize {
|
||||||
|
match from {
|
||||||
|
Some(v) => v.index(val),
|
||||||
|
_ => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _to<F: ArrayIndex>(to: Option<F>, val: &RefValueWrapper) -> usize {
|
||||||
|
match to {
|
||||||
|
Some(v) => v.index(val),
|
||||||
|
_ => {
|
||||||
|
if let RefValue::Array(v) = val.deref() {
|
||||||
|
v.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<RefValueWrapper> {
|
||||||
|
trace!("range - {}:{}", from, to);
|
||||||
|
|
||||||
|
(from..to).into_iter()
|
||||||
|
.map(|i| i.ref_value(v))
|
||||||
|
.filter(|v| !v.is_null())
|
||||||
|
.map(|v| v.clone())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let RefValue::Array(vec) = &self.val.deref() {
|
||||||
|
let ret = if self.is_leaves {
|
||||||
|
vec.iter()
|
||||||
|
.map(|v| _range(_from(from, v), _to(to, v), v))
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
_range(_from(from, &self.val), _to(to, &self.val), &self.val)
|
||||||
|
};
|
||||||
|
Some(RefValue::Array(ret).into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pick_with_nums<I: ArrayIndex>(&self, indices: Vec<I>) -> Option<RefValueWrapper> {
|
||||||
|
if let RefValue::Array(vec) = &self.val.deref() {
|
||||||
|
let ret = if self.is_leaves {
|
||||||
|
indices.iter()
|
||||||
|
.map(|index| collect_not_null(vec.iter(), |v| { index.ref_value(v) }))
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
indices.iter()
|
||||||
|
.map(|index| index.ref_value(&self.val))
|
||||||
|
.filter(|v| !v.is_null())
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
Some(RefValue::Array(ret).into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace(&mut self, val: RefValueWrapper) {
|
||||||
|
self.val = match val.deref() {
|
||||||
|
RefValue::Array(v) if v.is_empty() => RefValue::Null.into(),
|
||||||
|
RefValue::Object(m) if m.is_empty() => RefValue::Null.into(),
|
||||||
|
_ => val
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_val(&self) -> &RefValueWrapper {
|
||||||
|
&self.val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_value(&self) -> Value {
|
||||||
|
self.get_val().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_array(&self) -> bool {
|
||||||
|
self.val.is_array()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_hashset(&self) -> IndexSet<&RefValue> {
|
||||||
|
trace!("into_hashset");
|
||||||
|
let mut hashset = IndexSet::new();
|
||||||
|
match self.val.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
for v in vec {
|
||||||
|
hashset.insert(v.deref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
hashset.insert(self.val.deref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashset
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_hashmap(&self) -> IndexMap<&RefValue, RefValueWrapper> {
|
||||||
|
trace!("into_hashmap");
|
||||||
|
let mut hashmap = IndexMap::new();
|
||||||
|
match self.val.deref() {
|
||||||
|
RefValue::Array(ref v1) => {
|
||||||
|
for v in v1 {
|
||||||
|
hashmap.insert(v.deref(), v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
hashmap.insert(self.val.deref(), self.val.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashmap
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn except(&self, other: &Self) -> Self {
|
||||||
|
trace!("except");
|
||||||
|
let hashset = self.into_hashset();
|
||||||
|
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||||
|
|
||||||
|
match other.val.deref() {
|
||||||
|
RefValue::Array(ref vec) => {
|
||||||
|
for v in vec {
|
||||||
|
if !hashset.contains(v.deref()) {
|
||||||
|
ret.insert(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !hashset.contains(&other.val.deref()) {
|
||||||
|
ret.insert(other.val.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||||
|
ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intersect(&self, other: &Self) -> Self {
|
||||||
|
trace!("intersect");
|
||||||
|
let hashset = self.into_hashset();
|
||||||
|
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||||
|
match other.val.deref() {
|
||||||
|
RefValue::Array(ref v1) => {
|
||||||
|
for v in v1 {
|
||||||
|
if hashset.contains(v.deref()) {
|
||||||
|
ret.insert(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e => {
|
||||||
|
if hashset.contains(e) {
|
||||||
|
ret.insert(other.val.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||||
|
ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn union(&self, other: &Self) -> Self {
|
||||||
|
trace!("union");
|
||||||
|
let origin = self.into_hashmap();
|
||||||
|
let mut ret = IndexSet::new();
|
||||||
|
|
||||||
|
for o in origin.values() {
|
||||||
|
ret.insert(o.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
match other.val.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
for v in vec {
|
||||||
|
if !origin.contains_key(v.deref()) {
|
||||||
|
ret.insert(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !origin.contains_key(&other.val.deref()) {
|
||||||
|
ret.insert(other.val.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||||
|
ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
|
||||||
|
match self.val.deref() {
|
||||||
|
RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
|
||||||
|
RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
||||||
|
RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
|
||||||
|
_ => TermContext::Json(match key {
|
||||||
|
Some(vk) => Some(vk.clone()),
|
||||||
|
_ => None
|
||||||
|
}, ValueManager::new(self.val.clone(), false, self.path_map.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
|
||||||
|
trace!("filter");
|
||||||
|
let v = match self.val.deref() {
|
||||||
|
RefValue::Array(ref vec) => {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for v in vec {
|
||||||
|
if let Some(ValueFilterKey::String(k)) = key {
|
||||||
|
if v.get(k.clone()).is_some() {
|
||||||
|
ret.push(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RefValue::Array(ret).into()
|
||||||
|
}
|
||||||
|
RefValue::Object(ref map) => {
|
||||||
|
match key {
|
||||||
|
Some(ValueFilterKey::String(k)) => match map.get(k) {
|
||||||
|
Some(v) => v.clone(),
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
},
|
||||||
|
_ => RefValue::Null.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.val.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
ValueManager::new(v, false, self.path_map.clone())
|
||||||
|
}
|
||||||
|
}
|
@ -1,307 +0,0 @@
|
|||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use indexmap::{IndexSet, IndexMap};
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use ref_value::model::*;
|
|
||||||
|
|
||||||
use super::cmp::*;
|
|
||||||
use super::term::*;
|
|
||||||
use super::value_filter::*;
|
|
||||||
|
|
||||||
fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
|
||||||
match val.deref() {
|
|
||||||
RefValue::Bool(ref v1) => {
|
|
||||||
match et {
|
|
||||||
ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) },
|
|
||||||
_ => default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RefValue::Number(ref v1) => match et {
|
|
||||||
ExprTerm::Number(v2) => if reverse { cmp_fn.cmp_f64(v2, &v1.as_f64().unwrap()) } else { cmp_fn.cmp_f64(&v1.as_f64().unwrap(), v2) },
|
|
||||||
_ => default
|
|
||||||
},
|
|
||||||
RefValue::String(ref v1) => {
|
|
||||||
match et {
|
|
||||||
ExprTerm::String(v2) => if reverse { cmp_fn.cmp_string(v2, v1) } else { cmp_fn.cmp_string(v1, v2) },
|
|
||||||
_ => default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ValueWrapper {
|
|
||||||
val: RefValueWrapper,
|
|
||||||
is_leaves: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValueWrapper {
|
|
||||||
pub fn new(val: RefValueWrapper, leaves: bool) -> Self {
|
|
||||||
ValueWrapper { val, is_leaves: leaves }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_leaves(&self) -> bool {
|
|
||||||
self.is_leaves
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_leaves(&mut self, is_leaves: bool) {
|
|
||||||
self.is_leaves = is_leaves;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmp(&self, other: &ValueWrapper, cmp_type: CmpType) -> TermContext {
|
|
||||||
match cmp_type {
|
|
||||||
CmpType::Eq => {
|
|
||||||
TermContext::Json(None, self.intersect(other))
|
|
||||||
}
|
|
||||||
CmpType::Ne => {
|
|
||||||
TermContext::Json(None, self.except(other))
|
|
||||||
}
|
|
||||||
CmpType::Gt | CmpType::Ge | CmpType::Lt | CmpType::Le => {
|
|
||||||
TermContext::Constants(ExprTerm::Bool(false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_object_in_array<F: PrivCmp>(&self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
|
||||||
fn _filter_with_object<F: Fn(&RefValueWrapper) -> bool>(v: &RefValueWrapper, key: &String, fun: F) -> bool {
|
|
||||||
match v.deref() {
|
|
||||||
RefValue::Object(map) => {
|
|
||||||
match map.get(key) {
|
|
||||||
Some(val) => fun(val),
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.val.deref() {
|
|
||||||
RefValue::Array(vec) => {
|
|
||||||
let mut set = IndexSet::new();
|
|
||||||
for v in vec {
|
|
||||||
if _filter_with_object(v, key, |vv| {
|
|
||||||
cmp_with_term(vv, et, cmp, false, reverse)
|
|
||||||
}) {
|
|
||||||
set.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = set.into_iter().collect();
|
|
||||||
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_with_key_type<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
|
||||||
match key {
|
|
||||||
Some(ValueFilterKey::String(key)) => {
|
|
||||||
self.take_object_in_array(key, et, cmp, reverse)
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_with<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
|
|
||||||
match self.take_with_key_type(key, et, &cmp, reverse) {
|
|
||||||
Some(vw) => vw,
|
|
||||||
_ => {
|
|
||||||
match &(*self.val) {
|
|
||||||
RefValue::Array(vec) => {
|
|
||||||
let mut set = IndexSet::new();
|
|
||||||
for v in vec {
|
|
||||||
if cmp_with_term(v, et, &cmp, false, reverse) {
|
|
||||||
set.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let ret = set.into_iter().collect();
|
|
||||||
ValueWrapper::new(RefValue::Array(ret).into(), false)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if cmp_with_term(&self.val, et, &cmp, false, reverse) {
|
|
||||||
ValueWrapper::new(self.val.clone(), false)
|
|
||||||
} else {
|
|
||||||
ValueWrapper::new(RefValue::Null.into(), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn replace(&mut self, val: RefValueWrapper) {
|
|
||||||
let is_null = match val.deref() {
|
|
||||||
RefValue::Array(v) => v.is_empty(),
|
|
||||||
RefValue::Object(m) => m.is_empty(),
|
|
||||||
_ => val.is_null()
|
|
||||||
};
|
|
||||||
self.val = if is_null {
|
|
||||||
RefValue::Null.into()
|
|
||||||
} else {
|
|
||||||
val
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_val(&self) -> &RefValueWrapper {
|
|
||||||
&self.val
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_value(&self) -> Value {
|
|
||||||
self.get_val().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_array(&self) -> bool {
|
|
||||||
self.val.is_array()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_hashset(&self) -> IndexSet<&RefValue> {
|
|
||||||
trace!("into_hashset");
|
|
||||||
let mut hashset = IndexSet::new();
|
|
||||||
match self.val.deref() {
|
|
||||||
RefValue::Array(ref v1) => {
|
|
||||||
for v in v1 {
|
|
||||||
hashset.insert(v.deref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
hashset.insert(self.val.deref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hashset
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_hashmap(&self) -> IndexMap<&RefValue, RefValueWrapper> {
|
|
||||||
trace!("into_hashmap");
|
|
||||||
let mut hashmap = IndexMap::new();
|
|
||||||
match self.val.deref() {
|
|
||||||
RefValue::Array(ref v1) => {
|
|
||||||
for v in v1 {
|
|
||||||
hashmap.insert(v.deref(), v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
hashmap.insert(self.val.deref(), self.val.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hashmap
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn except(&self, other: &Self) -> Self {
|
|
||||||
trace!("except");
|
|
||||||
let hashset = self.into_hashset();
|
|
||||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
|
||||||
match other.val.deref() {
|
|
||||||
RefValue::Array(ref v1) => {
|
|
||||||
for v in v1 {
|
|
||||||
if !hashset.contains(v.deref()) {
|
|
||||||
ret.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if !hashset.contains(&other.val.deref()) {
|
|
||||||
ret.insert(other.val.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
|
||||||
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn intersect(&self, other: &Self) -> Self {
|
|
||||||
trace!("intersect");
|
|
||||||
let hashset = self.into_hashset();
|
|
||||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
|
||||||
match other.val.deref() {
|
|
||||||
RefValue::Array(ref v1) => {
|
|
||||||
for v in v1 {
|
|
||||||
if hashset.contains(v.deref()) {
|
|
||||||
ret.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e => {
|
|
||||||
if hashset.contains(e) {
|
|
||||||
ret.insert(other.val.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
|
||||||
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn union(&self, other: &Self) -> Self {
|
|
||||||
trace!("union");
|
|
||||||
let origin = self.into_hashmap();
|
|
||||||
let mut ret = IndexSet::new();
|
|
||||||
|
|
||||||
for o in origin.values() {
|
|
||||||
ret.insert(o.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
match other.val.deref() {
|
|
||||||
RefValue::Array(ref v1) => {
|
|
||||||
for v in v1 {
|
|
||||||
if !origin.contains_key(v.deref()) {
|
|
||||||
ret.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if !origin.contains_key(&other.val.deref()) {
|
|
||||||
ret.insert(other.val.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut vw = ValueWrapper::new(RefValue::Null.into(), false);
|
|
||||||
let list = ret.iter().map(|v| v.clone()).collect();
|
|
||||||
vw.replace(RefValue::Array(list).into());
|
|
||||||
vw
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
|
|
||||||
match self.val.deref() {
|
|
||||||
RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
|
|
||||||
RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
|
||||||
RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
|
|
||||||
_ => TermContext::Json(match key {
|
|
||||||
Some(vk) => Some(vk.clone()),
|
|
||||||
_ => None
|
|
||||||
}, ValueWrapper::new(self.val.clone(), false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
|
|
||||||
trace!("filter");
|
|
||||||
let v = match self.val.deref() {
|
|
||||||
RefValue::Array(ref vec) => {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
for v in vec {
|
|
||||||
if let Some(ValueFilterKey::String(k)) = key {
|
|
||||||
if v.get(k.clone()).is_some() {
|
|
||||||
ret.push(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RefValue::Array(ret).into()
|
|
||||||
}
|
|
||||||
RefValue::Object(ref map) => {
|
|
||||||
match key {
|
|
||||||
Some(ValueFilterKey::String(k)) => match map.get(k) {
|
|
||||||
Some(v) => v.clone(),
|
|
||||||
_ => RefValue::Null.into()
|
|
||||||
},
|
|
||||||
_ => RefValue::Null.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.val.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
ValueWrapper::new(v, false)
|
|
||||||
}
|
|
||||||
}
|
|
@ -172,6 +172,8 @@ use std::result;
|
|||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
pub use select::selector::Selector;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -181,8 +183,6 @@ pub mod ref_value;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod select;
|
pub mod select;
|
||||||
|
|
||||||
pub use select::Selector;
|
|
||||||
|
|
||||||
/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
|
/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -349,7 +349,7 @@ pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value,
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
|
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
|
||||||
let mut selector = Selector::new();
|
let mut selector = Selector::new();
|
||||||
selector.path(path)?.value(json.into())?.select_as_value()
|
selector.path(path)?.value(json)?.select_as_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
|
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -5,13 +7,25 @@ use std::sync::Arc;
|
|||||||
use indexmap::map::IndexMap;
|
use indexmap::map::IndexMap;
|
||||||
use serde::ser::Serialize;
|
use serde::ser::Serialize;
|
||||||
use serde_json::{Number, Value};
|
use serde_json::{Number, Value};
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::fmt;
|
||||||
|
|
||||||
type TypeRefValue = Arc<Box<RefValue>>;
|
type TypeRefValue = Arc<RefCell<RefValue>>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RefValueWrapper {
|
pub struct RefValueWrapper {
|
||||||
data: TypeRefValue
|
data: TypeRefValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for RefValueWrapper {
|
||||||
|
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.deref().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefValueWrapper {
|
||||||
|
pub fn ref_count(&self) -> usize {
|
||||||
|
Arc::strong_count(&self.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for RefValueWrapper {
|
impl PartialEq for RefValueWrapper {
|
||||||
@ -26,10 +40,16 @@ impl Deref for RefValueWrapper {
|
|||||||
type Target = RefValue;
|
type Target = RefValue;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&(**self.data)
|
unsafe { self.data.as_ptr().as_mut().unwrap() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//impl DerefMut for RefValueWrapper {
|
||||||
|
// fn deref_mut(&mut self) -> &mut RefValue {
|
||||||
|
// unsafe { self.data.as_ptr().as_mut().unwrap() }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
impl Hash for RefValueWrapper {
|
impl Hash for RefValueWrapper {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.deref().hash(state)
|
self.deref().hash(state)
|
||||||
@ -120,7 +140,6 @@ impl RefIndex for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum RefValue {
|
pub enum RefValue {
|
||||||
Null,
|
Null,
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
@ -130,6 +149,12 @@ pub enum RefValue {
|
|||||||
Object(IndexMap<String, RefValueWrapper>),
|
Object(IndexMap<String, RefValueWrapper>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for RefValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", serde_json::to_string(&self).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for RefValue {
|
impl PartialEq for RefValue {
|
||||||
fn eq(&self, other: &RefValue) -> bool {
|
fn eq(&self, other: &RefValue) -> bool {
|
||||||
let mut hasher1 = DefaultHasher::new();
|
let mut hasher1 = DefaultHasher::new();
|
||||||
@ -146,6 +171,9 @@ static REF_VALUE_NULL: &'static str = "$jsonpath::ref_value::model::RefValue::Nu
|
|||||||
|
|
||||||
impl Hash for RefValue {
|
impl Hash for RefValue {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
|
||||||
|
// println!("###hash - RefValue - {:?}", self);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
RefValue::Null => {
|
RefValue::Null => {
|
||||||
REF_VALUE_NULL.hash(state)
|
REF_VALUE_NULL.hash(state)
|
||||||
@ -188,71 +216,40 @@ impl RefValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_object(&self) -> bool {
|
pub fn is_object(&self) -> bool {
|
||||||
self.as_object().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_object(&self) -> Option<&IndexMap<String, RefValueWrapper>> {
|
|
||||||
match *self {
|
match *self {
|
||||||
RefValue::Object(ref map) => Some(map),
|
RefValue::Object(_) => true,
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_array(&self) -> bool {
|
|
||||||
self.as_array().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_array(&self) -> Option<&Vec<RefValueWrapper>> {
|
|
||||||
match *self {
|
|
||||||
RefValue::Array(ref array) => Some(&*array),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_string(&self) -> bool {
|
|
||||||
self.as_str().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> Option<&str> {
|
|
||||||
match *self {
|
|
||||||
RefValue::String(ref s) => Some(s),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_number(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
RefValue::Number(_) => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_number(&self) -> Option<Number> {
|
pub fn is_array(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
RefValue::Number(ref n) => Some(n.clone()),
|
RefValue::Array(_) => true,
|
||||||
_ => None,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_boolean(&self) -> bool {
|
pub fn len(&self) -> usize {
|
||||||
self.as_bool().is_some()
|
match &self {
|
||||||
|
RefValue::Object(m) => m.len(),
|
||||||
|
RefValue::Array(v) => v.len(),
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_bool(&self) -> Option<bool> {
|
pub fn is_empty(&self) -> bool {
|
||||||
match *self {
|
match &self {
|
||||||
RefValue::Bool(b) => Some(b),
|
RefValue::Object(m) => m.is_empty(),
|
||||||
_ => None,
|
RefValue::Array(v) => v.is_empty(),
|
||||||
|
RefValue::Null => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_null(&self) -> bool {
|
pub fn is_null(&self) -> bool {
|
||||||
self.as_null().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_null(&self) -> Option<()> {
|
|
||||||
match *self {
|
match *self {
|
||||||
RefValue::Null => Some(()),
|
RefValue::Null => true,
|
||||||
_ => None,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,14 +257,14 @@ impl RefValue {
|
|||||||
impl Into<RefValueWrapper> for RefValue {
|
impl Into<RefValueWrapper> for RefValue {
|
||||||
fn into(self) -> RefValueWrapper {
|
fn into(self) -> RefValueWrapper {
|
||||||
RefValueWrapper {
|
RefValueWrapper {
|
||||||
data: Arc::new(Box::new(self))
|
data: Arc::new(RefCell::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<RefValue> for &Value {
|
impl Into<RefValue> for &Value {
|
||||||
fn into(self) -> RefValue {
|
fn into(self) -> RefValue {
|
||||||
match self.serialize(super::ser::Serializer) {
|
match self.serialize(super::ser::RefValueSerializer) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||||
}
|
}
|
||||||
@ -276,7 +273,7 @@ impl Into<RefValue> for &Value {
|
|||||||
|
|
||||||
impl Into<RefValueWrapper> for &Value {
|
impl Into<RefValueWrapper> for &Value {
|
||||||
fn into(self) -> RefValueWrapper {
|
fn into(self) -> RefValueWrapper {
|
||||||
match self.serialize(super::ser::Serializer) {
|
match self.serialize(super::ser::RefValueSerializer) {
|
||||||
Ok(v) => v.into(),
|
Ok(v) => v.into(),
|
||||||
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,9 @@ impl Serialize for RefValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Serializer;
|
pub struct RefValueSerializer;
|
||||||
|
|
||||||
impl serde::Serializer for Serializer {
|
impl serde::Serializer for RefValueSerializer {
|
||||||
type Ok = RefValue;
|
type Ok = RefValue;
|
||||||
type Error = SerdeError;
|
type Error = SerdeError;
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ impl serde::Serializer for Serializer {
|
|||||||
{
|
{
|
||||||
let mut values: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
let mut values: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||||
values.insert(String::from(variant), {
|
values.insert(String::from(variant), {
|
||||||
value.serialize(Serializer)?.into()
|
value.serialize(RefValueSerializer)?.into()
|
||||||
});
|
});
|
||||||
Ok(RefValue::Object(values))
|
Ok(RefValue::Object(values))
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ impl serde::ser::SerializeSeq for SerializeVec {
|
|||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
self.vec.push({
|
self.vec.push({
|
||||||
value.serialize(Serializer)?.into()
|
value.serialize(RefValueSerializer)?.into()
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -331,7 +331,7 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
|||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
self.vec.push({
|
self.vec.push({
|
||||||
let a: RefValue = value.serialize(Serializer)?;
|
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||||
a.into()
|
a.into()
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -378,7 +378,7 @@ impl serde::ser::SerializeMap for SerializeMap {
|
|||||||
// expected failure.
|
// expected failure.
|
||||||
let key = key.expect("serialize_value called before serialize_key");
|
let key = key.expect("serialize_value called before serialize_key");
|
||||||
map.insert(key, {
|
map.insert(key, {
|
||||||
let a: RefValue = value.serialize(Serializer)?;
|
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||||
a.into()
|
a.into()
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -608,7 +608,7 @@ impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
|||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
self.map.insert(String::from(key), {
|
self.map.insert(String::from(key), {
|
||||||
let a: RefValue = value.serialize(Serializer)?;
|
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||||
a.into()
|
a.into()
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,239 +1,3 @@
|
|||||||
use std::{fmt, result};
|
pub mod selector;
|
||||||
use std::ops::Deref;
|
pub mod modifiable;
|
||||||
|
pub mod path_map;
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use super::filter::value_filter::*;
|
|
||||||
use super::parser::parser::*;
|
|
||||||
use super::ref_value::model::*;
|
|
||||||
|
|
||||||
/// Utility. Functions like jsonpath::selector or jsonpath::compile are also implemented using this structure.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
|
||||||
/// extern crate serde;
|
|
||||||
/// extern crate serde_json;
|
|
||||||
///
|
|
||||||
/// use serde::{Deserialize, Serialize};
|
|
||||||
/// use serde_json::Value;
|
|
||||||
///
|
|
||||||
/// use jsonpath::Selector;
|
|
||||||
///
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct Person {
|
|
||||||
/// name: String,
|
|
||||||
/// age: Option<u8>,
|
|
||||||
/// phone: String,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn input_str() -> &'static str {
|
|
||||||
/// r#"[
|
|
||||||
/// {
|
|
||||||
/// "name": "이름1",
|
|
||||||
/// "age": 40,
|
|
||||||
/// "phone": "+33 12341234"
|
|
||||||
/// },
|
|
||||||
/// {
|
|
||||||
/// "name": "이름2",
|
|
||||||
/// "age": 42,
|
|
||||||
/// "phone": "++44 12341234"
|
|
||||||
/// }
|
|
||||||
/// ]"#
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn input_json() -> Value {
|
|
||||||
/// serde_json::from_str(input_str()).unwrap()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn input_person() -> Vec<Person> {
|
|
||||||
/// serde_json::from_str(input_str()).unwrap()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// let mut selector = Selector::new();
|
|
||||||
///
|
|
||||||
/// let result = selector
|
|
||||||
/// .path("$..[?(@.age > 40)]").unwrap()
|
|
||||||
/// .value_from_str(input_str()).unwrap()
|
|
||||||
/// .select_as_value().unwrap();
|
|
||||||
/// assert_eq!(input_json()[1], result[0]);
|
|
||||||
///
|
|
||||||
/// let result = selector.select_as_str().unwrap();
|
|
||||||
/// assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
|
|
||||||
///
|
|
||||||
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
|
||||||
/// assert_eq!(input_person()[1], result[0]);
|
|
||||||
///
|
|
||||||
/// let _ = selector.path("$..[?(@.age == 40)]");
|
|
||||||
///
|
|
||||||
/// let result = selector.select_as_value().unwrap();
|
|
||||||
/// assert_eq!(input_json()[0], result[0]);
|
|
||||||
///
|
|
||||||
/// let result = selector.select_as_str().unwrap();
|
|
||||||
/// assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
|
||||||
///
|
|
||||||
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
|
||||||
/// assert_eq!(input_person()[0], result[0]);
|
|
||||||
///
|
|
||||||
/// selector.map(|v| {
|
|
||||||
/// let r = match v {
|
|
||||||
/// Value::Array(mut vec) => {
|
|
||||||
/// for mut v in &mut vec {
|
|
||||||
/// v.as_object_mut().unwrap().remove("age");
|
|
||||||
/// }
|
|
||||||
/// Value::Array(vec)
|
|
||||||
/// }
|
|
||||||
/// _ => Value::Null
|
|
||||||
/// };
|
|
||||||
/// Some(r)
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(
|
|
||||||
/// serde_json::from_str::<Value>(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(),
|
|
||||||
/// selector.get().unwrap());
|
|
||||||
///
|
|
||||||
/// selector.value_from_str(input_str()).unwrap()
|
|
||||||
/// .map_as(|mut v: Vec<Person>| {
|
|
||||||
/// let mut p = v.pop().unwrap();
|
|
||||||
/// p.name = "name1".to_string();
|
|
||||||
/// p.age = None;
|
|
||||||
/// Some(vec![p])
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(
|
|
||||||
/// vec![Person { name: "name1".to_string(), age: None, phone: "+33 12341234".to_string() }],
|
|
||||||
/// selector.get_as::<Vec<Person>>().unwrap());
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Selector {
|
|
||||||
pub(crate) node: Option<Node>,
|
|
||||||
pub(crate) value: Option<RefValueWrapper>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Selector {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Selector { node: None, value: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&mut self, path: &str) -> result::Result<&mut Self, String> {
|
|
||||||
let mut parser = Parser::new(path);
|
|
||||||
self.node = Some(parser.compile()?);
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value(&mut self, value: &Value) -> result::Result<&mut Self, String> {
|
|
||||||
self.value = Some(value.into());
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_from(&mut self, serializable: &impl serde::ser::Serialize) -> result::Result<&mut Self, String> {
|
|
||||||
let ref_value: RefValue = serializable
|
|
||||||
.serialize(super::ref_value::ser::Serializer)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
self.value = Some(ref_value.into());
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
|
|
||||||
let value = serde_json::from_str(json_str)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
self.value(&value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jf(&self) -> result::Result<JsonValueFilter, String> {
|
|
||||||
match &self.value {
|
|
||||||
Some(v) => Ok(JsonValueFilter::new_from_value(v.clone())),
|
|
||||||
_ => return Err(SelectorErrorMessage::EmptyValue.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select(&self) -> result::Result<RefValueWrapper, String> {
|
|
||||||
let mut jf = self.jf()?;
|
|
||||||
|
|
||||||
match &self.node {
|
|
||||||
Some(node) => {
|
|
||||||
jf.visit(node.clone());
|
|
||||||
Ok(jf.take_value())
|
|
||||||
}
|
|
||||||
_ => Err(SelectorErrorMessage::EmptyPath.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated(since = "0.1.13", note = "Please use the select_as_str function instead")]
|
|
||||||
pub fn select_to_str(&self) -> result::Result<String, String> {
|
|
||||||
self.select_as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated(since = "0.1.13", note = "Please use the select_as_value function instead")]
|
|
||||||
pub fn select_to_value(&self) -> result::Result<Value, String> {
|
|
||||||
self.select_as_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated(since = "0.1.13", note = "Please use the select_as function instead")]
|
|
||||||
pub fn select_to<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
|
||||||
self.select_as()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_as_str(&self) -> result::Result<String, String> {
|
|
||||||
serde_json::to_string(self.select()?.deref()).map_err(|e| e.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_as_value(&self) -> result::Result<Value, String> {
|
|
||||||
Ok((&self.select()?).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
|
||||||
T::deserialize(self.select()?.deref()).map_err(|e| e.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map<F>(&mut self, func: F) -> result::Result<&mut Self, String>
|
|
||||||
where F: FnOnce(Value) -> Option<Value>
|
|
||||||
{
|
|
||||||
self.value = func((&self.select()?).into()).map(|ref v| v.into());
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_as<F, D, S>(&mut self, func: F) -> result::Result<&mut Self, String>
|
|
||||||
where F: FnOnce(D) -> Option<S>,
|
|
||||||
D: serde::de::DeserializeOwned,
|
|
||||||
S: serde::ser::Serialize
|
|
||||||
{
|
|
||||||
let ret = func(D::deserialize(self.select()?.deref()).map_err(|e| e.to_string())?)
|
|
||||||
.map(|ref ser| ser.serialize(super::ref_value::ser::Serializer));
|
|
||||||
|
|
||||||
self.value = match ret {
|
|
||||||
Some(ret) => match ret {
|
|
||||||
Ok(v) => Some(v.into()),
|
|
||||||
Err(e) => return Err(e.to_string())
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self) -> result::Result<Value, String> {
|
|
||||||
match &self.value {
|
|
||||||
Some(value) => Ok(value.into()),
|
|
||||||
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
|
||||||
match &self.value {
|
|
||||||
Some(value) => T::deserialize(value.deref()).map_err(|e| e.to_string()),
|
|
||||||
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SelectorErrorMessage {
|
|
||||||
EmptyValue,
|
|
||||||
EmptyPath,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SelectorErrorMessage {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
SelectorErrorMessage::EmptyValue => write!(f, "Empty value"),
|
|
||||||
SelectorErrorMessage::EmptyPath => write!(f, "Empty path"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
60
src/select/modifiable.rs
Normal file
60
src/select/modifiable.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use ref_value::model::{RefValue, RefValueWrapper};
|
||||||
|
use Selector;
|
||||||
|
|
||||||
|
pub trait Modifiable {
|
||||||
|
fn delete(&mut self) -> Result<&mut Self, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Modifiable for Selector {
|
||||||
|
fn delete(&mut self) -> Result<&mut Self, String> {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn traverse(parent_path: String, v: &RefValueWrapper, buf: &mut HashMap<RefValueWrapper, String>, depth: usize, limit: usize) {
|
||||||
|
if depth >= limit {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
for (i, v) in vec.iter().enumerate() {
|
||||||
|
buf.insert(v.clone(), format!("{}/{}", parent_path, i.to_string()));
|
||||||
|
}
|
||||||
|
for (i, v) in vec.iter().enumerate() {
|
||||||
|
traverse(format!("{}/{}", parent_path, i.to_string()), v, buf, depth + 1, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RefValue::Object(map) => {
|
||||||
|
for (k, v) in map.into_iter() {
|
||||||
|
buf.insert(v.clone(), format!("{}/{}", parent_path, k.to_string()));
|
||||||
|
}
|
||||||
|
for (k, v) in map.into_iter() {
|
||||||
|
traverse(format!("{}/{}", parent_path, k.to_string()), v, buf, depth + 1, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
buf.insert(v.clone(), parent_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PathFinder {
|
||||||
|
map: HashMap<RefValueWrapper, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathFinder {
|
||||||
|
pub fn new(v: RefValueWrapper) -> Self {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
traverse("/".to_string(), &v, &mut map, 0, 1);
|
||||||
|
debug!("map: {:?}", map);
|
||||||
|
PathFinder { map }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, v: &RefValueWrapper) -> Option<&String> {
|
||||||
|
self.map.get(v)
|
||||||
|
}
|
||||||
|
}
|
53
src/select/path_map.rs
Normal file
53
src/select/path_map.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use ref_value::model::{RefValue, RefValueWrapper};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PathMap {
|
||||||
|
map: IndexMap<RefValueWrapper, String>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathMap {
|
||||||
|
pub(in select) fn new() -> Self {
|
||||||
|
PathMap { map: IndexMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_path(&self, v: &RefValueWrapper) -> Option<&String> {
|
||||||
|
self.map.get(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in select) fn replace(&mut self, v: &RefValueWrapper) {
|
||||||
|
self.map.clear();
|
||||||
|
self.walk("".to_string(), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk(&mut self, parent_path: String, v: &RefValueWrapper) {
|
||||||
|
if &parent_path == "" {
|
||||||
|
self.map.insert(v.clone(), "/".to_string());
|
||||||
|
} else {
|
||||||
|
self.map.insert(v.clone(), parent_path.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
match v.deref() {
|
||||||
|
RefValue::Object(map) => {
|
||||||
|
for (key, value) in map {
|
||||||
|
self.walk(format!("{}/{}", &parent_path, key), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RefValue::Array(vec) => {
|
||||||
|
for (index, value) in vec.iter().enumerate() {
|
||||||
|
self.walk(format!("{}/{}", &parent_path, index), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&self) {
|
||||||
|
for (k, v) in &self.map {
|
||||||
|
println!("{:?} : {}", k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
266
src/select/selector.rs
Normal file
266
src/select/selector.rs
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
use std::{fmt, result};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use filter::value_filter::*;
|
||||||
|
use parser::parser::*;
|
||||||
|
use ref_value;
|
||||||
|
use ref_value::model::*;
|
||||||
|
use select::path_map::PathMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
/// Utility. Functions like jsonpath::selector or jsonpath::compile are also implemented using this structure.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
|
/// extern crate serde;
|
||||||
|
/// extern crate serde_json;
|
||||||
|
///
|
||||||
|
/// use serde::{Deserialize, Serialize};
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// use jsonpath::Selector;
|
||||||
|
///
|
||||||
|
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
/// struct Person {
|
||||||
|
/// name: String,
|
||||||
|
/// age: Option<u8>,
|
||||||
|
/// phone: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_str() -> &'static str {
|
||||||
|
/// r#"[
|
||||||
|
/// {
|
||||||
|
/// "name": "이름1",
|
||||||
|
/// "age": 40,
|
||||||
|
/// "phone": "+33 12341234"
|
||||||
|
/// },
|
||||||
|
/// {
|
||||||
|
/// "name": "이름2",
|
||||||
|
/// "age": 42,
|
||||||
|
/// "phone": "++44 12341234"
|
||||||
|
/// }
|
||||||
|
/// ]"#
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_json() -> Value {
|
||||||
|
/// serde_json::from_str(input_str()).unwrap()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_person() -> Vec<Person> {
|
||||||
|
/// serde_json::from_str(input_str()).unwrap()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// let mut selector = Selector::new();
|
||||||
|
///
|
||||||
|
/// let result = selector
|
||||||
|
/// .path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
/// .value_from_str(input_str()).unwrap()
|
||||||
|
/// .select_as_value().unwrap();
|
||||||
|
/// assert_eq!(input_json()[1], result[0]);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_as_str().unwrap();
|
||||||
|
/// assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||||
|
/// assert_eq!(input_person()[1], result[0]);
|
||||||
|
///
|
||||||
|
/// let _ = selector.path("$..[?(@.age == 40)]");
|
||||||
|
///
|
||||||
|
/// let result = selector.select_as_value().unwrap();
|
||||||
|
/// assert_eq!(input_json()[0], result[0]);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_as_str().unwrap();
|
||||||
|
/// assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||||
|
/// assert_eq!(input_person()[0], result[0]);
|
||||||
|
///
|
||||||
|
/// selector.map(|v| {
|
||||||
|
/// let r = match v {
|
||||||
|
/// Value::Array(mut vec) => {
|
||||||
|
/// for mut v in &mut vec {
|
||||||
|
/// v.as_object_mut().unwrap().remove("age");
|
||||||
|
/// }
|
||||||
|
/// Value::Array(vec)
|
||||||
|
/// }
|
||||||
|
/// _ => Value::Null
|
||||||
|
/// };
|
||||||
|
/// Some(r)
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(
|
||||||
|
/// serde_json::from_str::<Value>(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(),
|
||||||
|
/// selector.get().unwrap());
|
||||||
|
///
|
||||||
|
/// selector.value_from_str(input_str()).unwrap()
|
||||||
|
/// .map_as(|mut v: Vec<Person>| {
|
||||||
|
/// let mut p = v.pop().unwrap();
|
||||||
|
/// p.name = "name1".to_string();
|
||||||
|
/// p.age = None;
|
||||||
|
/// Some(vec![p])
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(
|
||||||
|
/// vec![Person { name: "name1".to_string(), age: None, phone: "+33 12341234".to_string() }],
|
||||||
|
/// selector.get_as::<Vec<Person>>().unwrap());
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Selector {
|
||||||
|
pub(crate) node: Option<Node>,
|
||||||
|
pub(crate) value: Option<RefValueWrapper>,
|
||||||
|
path_builder: Arc<RefCell<PathMap>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Selector {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Selector { node: None, value: None, path_builder: Arc::new(RefCell::new(PathMap::new())) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_value(&mut self, value: RefValueWrapper) {
|
||||||
|
// (*self.path_builder).borrow_mut().replace(&value);
|
||||||
|
self.value = Some(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&mut self, path: &str) -> result::Result<&mut Self, String> {
|
||||||
|
let mut parser = Parser::new(path);
|
||||||
|
self.node = Some(parser.compile()?);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&mut self, value: &Value) -> result::Result<&mut Self, String> {
|
||||||
|
self.set_value(value.into());
|
||||||
|
// (*self.path_builder).borrow_mut().print();
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_from_ref_value(&mut self, value: RefValueWrapper) -> result::Result<&mut Self, String> {
|
||||||
|
self.set_value(value);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_from(&mut self, serializable: &impl serde::ser::Serialize) -> result::Result<&mut Self, String> {
|
||||||
|
let ref_value: RefValue = serializable
|
||||||
|
.serialize(ref_value::ser::RefValueSerializer)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
self.set_value(ref_value.into());
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
|
||||||
|
let value: RefValue = serde_json::from_str(json_str)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
self.set_value(value.into());
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jf(&self) -> result::Result<JsonValueFilter, String> {
|
||||||
|
match &self.value {
|
||||||
|
Some(v) => Ok(JsonValueFilter::new(v.clone(),
|
||||||
|
self.path_builder.clone())),
|
||||||
|
_ => return Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select(&self) -> result::Result<RefValueWrapper, String> {
|
||||||
|
let mut jf = self.jf()?;
|
||||||
|
|
||||||
|
match &self.node {
|
||||||
|
Some(node) => {
|
||||||
|
jf.visit(node.clone());
|
||||||
|
Ok(jf.clone_value())
|
||||||
|
}
|
||||||
|
_ => Err(SelectorErrorMessage::EmptyPath.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(since = "0.1.13", note = "Please use the select_as_str function instead")]
|
||||||
|
pub fn select_to_str(&self) -> result::Result<String, String> {
|
||||||
|
self.select_as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(since = "0.1.13", note = "Please use the select_as_value function instead")]
|
||||||
|
pub fn select_to_value(&self) -> result::Result<Value, String> {
|
||||||
|
self.select_as_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(since = "0.1.13", note = "Please use the select_as function instead")]
|
||||||
|
pub fn select_to<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||||
|
self.select_as()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_as_str(&self) -> result::Result<String, String> {
|
||||||
|
serde_json::to_string(self.select()?.deref()).map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_as_value2(&self) {
|
||||||
|
let _ = &self.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_as_value(&self) -> result::Result<Value, String> {
|
||||||
|
Ok((&self.select()?).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||||
|
T::deserialize(self.select()?.deref()).map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map<F>(&mut self, func: F) -> result::Result<&mut Self, String>
|
||||||
|
where F: FnOnce(Value) -> Option<Value>
|
||||||
|
{
|
||||||
|
match func((&self.select()?).into()).map(|ref v| v.into()) {
|
||||||
|
Some(value) => {
|
||||||
|
self.set_value(value)
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_as<F, D, S>(&mut self, func: F) -> result::Result<&mut Self, String>
|
||||||
|
where F: FnOnce(D) -> Option<S>,
|
||||||
|
D: serde::de::DeserializeOwned,
|
||||||
|
S: serde::ser::Serialize
|
||||||
|
{
|
||||||
|
let ret = func(D::deserialize(self.select()?.deref()).map_err(|e| e.to_string())?)
|
||||||
|
.map(|ref ser| ser.serialize(ref_value::ser::RefValueSerializer));
|
||||||
|
|
||||||
|
match ret {
|
||||||
|
Some(ret) => match ret {
|
||||||
|
Ok(v) => self.set_value(v.into()),
|
||||||
|
Err(e) => return Err(e.to_string())
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> result::Result<Value, String> {
|
||||||
|
match &self.value {
|
||||||
|
Some(value) => Ok(value.into()),
|
||||||
|
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||||
|
match &self.value {
|
||||||
|
Some(value) => T::deserialize(value.deref()).map_err(|e| e.to_string()),
|
||||||
|
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SelectorErrorMessage {
|
||||||
|
EmptyValue,
|
||||||
|
EmptyPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SelectorErrorMessage {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SelectorErrorMessage::EmptyValue => write!(f, "Empty value"),
|
||||||
|
SelectorErrorMessage::EmptyPath => write!(f, "Empty path"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
271
tests/filter.rs
271
tests/filter.rs
@ -10,23 +10,24 @@ use serde_json::Value;
|
|||||||
|
|
||||||
use jsonpath::filter::value_filter::{JsonValueFilter, ValueFilter};
|
use jsonpath::filter::value_filter::{JsonValueFilter, ValueFilter};
|
||||||
use jsonpath::parser::parser::Parser;
|
use jsonpath::parser::parser::Parser;
|
||||||
|
use jsonpath::Selector;
|
||||||
|
|
||||||
fn setup() {
|
fn setup() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_value_filter(file: &str) -> ValueFilter {
|
//fn new_value_filter(file: &str) -> ValueFilter {
|
||||||
let string = read_json(file);
|
// let string = read_json(file);
|
||||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
// let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||||
ValueFilter::new((&json).into(), false, false)
|
// ValueFilter::new((&json).into(), false, false)
|
||||||
}
|
//}
|
||||||
|
|
||||||
fn do_filter(path: &str, file: &str) -> JsonValueFilter {
|
fn selector(path: &str, file: &str) -> Selector {
|
||||||
let string = read_json(file);
|
let string = read_json(file);
|
||||||
let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
|
let mut s = Selector::new();
|
||||||
let mut parser = Parser::new(path);
|
let _ = s.path(path);
|
||||||
parser.parse(&mut jf).unwrap();
|
let _ = s.value_from_str(&string);
|
||||||
jf
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_json(path: &str) -> String {
|
fn read_json(path: &str) -> String {
|
||||||
@ -36,53 +37,53 @@ fn read_json(path: &str) -> String {
|
|||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
//#[test]
|
||||||
fn step_in() {
|
//fn step_in() {
|
||||||
setup();
|
// setup();
|
||||||
|
//
|
||||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||||
{
|
// {
|
||||||
let current = jf.step_in_str("friends");
|
// let current = jf.step_in_str("friends");
|
||||||
assert_eq!(current.is_array(), true);
|
// assert_eq!(current.is_array(), true);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let mut jf = new_value_filter("./benches/data_array.json");
|
// let mut jf = new_value_filter("./benches/data_array.json");
|
||||||
{
|
// {
|
||||||
let current = jf.step_in_num(&1.0);
|
// let current = jf.step_in_num(&1.0);
|
||||||
assert_eq!(current.get_val().is_object(), true);
|
// assert_eq!(current.get_val().is_object(), true);
|
||||||
}
|
// }
|
||||||
{
|
// {
|
||||||
let current = jf.step_in_str("friends");
|
// let current = jf.step_in_str("friends");
|
||||||
assert_eq!(current.is_array(), true);
|
// assert_eq!(current.is_array(), true);
|
||||||
}
|
// }
|
||||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||||
{
|
// {
|
||||||
jf.step_in_str("school");
|
// jf.step_in_str("school");
|
||||||
jf.step_in_str("friends");
|
// jf.step_in_str("friends");
|
||||||
jf.step_in_all();
|
// jf.step_in_all();
|
||||||
let current = jf.step_in_str("name");
|
// let current = jf.step_in_str("name");
|
||||||
let friends = json!([
|
// let friends = json!([
|
||||||
"Millicent Norman",
|
// "Millicent Norman",
|
||||||
"Vincent Cannon",
|
// "Vincent Cannon",
|
||||||
"Gray Berry"
|
// "Gray Berry"
|
||||||
]);
|
// ]);
|
||||||
|
//
|
||||||
assert_eq!(friends, current.into_value());
|
// assert_eq!(friends, current.into_value());
|
||||||
}
|
// }
|
||||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||||
{
|
// {
|
||||||
let current = jf.step_leaves_str("name");
|
// let current = jf.step_leaves_str("name");
|
||||||
let names = json!([
|
// let names = json!([
|
||||||
"Leonor Herman",
|
// "Leonor Herman",
|
||||||
"Millicent Norman",
|
// "Millicent Norman",
|
||||||
"Vincent Cannon",
|
// "Vincent Cannon",
|
||||||
"Gray Berry",
|
// "Gray Berry",
|
||||||
"Vincent Cannon",
|
// "Vincent Cannon",
|
||||||
"Gray Berry"
|
// "Gray Berry"
|
||||||
]);
|
// ]);
|
||||||
assert_eq!(names, current.into_value());
|
// assert_eq!(names, current.into_value());
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array() {
|
fn array() {
|
||||||
@ -93,33 +94,33 @@ fn array() {
|
|||||||
{"id": 2, "name": "Gray Berry"}
|
{"id": 2, "name": "Gray Berry"}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
|
let s = selector("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
|
let s = selector("$.school.friends[1:]", "./benches/data_obj.json");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json");
|
let s = selector("$.school.friends[:-2]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{"id": 0, "name": "Millicent Norman"}
|
{"id": 0, "name": "Millicent Norman"}
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[2].name", "./benches/data_obj.json");
|
let s = selector("$..friends[2].name", "./benches/data_obj.json");
|
||||||
let friends = json!(["Gray Berry", "Gray Berry"]);
|
let friends = json!(["Gray Berry", "Gray Berry"]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[*].name", "./benches/data_obj.json");
|
let s = selector("$..friends[*].name", "./benches/data_obj.json");
|
||||||
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
let s = selector("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
||||||
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
let s = selector("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
||||||
let friends = json!("Millicent Norman");
|
let friends = json!("Millicent Norman");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -134,32 +135,32 @@ fn return_type() {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
let jf = do_filter("$.school", "./benches/data_obj.json");
|
let s = selector("$.school", "./benches/data_obj.json");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
let s = selector("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
let s = selector("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||||
assert_eq!(Value::Null, jf.into_value());
|
assert_eq!(Value::Null, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
|
let s = selector("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
let s = selector("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{"id": 0, "name": "Millicent Norman"},
|
{"id": 0, "name": "Millicent Norman"},
|
||||||
{"id": 1, "name": "Vincent Cannon" },
|
{"id": 1, "name": "Vincent Cannon" },
|
||||||
{"id": 2, "name": "Gray Berry"}
|
{"id": 2, "name": "Gray Berry"}
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_default() {
|
fn op_default() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json");
|
let s = selector("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json");
|
||||||
let friends = json!({
|
let friends = json!({
|
||||||
"friends": [
|
"friends": [
|
||||||
{"id": 0, "name": "Millicent Norman"},
|
{"id": 0, "name": "Millicent Norman"},
|
||||||
@ -167,54 +168,55 @@ fn op_default() {
|
|||||||
{"id": 2, "name": "Gray Berry"}
|
{"id": 2, "name": "Gray Berry"}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json");
|
let s = selector("$.friends[?(@.name)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
{ "id" : 1, "name" : "Vincent Cannon" },
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
{ "id" : 2, "name" : "Gray Berry" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
let s = selector("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
{ "id" : 2, "name" : "Gray Berry" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
let s = selector("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" },
|
{ "id" : 2, "name" : "Gray Berry" },
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" }
|
{ "id" : 1, "name" : "Vincent Cannon" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
let s = selector("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
||||||
assert_eq!(Value::Null, jf.into_value());
|
assert_eq!(Value::Null, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
let s = selector("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
||||||
let friends = json!([0, 0]);
|
let friends = json!([0, 0]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
let s = selector("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
||||||
let friends = json!([22.99]);
|
let friends = json!([22.99]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
let s = selector("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
||||||
let friends = json!([12.99]);
|
let friends = json!([12.99]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let ref value = json!([
|
let ref value = json!([
|
||||||
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
||||||
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
||||||
]);
|
]);
|
||||||
let mut jf = JsonValueFilter::new_from_value(value.into());
|
|
||||||
let mut parser = Parser::new("$..[?(@.age > 40)]");
|
let mut s = Selector::new();
|
||||||
parser.parse(&mut jf).unwrap();
|
let _ = s.path("$..[?(@.age > 40)]");
|
||||||
|
let _ = s.value(value);
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let ref value = json!({
|
let ref value = json!({
|
||||||
"school": {
|
"school": {
|
||||||
@ -227,11 +229,11 @@ fn op_default() {
|
|||||||
{"name": "친구3", "age": 30},
|
{"name": "친구3", "age": 30},
|
||||||
{"name": "친구4"}
|
{"name": "친구4"}
|
||||||
]});
|
]});
|
||||||
let mut jf = JsonValueFilter::new_from_value(value.into());
|
let mut s = Selector::new();
|
||||||
let mut parser = Parser::new("$..[?(@.age >= 30)]");
|
let _ = s.path("$..[?(@.age >= 30)]");
|
||||||
parser.parse(&mut jf).unwrap();
|
let _ = s.value(value);
|
||||||
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
|
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, s.select_as_value().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -314,14 +316,14 @@ fn op_complex() {
|
|||||||
fn example() {
|
fn example() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
let jf = do_filter("$.store.book[*].author", "./benches/example.json");
|
let s = selector("$.store.book[*].author", "./benches/example.json");
|
||||||
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..author", "./benches/example.json");
|
let s = selector("$..author", "./benches/example.json");
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.store.*", "./benches/example.json");
|
let s = selector("$.store.*", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
[
|
[
|
||||||
{"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
|
{"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
|
||||||
@ -331,13 +333,13 @@ fn example() {
|
|||||||
],
|
],
|
||||||
{"color" : "red","price" : 19.95},
|
{"color" : "red","price" : 19.95},
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.store..price", "./benches/example.json");
|
let s = selector("$.store..price", "./benches/example.json");
|
||||||
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[2]", "./benches/example.json");
|
let s = selector("$..book[2]", "./benches/example.json");
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
"author" : "Herman Melville",
|
"author" : "Herman Melville",
|
||||||
@ -345,9 +347,9 @@ fn example() {
|
|||||||
"isbn" : "0-553-21311-3",
|
"isbn" : "0-553-21311-3",
|
||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}]);
|
}]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[-2]", "./benches/example.json");
|
let s = selector("$..book[-2]", "./benches/example.json");
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
"author" : "Herman Melville",
|
"author" : "Herman Melville",
|
||||||
@ -355,9 +357,9 @@ fn example() {
|
|||||||
"isbn" : "0-553-21311-3",
|
"isbn" : "0-553-21311-3",
|
||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}]);
|
}]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[0,1]", "./benches/example.json");
|
let s = selector("$..book[0,1]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category" : "reference",
|
"category" : "reference",
|
||||||
@ -372,9 +374,9 @@ fn example() {
|
|||||||
"price" : 12.99
|
"price" : 12.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[:2]", "./benches/example.json");
|
let s = selector("$..book[:2]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category" : "reference",
|
"category" : "reference",
|
||||||
@ -389,9 +391,9 @@ fn example() {
|
|||||||
"price" : 12.99
|
"price" : 12.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[2:]", "./benches/example.json");
|
let s = selector("$..book[2:]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
@ -408,9 +410,9 @@ fn example() {
|
|||||||
"price" : 22.99
|
"price" : 22.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json");
|
let s = selector("$..book[?(@.isbn)]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
@ -427,9 +429,9 @@ fn example() {
|
|||||||
"price" : 22.99
|
"price" : 22.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
let s = selector("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category" : "reference",
|
"category" : "reference",
|
||||||
@ -445,28 +447,27 @@ fn example() {
|
|||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(ret, jf.into_value());
|
assert_eq!(ret, s.select_as_value().unwrap());
|
||||||
|
|
||||||
let jf = do_filter("$..*", "./benches/example.json");
|
let s = selector("$..*", "./benches/example.json");
|
||||||
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
|
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
|
||||||
assert_eq!(json, jf.into_value());
|
assert_eq!(json, s.select_as_value().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn filer_same_obj() {
|
fn filer_same_obj() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
let mut jf = JsonValueFilter::new(r#"
|
let mut s = Selector::new();
|
||||||
|
let _ = s.path("$..[?(@.a == 1)]");
|
||||||
|
let _ = s.value_from_str(r#"
|
||||||
{
|
{
|
||||||
"a": 1,
|
"a": 1,
|
||||||
"b" : {"a": 1},
|
"b" : {"a": 1},
|
||||||
"c" : {"a": 1}
|
"c" : {"a": 1}
|
||||||
}
|
}
|
||||||
"#).unwrap();
|
"#);
|
||||||
let mut parser = Parser::new("$..[?(@.a == 1)]");
|
assert_eq!(s.select_as_value().unwrap(), json!([
|
||||||
parser.parse(&mut jf).unwrap();
|
|
||||||
let ret = jf.into_value();
|
|
||||||
assert_eq!(ret, json!([
|
|
||||||
{"a": 1},
|
{"a": 1},
|
||||||
{"a": 1}
|
{"a": 1}
|
||||||
]));
|
]));
|
||||||
|
31
tests/modifiable.rs
Normal file
31
tests/modifiable.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//extern crate indexmap;
|
||||||
|
//extern crate jsonpath_lib;
|
||||||
|
//#[macro_use]
|
||||||
|
//extern crate serde_json;
|
||||||
|
//
|
||||||
|
//use std::io::Read;
|
||||||
|
//
|
||||||
|
//use serde_json::Value;
|
||||||
|
//
|
||||||
|
//use jsonpath_lib::filter::value_filter::JsonValueFilter;
|
||||||
|
//use jsonpath_lib::parser::parser::Parser;
|
||||||
|
//use jsonpath_lib::ref_value::model::RefValue;
|
||||||
|
//
|
||||||
|
//fn setup() {
|
||||||
|
// let _ = env_logger::try_init();
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//fn do_filter(path: &str, file: &str) -> JsonValueFilter {
|
||||||
|
// let string = read_json(file);
|
||||||
|
// let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
|
||||||
|
// let mut parser = Parser::new(path);
|
||||||
|
// parser.parse(&mut jf).unwrap();
|
||||||
|
// jf
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//fn read_json(path: &str) -> String {
|
||||||
|
// let mut f = std::fs::File::open(path).unwrap();
|
||||||
|
// let mut contents = String::new();
|
||||||
|
// f.read_to_string(&mut contents).unwrap();
|
||||||
|
// contents
|
||||||
|
//}
|
139
wasm/src/lib.rs
139
wasm/src/lib.rs
@ -12,7 +12,7 @@ use std::collections::HashMap;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::sync::Mutex;
|
use std::sync::{Mutex, Arc};
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use jsonpath::filter::value_filter::JsonValueFilter;
|
use jsonpath::filter::value_filter::JsonValueFilter;
|
||||||
@ -23,6 +23,8 @@ use serde_json::Value;
|
|||||||
use wasm_bindgen::*;
|
use wasm_bindgen::*;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::console;
|
use web_sys::console;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use jsonpath::select::path_map::PathMap;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "wee_alloc")] {
|
if #[cfg(feature = "wee_alloc")] {
|
||||||
@ -43,13 +45,14 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||||
let mut jf = JsonValueFilter::new_from_value(json);
|
// let mut jf = JsonValueFilter::new(json, Arc::new(RefCell::new(PathMap::new())));
|
||||||
jf.visit(node);
|
// jf.visit(node);
|
||||||
let taken = &jf.take_value();
|
// let taken = &jf.clone_value();
|
||||||
match JsValue::from_serde(taken.deref()) {
|
// match JsValue::from_serde(taken.deref()) {
|
||||||
Ok(js_value) => js_value,
|
// Ok(js_value) => js_value,
|
||||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
// Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||||
}
|
// }
|
||||||
|
JsValue::from_str("")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
|
fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
|
||||||
@ -77,48 +80,51 @@ fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_ref_value(js_value: JsValue, node: Node) -> JsValue {
|
fn get_ref_value(js_value: JsValue, node: Node) -> JsValue {
|
||||||
match js_value.as_f64() {
|
// match js_value.as_f64() {
|
||||||
Some(val) => {
|
// Some(val) => {
|
||||||
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
// match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||||
Some(json) => filter_ref_value(json.clone(), node),
|
// Some(json) => filter_ref_value(json.clone(), node),
|
||||||
_ => JsValue::from_str("Invalid pointer")
|
// _ => JsValue::from_str("Invalid pointer")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => into_ref_value(&js_value, node)
|
// _ => into_ref_value(&js_value, node)
|
||||||
}
|
// }
|
||||||
|
JsValue::from_str("")
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
//lazy_static! {
|
||||||
static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
|
// static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
|
||||||
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
// static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
||||||
}
|
//}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = allocJson)]
|
#[wasm_bindgen(js_name = allocJson)]
|
||||||
pub extern fn alloc_json(js_value: JsValue) -> usize {
|
pub extern fn alloc_json(js_value: JsValue) -> usize {
|
||||||
let result: result::Result<RefValue, String> = into_serde_json(&js_value);
|
// let result: result::Result<RefValue, String> = into_serde_json(&js_value);
|
||||||
match result {
|
// match result {
|
||||||
Ok(json) => {
|
// Ok(json) => {
|
||||||
let mut map = CACHE_JSON.lock().unwrap();
|
// let mut map = CACHE_JSON.lock().unwrap();
|
||||||
if map.len() >= std::u8::MAX as usize {
|
// if map.len() >= std::u8::MAX as usize {
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
// let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
||||||
*idx += 1;
|
// *idx += 1;
|
||||||
map.insert(*idx, json.into());
|
// map.insert(*idx, json.into());
|
||||||
*idx
|
// *idx
|
||||||
}
|
// }
|
||||||
Err(e) => {
|
// Err(e) => {
|
||||||
console::error_1(&e.into());
|
// console::error_1(&e.into());
|
||||||
0
|
// 0
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = deallocJson)]
|
#[wasm_bindgen(js_name = deallocJson)]
|
||||||
pub extern fn dealloc_json(ptr: usize) -> bool {
|
pub extern fn dealloc_json(ptr: usize) -> bool {
|
||||||
let mut map = CACHE_JSON.lock().unwrap();
|
// let mut map = CACHE_JSON.lock().unwrap();
|
||||||
map.remove(&ptr).is_some()
|
// map.remove(&ptr).is_some()
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@ -139,32 +145,35 @@ pub fn compile(path: &str) -> JsValue {
|
|||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn selector(js_value: JsValue) -> JsValue {
|
pub fn selector(js_value: JsValue) -> JsValue {
|
||||||
let json = match js_value.as_f64() {
|
// let json = match js_value.as_f64() {
|
||||||
Some(val) => {
|
// Some(val) => {
|
||||||
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
// match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||||
Some(json) => json.clone(),
|
// Some(json) => json.clone(),
|
||||||
_ => return JsValue::from_str("Invalid pointer")
|
// _ => return JsValue::from_str("Invalid pointer")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => {
|
// _ => {
|
||||||
match into_serde_json::<RefValue>(&js_value) {
|
// match into_serde_json::<RefValue>(&js_value) {
|
||||||
Ok(json) => json.into(),
|
// Ok(json) => json.into(),
|
||||||
Err(e) => return JsValue::from_str(e.as_str())
|
// Err(e) => return JsValue::from_str(e.as_str())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
|
||||||
|
|
||||||
let cb = Closure::wrap(Box::new(move |path: String| {
|
// };
|
||||||
let mut parser = Parser::new(path.as_str());
|
|
||||||
match parser.compile() {
|
|
||||||
Ok(node) => filter_ref_value(json.clone(), node),
|
|
||||||
Err(e) => return JsValue::from_str(e.as_str())
|
|
||||||
}
|
|
||||||
}) as Box<Fn(String) -> JsValue>);
|
|
||||||
|
|
||||||
let ret = cb.as_ref().clone();
|
// let cb = Closure::wrap(Box::new(move |path: String| {
|
||||||
cb.forget();
|
// let mut parser = Parser::new(path.as_str());
|
||||||
ret
|
// match parser.compile() {
|
||||||
|
// Ok(node) => filter_ref_value(json.clone(), node),
|
||||||
|
// Err(e) => return JsValue::from_str(e.as_str())
|
||||||
|
// }
|
||||||
|
// }) as Box<Fn(String) -> JsValue>);
|
||||||
|
//
|
||||||
|
// let ret = cb.as_ref().clone();
|
||||||
|
// cb.forget();
|
||||||
|
// ret
|
||||||
|
|
||||||
|
JsValue::from_str("")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user