mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-24 08:52:17 +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
|
||||
!.idea/runConfigurations/
|
||||
/target/
|
||||
Cargo.lock
|
||||
Cargo.lock
|
||||
callgrind.out.*
|
@ -32,5 +32,5 @@ name = "jsonpath_lib"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[profile.release]
|
||||
#debug = true
|
||||
debug = true
|
||||
#lto = false
|
||||
|
@ -1,18 +1,20 @@
|
||||
#![feature(test)]
|
||||
extern crate bencher;
|
||||
extern crate indexmap;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate test;
|
||||
extern crate bencher;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use self::test::Bencher;
|
||||
use jsonpath::ref_value::model::RefValue;
|
||||
use serde::ser::Serialize;
|
||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||
use jsonpath::ref_value::ser::RefValueSerializer;
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
@ -107,22 +109,55 @@ fn bench_select_as(b: &mut Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_serde_ser(b: &mut Bencher) {
|
||||
fn refval_de(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _: RefValue = json.serialize(jsonpath::ref_value::ser::Serializer).unwrap().into();
|
||||
let _ = RefValue::deserialize(&json).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_serde_de(b: &mut Bencher) {
|
||||
let json_string = get_string();
|
||||
let json_str = json_string.as_str();
|
||||
fn refval_se(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = &json.serialize(RefValueSerializer).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.iter(move || for _ in 1..100 {
|
||||
let _: RefValue = serde_json::from_str(json_str).unwrap();
|
||||
#[bench]
|
||||
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 term;
|
||||
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::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)]
|
||||
pub enum TermContext {
|
||||
Constants(ExprTerm),
|
||||
Json(Option<ValueFilterKey>, ValueWrapper),
|
||||
Json(Option<ValueFilterKey>, ValueManager),
|
||||
}
|
||||
|
||||
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 {
|
||||
TermContext::Constants(et) => {
|
||||
match other {
|
||||
@ -17,9 +20,9 @@ impl TermContext {
|
||||
trace!("const-const");
|
||||
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");
|
||||
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 oc = ov.into_term(key_other);
|
||||
let mut c = v.into_term(key);
|
||||
let mut oc = ov.into_term(key_other);
|
||||
if is_json(&c) && is_json(&oc) {
|
||||
v.cmp(&ov, cmp_fn.into_type())
|
||||
} else {
|
||||
c.cmp(&oc, cmp_fn, default)
|
||||
c.cmp(&mut oc, cmp_fn, default)
|
||||
}
|
||||
}
|
||||
TermContext::Constants(et) => {
|
||||
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 {
|
||||
TermContext::Constants(et) => {
|
||||
match other {
|
||||
@ -67,7 +70,7 @@ impl TermContext {
|
||||
}
|
||||
}
|
||||
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");
|
||||
self.cmp(other, CmpEq, false)
|
||||
}
|
||||
|
||||
pub fn ne(&self, other: &TermContext) -> TermContext {
|
||||
pub fn ne(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("ne");
|
||||
self.cmp(other, CmpNe, true)
|
||||
}
|
||||
|
||||
pub fn gt(&self, other: &TermContext) -> TermContext {
|
||||
pub fn gt(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("gt");
|
||||
self.cmp(other, CmpGt, false)
|
||||
}
|
||||
|
||||
pub fn ge(&self, other: &TermContext) -> TermContext {
|
||||
pub fn ge(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("ge");
|
||||
self.cmp(other, CmpGe, false)
|
||||
}
|
||||
|
||||
pub fn lt(&self, other: &TermContext) -> TermContext {
|
||||
pub fn lt(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("lt");
|
||||
self.cmp(other, CmpLt, false)
|
||||
}
|
||||
|
||||
pub fn le(&self, other: &TermContext) -> TermContext {
|
||||
pub fn le(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("le");
|
||||
self.cmp(other, CmpLe, false)
|
||||
}
|
||||
|
||||
pub fn and(&self, other: &TermContext) -> TermContext {
|
||||
self.cmp_cond(other, CmpCondType::And)
|
||||
pub fn and(&mut self, other: &mut TermContext, path_map: Arc<RefCell<PathMap>>) -> TermContext {
|
||||
self.cmp_cond(other, CmpCondType::And, path_map)
|
||||
}
|
||||
|
||||
pub fn or(&self, other: &TermContext) -> TermContext {
|
||||
self.cmp_cond(other, CmpCondType::Or)
|
||||
pub fn or(&mut self, other: &mut TermContext, path_map: Arc<RefCell<PathMap>>) -> TermContext {
|
||||
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::result::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use filter::term::*;
|
||||
use filter::value_wrapper::*;
|
||||
use filter::value_manager::*;
|
||||
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
|
||||
use ref_value::model::*;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
use select::path_map::PathMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ValueFilterKey {
|
||||
@ -54,248 +17,136 @@ pub enum ValueFilterKey {
|
||||
All,
|
||||
}
|
||||
|
||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> 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>) {
|
||||
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<RefValueWrapper>) {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
if key.is_none() {
|
||||
for v in vec {
|
||||
for v in vec.iter() {
|
||||
buf.push(v.clone());
|
||||
}
|
||||
}
|
||||
for i in vec {
|
||||
traverse(key, i, buf);
|
||||
|
||||
for v in vec {
|
||||
collect_all(key, v, buf);
|
||||
}
|
||||
}
|
||||
RefValue::Object(v) => {
|
||||
for (k, v) in v.into_iter() {
|
||||
if match key {
|
||||
Some(map_key) => map_key == k,
|
||||
_ => true
|
||||
} {
|
||||
buf.push(v.clone());
|
||||
RefValue::Object(map) => {
|
||||
if let Some(k) = key {
|
||||
if let Some(val) = map.get(k) {
|
||||
buf.push(val.clone());
|
||||
}
|
||||
} else {
|
||||
let mut c = map.values().map(|v| v.clone()).collect();
|
||||
buf.append(&mut c);
|
||||
}
|
||||
for (_, v) in v.into_iter() {
|
||||
traverse(key, v, buf);
|
||||
for (_, v) in map {
|
||||
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)]
|
||||
pub struct ValueFilter {
|
||||
val_wrapper: ValueWrapper,
|
||||
value_mgr: ValueManager,
|
||||
last_key: Option<ValueFilterKey>,
|
||||
filter_mode: bool,
|
||||
is_relative: bool,
|
||||
path_map: Arc<RefCell<PathMap>>,
|
||||
}
|
||||
|
||||
impl ValueFilter {
|
||||
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
|
||||
ValueFilter { val_wrapper: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
||||
pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool, path_map: Arc<RefCell<PathMap>>) -> Self {
|
||||
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>) {
|
||||
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);
|
||||
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");
|
||||
self.step_leaves(None);
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueManager {
|
||||
debug!("step_leaves_string");
|
||||
self.step_leaves(Some(key));
|
||||
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");
|
||||
|
||||
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.val_wrapper.replace(RefValue::Array(vec).into());
|
||||
trace!("step_in_all - {:?}", self.val_wrapper.get_val());
|
||||
&self.val_wrapper
|
||||
self.value_mgr.replace(self.value_mgr.get_as_array());
|
||||
trace!("step_in_all - {:?}", self.value_mgr.get_val());
|
||||
&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");
|
||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||
, self.val_wrapper.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.val_wrapper.get_val());
|
||||
, self.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, 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.val_wrapper.replace(v);
|
||||
trace!("step_in_num - after: {:?}", self.val_wrapper.get_val());
|
||||
&self.val_wrapper
|
||||
self.last_key = Some(ValueFilterKey::Num(self.value_mgr.get_index(*key)));
|
||||
let v = self.value_mgr.get_with_num(key, self.is_relative);
|
||||
self.value_mgr.replace(v);
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
||||
pub fn step_in_string(&mut self, key: &String) -> &ValueManager {
|
||||
debug!("step_in_string");
|
||||
trace!("step_in_string - before: {},{},{:?}"
|
||||
, self.val_wrapper.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.val_wrapper.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.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, self.value_mgr.get_val());
|
||||
|
||||
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: {},{},{:?}"
|
||||
, self.val_wrapper.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.val_wrapper.get_val());
|
||||
&self.val_wrapper
|
||||
, self.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, self.value_mgr.get_val());
|
||||
&self.value_mgr
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JsonValueFilter {
|
||||
json: RefValueWrapper,
|
||||
path_map: Arc<RefCell<PathMap>>,
|
||||
filter_stack: Vec<ValueFilter>,
|
||||
token_stack: Vec<ParseToken>,
|
||||
term_stack: Vec<TermContext>,
|
||||
}
|
||||
|
||||
impl JsonValueFilter {
|
||||
pub fn new(json: &str) -> Result<Self, String> {
|
||||
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 {
|
||||
pub fn new(json: RefValueWrapper, path_map: Arc<RefCell<PathMap>>) -> Self {
|
||||
JsonValueFilter {
|
||||
json,
|
||||
path_map,
|
||||
filter_stack: Vec::new(),
|
||||
token_stack: Vec::new(),
|
||||
term_stack: Vec::new(),
|
||||
@ -303,90 +154,86 @@ impl JsonValueFilter {
|
||||
}
|
||||
|
||||
fn is_peek_token_array(&self) -> bool {
|
||||
if let Some(ParseToken::Array) = self.token_stack.last() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
if let Some(ParseToken::Array) = self.token_stack.last() { true } else { false }
|
||||
}
|
||||
|
||||
fn push_value_filter(&mut self, from_current: bool) {
|
||||
if from_current {
|
||||
fn create_new_filter(&mut self, is_relative: bool) {
|
||||
if is_relative {
|
||||
self.filter_stack.last()
|
||||
.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| {
|
||||
Some(self.filter_stack.push(vf))
|
||||
});
|
||||
} else {
|
||||
self.filter_stack.push({
|
||||
ValueFilter::new(self.json.clone(), false, from_current)
|
||||
});
|
||||
let vf = ValueFilter::new(
|
||||
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() {
|
||||
self.filter_stack.push(ValueFilter::new(v, is_leaves, false));
|
||||
} else {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
vf.val_wrapper.set_leaves(is_leaves);
|
||||
if v.is_null() {
|
||||
vf.val_wrapper.replace(v);
|
||||
} 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() {
|
||||
vf.val_wrapper.replace(v);
|
||||
}
|
||||
self.filter_stack.push(ValueFilter::new(
|
||||
v,
|
||||
is_leaves,
|
||||
false,
|
||||
self.path_map.clone(),
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
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 {
|
||||
match self.filter_stack.last() {
|
||||
Some(v) => v.val_wrapper.into_value(),
|
||||
Some(v) => v.value_mgr.into_value(),
|
||||
_ => Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.14", note = "Please use the clone_value function instead")]
|
||||
pub fn take_value(&mut self) -> RefValueWrapper {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(v) => v.val_wrapper.get_val().clone(),
|
||||
self.clone_value()
|
||||
}
|
||||
|
||||
pub fn clone_value(&mut self) -> RefValueWrapper {
|
||||
match self.filter_stack.last() {
|
||||
Some(v) => v.value_mgr.get_val().clone(),
|
||||
_ => 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();
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
||||
let mut ret = Vec::new();
|
||||
if let RefValue::Array(val) = vf.val_wrapper.get_val().deref() {
|
||||
for v in val {
|
||||
for i in &indices {
|
||||
let v = i.take_value(v);
|
||||
if !v.is_null() {
|
||||
ret.push(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(vf) => {
|
||||
if let Some(vec) = vf.value_mgr.pick_with_nums(indices) {
|
||||
vf.value_mgr.replace(vec);
|
||||
}
|
||||
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>) {
|
||||
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() {
|
||||
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
||||
let mut buf = Vec::new();
|
||||
if let RefValue::Array(vec) = vf.val_wrapper.get_val().deref() {
|
||||
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);
|
||||
}
|
||||
Some(ref mut vf) => {
|
||||
if let Some(vec) = vf.value_mgr.range_with(from, to) {
|
||||
vf.value_mgr.replace(vec);
|
||||
}
|
||||
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))) => {
|
||||
self.replace_filter_stack(RefValue::Null.into(), false);
|
||||
self.append_to_current_filter(RefValue::Null.into(), false);
|
||||
}
|
||||
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() {
|
||||
Some(vf) => {
|
||||
let is_leaves = vf.val_wrapper.is_leaves();
|
||||
match vf.val_wrapper.get_val().deref() {
|
||||
match vf.value_mgr.get_val().deref() {
|
||||
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);
|
||||
|
||||
if left.is_some() && right.is_some() {
|
||||
let left = left.unwrap();
|
||||
let right = right.unwrap();
|
||||
let mut left = left.unwrap();
|
||||
let mut right = right.unwrap();
|
||||
|
||||
let tc = match ft {
|
||||
FilterToken::Equal => left.eq(&right),
|
||||
FilterToken::NotEqual => left.ne(&right),
|
||||
FilterToken::Greater => left.gt(&right),
|
||||
FilterToken::GreaterOrEqual => left.ge(&right),
|
||||
FilterToken::Little => left.lt(&right),
|
||||
FilterToken::LittleOrEqual => left.le(&right),
|
||||
FilterToken::And => left.and(&right),
|
||||
FilterToken::Or => left.or(&right),
|
||||
FilterToken::Equal => left.eq(&mut right),
|
||||
FilterToken::NotEqual => left.ne(&mut right),
|
||||
FilterToken::Greater => left.gt(&mut right),
|
||||
FilterToken::GreaterOrEqual => left.ge(&mut right),
|
||||
FilterToken::Little => left.lt(&mut right),
|
||||
FilterToken::LittleOrEqual => left.le(&mut right),
|
||||
FilterToken::And => left.and(&mut right, self.path_map.clone()),
|
||||
FilterToken::Or => left.or(&mut right, self.path_map.clone()),
|
||||
};
|
||||
self.term_stack.push(tc);
|
||||
}
|
||||
@ -556,7 +368,7 @@ impl NodeVisitor for JsonValueFilter {
|
||||
if self.is_peek_token_array() {
|
||||
self.token_stack.pop();
|
||||
}
|
||||
self.push_value_filter(ParseToken::Relative == token);
|
||||
self.create_new_filter(ParseToken::Relative == token);
|
||||
}
|
||||
ParseToken::In
|
||||
| ParseToken::Leaves => {
|
||||
@ -609,7 +421,7 @@ impl NodeVisitor for JsonValueFilter {
|
||||
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
||||
match self.filter_stack.pop() {
|
||||
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;
|
||||
|
||||
pub use select::selector::Selector;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod parser;
|
||||
#[doc(hidden)]
|
||||
@ -181,8 +183,6 @@ pub mod ref_value;
|
||||
#[doc(hidden)]
|
||||
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.
|
||||
///
|
||||
/// ```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> {
|
||||
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")]
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
@ -5,13 +7,25 @@ use std::sync::Arc;
|
||||
use indexmap::map::IndexMap;
|
||||
use serde::ser::Serialize;
|
||||
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 {
|
||||
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 {
|
||||
@ -26,10 +40,16 @@ impl Deref for RefValueWrapper {
|
||||
type Target = RefValue;
|
||||
|
||||
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 {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.deref().hash(state)
|
||||
@ -120,7 +140,6 @@ impl RefIndex for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RefValue {
|
||||
Null,
|
||||
Bool(bool),
|
||||
@ -130,6 +149,12 @@ pub enum RefValue {
|
||||
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 {
|
||||
fn eq(&self, other: &RefValue) -> bool {
|
||||
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 {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
|
||||
// println!("###hash - RefValue - {:?}", self);
|
||||
|
||||
match self {
|
||||
RefValue::Null => {
|
||||
REF_VALUE_NULL.hash(state)
|
||||
@ -188,71 +216,40 @@ impl RefValue {
|
||||
}
|
||||
|
||||
pub fn is_object(&self) -> bool {
|
||||
self.as_object().is_some()
|
||||
}
|
||||
|
||||
pub fn as_object(&self) -> Option<&IndexMap<String, RefValueWrapper>> {
|
||||
match *self {
|
||||
RefValue::Object(ref map) => Some(map),
|
||||
_ => 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,
|
||||
RefValue::Object(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_number(&self) -> Option<Number> {
|
||||
pub fn is_array(&self) -> bool {
|
||||
match *self {
|
||||
RefValue::Number(ref n) => Some(n.clone()),
|
||||
_ => None,
|
||||
RefValue::Array(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_boolean(&self) -> bool {
|
||||
self.as_bool().is_some()
|
||||
pub fn len(&self) -> usize {
|
||||
match &self {
|
||||
RefValue::Object(m) => m.len(),
|
||||
RefValue::Array(v) => v.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bool(&self) -> Option<bool> {
|
||||
match *self {
|
||||
RefValue::Bool(b) => Some(b),
|
||||
_ => None,
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match &self {
|
||||
RefValue::Object(m) => m.is_empty(),
|
||||
RefValue::Array(v) => v.is_empty(),
|
||||
RefValue::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.as_null().is_some()
|
||||
}
|
||||
|
||||
pub fn as_null(&self) -> Option<()> {
|
||||
match *self {
|
||||
RefValue::Null => Some(()),
|
||||
_ => None,
|
||||
RefValue::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,14 +257,14 @@ impl RefValue {
|
||||
impl Into<RefValueWrapper> for RefValue {
|
||||
fn into(self) -> RefValueWrapper {
|
||||
RefValueWrapper {
|
||||
data: Arc::new(Box::new(self))
|
||||
data: Arc::new(RefCell::new(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RefValue> for &Value {
|
||||
fn into(self) -> RefValue {
|
||||
match self.serialize(super::ser::Serializer) {
|
||||
match self.serialize(super::ser::RefValueSerializer) {
|
||||
Ok(v) => v,
|
||||
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||
}
|
||||
@ -276,7 +273,7 @@ impl Into<RefValue> for &Value {
|
||||
|
||||
impl Into<RefValueWrapper> for &Value {
|
||||
fn into(self) -> RefValueWrapper {
|
||||
match self.serialize(super::ser::Serializer) {
|
||||
match self.serialize(super::ser::RefValueSerializer) {
|
||||
Ok(v) => v.into(),
|
||||
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 Error = SerdeError;
|
||||
|
||||
@ -170,7 +170,7 @@ impl serde::Serializer for Serializer {
|
||||
{
|
||||
let mut values: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
values.insert(String::from(variant), {
|
||||
value.serialize(Serializer)?.into()
|
||||
value.serialize(RefValueSerializer)?.into()
|
||||
});
|
||||
Ok(RefValue::Object(values))
|
||||
}
|
||||
@ -280,7 +280,7 @@ impl serde::ser::SerializeSeq for SerializeVec {
|
||||
T: Serialize,
|
||||
{
|
||||
self.vec.push({
|
||||
value.serialize(Serializer)?.into()
|
||||
value.serialize(RefValueSerializer)?.into()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@ -331,7 +331,7 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||
T: Serialize,
|
||||
{
|
||||
self.vec.push({
|
||||
let a: RefValue = value.serialize(Serializer)?;
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
@ -378,7 +378,7 @@ impl serde::ser::SerializeMap for SerializeMap {
|
||||
// expected failure.
|
||||
let key = key.expect("serialize_value called before serialize_key");
|
||||
map.insert(key, {
|
||||
let a: RefValue = value.serialize(Serializer)?;
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
@ -608,7 +608,7 @@ impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
||||
T: Serialize,
|
||||
{
|
||||
self.map.insert(String::from(key), {
|
||||
let a: RefValue = value.serialize(Serializer)?;
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
|
@ -1,239 +1,3 @@
|
||||
use std::{fmt, result};
|
||||
use std::ops::Deref;
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod selector;
|
||||
pub mod modifiable;
|
||||
pub mod path_map;
|
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::parser::parser::Parser;
|
||||
use jsonpath::Selector;
|
||||
|
||||
fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
fn new_value_filter(file: &str) -> ValueFilter {
|
||||
let string = read_json(file);
|
||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
ValueFilter::new((&json).into(), false, false)
|
||||
}
|
||||
//fn new_value_filter(file: &str) -> ValueFilter {
|
||||
// let string = read_json(file);
|
||||
// let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
// 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 mut jf = JsonValueFilter::new(string.as_str()).unwrap();
|
||||
let mut parser = Parser::new(path);
|
||||
parser.parse(&mut jf).unwrap();
|
||||
jf
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path(path);
|
||||
let _ = s.value_from_str(&string);
|
||||
s
|
||||
}
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
@ -36,53 +37,53 @@ fn read_json(path: &str) -> String {
|
||||
contents
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn step_in() {
|
||||
setup();
|
||||
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
let current = jf.step_in_str("friends");
|
||||
assert_eq!(current.is_array(), true);
|
||||
}
|
||||
|
||||
let mut jf = new_value_filter("./benches/data_array.json");
|
||||
{
|
||||
let current = jf.step_in_num(&1.0);
|
||||
assert_eq!(current.get_val().is_object(), true);
|
||||
}
|
||||
{
|
||||
let current = jf.step_in_str("friends");
|
||||
assert_eq!(current.is_array(), true);
|
||||
}
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
jf.step_in_str("school");
|
||||
jf.step_in_str("friends");
|
||||
jf.step_in_all();
|
||||
let current = jf.step_in_str("name");
|
||||
let friends = json!([
|
||||
"Millicent Norman",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
|
||||
assert_eq!(friends, current.into_value());
|
||||
}
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
let current = jf.step_leaves_str("name");
|
||||
let names = json!([
|
||||
"Leonor Herman",
|
||||
"Millicent Norman",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
assert_eq!(names, current.into_value());
|
||||
}
|
||||
}
|
||||
//#[test]
|
||||
//fn step_in() {
|
||||
// setup();
|
||||
//
|
||||
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
// {
|
||||
// let current = jf.step_in_str("friends");
|
||||
// assert_eq!(current.is_array(), true);
|
||||
// }
|
||||
//
|
||||
// let mut jf = new_value_filter("./benches/data_array.json");
|
||||
// {
|
||||
// let current = jf.step_in_num(&1.0);
|
||||
// assert_eq!(current.get_val().is_object(), true);
|
||||
// }
|
||||
// {
|
||||
// let current = jf.step_in_str("friends");
|
||||
// assert_eq!(current.is_array(), true);
|
||||
// }
|
||||
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
// {
|
||||
// jf.step_in_str("school");
|
||||
// jf.step_in_str("friends");
|
||||
// jf.step_in_all();
|
||||
// let current = jf.step_in_str("name");
|
||||
// let friends = json!([
|
||||
// "Millicent Norman",
|
||||
// "Vincent Cannon",
|
||||
// "Gray Berry"
|
||||
// ]);
|
||||
//
|
||||
// assert_eq!(friends, current.into_value());
|
||||
// }
|
||||
// let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
// {
|
||||
// let current = jf.step_leaves_str("name");
|
||||
// let names = json!([
|
||||
// "Leonor Herman",
|
||||
// "Millicent Norman",
|
||||
// "Vincent Cannon",
|
||||
// "Gray Berry",
|
||||
// "Vincent Cannon",
|
||||
// "Gray Berry"
|
||||
// ]);
|
||||
// assert_eq!(names, current.into_value());
|
||||
// }
|
||||
//}
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
@ -93,33 +94,33 @@ fn array() {
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]);
|
||||
|
||||
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
let s = selector("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
let s = selector("$.school.friends[1:]", "./benches/data_obj.json");
|
||||
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!([
|
||||
{"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"]);
|
||||
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"]);
|
||||
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"]);
|
||||
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");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -134,32 +135,32 @@ fn return_type() {
|
||||
]
|
||||
});
|
||||
|
||||
let jf = do_filter("$.school", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
let s = selector("$.school", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
let s = selector("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, jf.into_value());
|
||||
let s = selector("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, s.select_as_value().unwrap());
|
||||
|
||||
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.into_value());
|
||||
let s = selector("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||
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!([
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]);
|
||||
assert_eq!(friends, jf.into_value());
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_default() {
|
||||
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!({
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
@ -167,54 +168,55 @@ fn op_default() {
|
||||
{"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!([
|
||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
||||
{ "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!([
|
||||
{ "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!([
|
||||
{ "id" : 2, "name" : "Gray Berry" },
|
||||
{ "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");
|
||||
assert_eq!(Value::Null, jf.into_value());
|
||||
let s = selector("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
assert_eq!(friends, jf.into_value());
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let ref value = json!([
|
||||
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
||||
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
||||
]);
|
||||
let mut jf = JsonValueFilter::new_from_value(value.into());
|
||||
let mut parser = Parser::new("$..[?(@.age > 40)]");
|
||||
parser.parse(&mut jf).unwrap();
|
||||
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path("$..[?(@.age > 40)]");
|
||||
let _ = s.value(value);
|
||||
let friends = json!([
|
||||
{ "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!({
|
||||
"school": {
|
||||
@ -227,11 +229,11 @@ fn op_default() {
|
||||
{"name": "친구3", "age": 30},
|
||||
{"name": "친구4"}
|
||||
]});
|
||||
let mut jf = JsonValueFilter::new_from_value(value.into());
|
||||
let mut parser = Parser::new("$..[?(@.age >= 30)]");
|
||||
parser.parse(&mut jf).unwrap();
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path("$..[?(@.age >= 30)]");
|
||||
let _ = s.value(value);
|
||||
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
|
||||
assert_eq!(friends, jf.into_value());
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -314,14 +316,14 @@ fn op_complex() {
|
||||
fn example() {
|
||||
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"]);
|
||||
assert_eq!(ret, jf.into_value());
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
|
||||
let jf = do_filter("$..author", "./benches/example.json");
|
||||
assert_eq!(ret, jf.into_value());
|
||||
let s = selector("$..author", "./benches/example.json");
|
||||
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!([
|
||||
[
|
||||
{"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
|
||||
@ -331,13 +333,13 @@ fn example() {
|
||||
],
|
||||
{"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]);
|
||||
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!([{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
@ -345,9 +347,9 @@ fn example() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"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!([{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
@ -355,9 +357,9 @@ fn example() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"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!([
|
||||
{
|
||||
"category" : "reference",
|
||||
@ -372,9 +374,9 @@ fn example() {
|
||||
"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!([
|
||||
{
|
||||
"category" : "reference",
|
||||
@ -389,9 +391,9 @@ fn example() {
|
||||
"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!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
@ -408,9 +410,9 @@ fn example() {
|
||||
"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!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
@ -427,9 +429,9 @@ fn example() {
|
||||
"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!([
|
||||
{
|
||||
"category" : "reference",
|
||||
@ -445,28 +447,27 @@ fn example() {
|
||||
"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();
|
||||
assert_eq!(json, jf.into_value());
|
||||
assert_eq!(json, s.select_as_value().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filer_same_obj() {
|
||||
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,
|
||||
"b" : {"a": 1},
|
||||
"c" : {"a": 1}
|
||||
}
|
||||
"#).unwrap();
|
||||
let mut parser = Parser::new("$..[?(@.a == 1)]");
|
||||
parser.parse(&mut jf).unwrap();
|
||||
let ret = jf.into_value();
|
||||
assert_eq!(ret, json!([
|
||||
"#);
|
||||
assert_eq!(s.select_as_value().unwrap(), json!([
|
||||
{"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::result;
|
||||
use std::result::Result;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Mutex, Arc};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use jsonpath::filter::value_filter::JsonValueFilter;
|
||||
@ -23,6 +23,8 @@ use serde_json::Value;
|
||||
use wasm_bindgen::*;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::console;
|
||||
use std::cell::RefCell;
|
||||
use jsonpath::select::path_map::PathMap;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "wee_alloc")] {
|
||||
@ -43,13 +45,14 @@ cfg_if! {
|
||||
}
|
||||
|
||||
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||
let mut jf = JsonValueFilter::new_from_value(json);
|
||||
jf.visit(node);
|
||||
let taken = &jf.take_value();
|
||||
match JsValue::from_serde(taken.deref()) {
|
||||
Ok(js_value) => js_value,
|
||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||
}
|
||||
// let mut jf = JsonValueFilter::new(json, Arc::new(RefCell::new(PathMap::new())));
|
||||
// jf.visit(node);
|
||||
// let taken = &jf.clone_value();
|
||||
// match JsValue::from_serde(taken.deref()) {
|
||||
// Ok(js_value) => js_value,
|
||||
// Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||
// }
|
||||
JsValue::from_str("")
|
||||
}
|
||||
|
||||
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 {
|
||||
match js_value.as_f64() {
|
||||
Some(val) => {
|
||||
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||
Some(json) => filter_ref_value(json.clone(), node),
|
||||
_ => JsValue::from_str("Invalid pointer")
|
||||
}
|
||||
}
|
||||
_ => into_ref_value(&js_value, node)
|
||||
}
|
||||
// match js_value.as_f64() {
|
||||
// Some(val) => {
|
||||
// match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||
// Some(json) => filter_ref_value(json.clone(), node),
|
||||
// _ => JsValue::from_str("Invalid pointer")
|
||||
// }
|
||||
// }
|
||||
// _ => into_ref_value(&js_value, node)
|
||||
// }
|
||||
JsValue::from_str("")
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
|
||||
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
||||
}
|
||||
//lazy_static! {
|
||||
// static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
|
||||
// static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
||||
//}
|
||||
|
||||
#[wasm_bindgen(js_name = allocJson)]
|
||||
pub extern fn alloc_json(js_value: JsValue) -> usize {
|
||||
let result: result::Result<RefValue, String> = into_serde_json(&js_value);
|
||||
match result {
|
||||
Ok(json) => {
|
||||
let mut map = CACHE_JSON.lock().unwrap();
|
||||
if map.len() >= std::u8::MAX as usize {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
||||
*idx += 1;
|
||||
map.insert(*idx, json.into());
|
||||
*idx
|
||||
}
|
||||
Err(e) => {
|
||||
console::error_1(&e.into());
|
||||
0
|
||||
}
|
||||
}
|
||||
// let result: result::Result<RefValue, String> = into_serde_json(&js_value);
|
||||
// match result {
|
||||
// Ok(json) => {
|
||||
// let mut map = CACHE_JSON.lock().unwrap();
|
||||
// if map.len() >= std::u8::MAX as usize {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
||||
// *idx += 1;
|
||||
// map.insert(*idx, json.into());
|
||||
// *idx
|
||||
// }
|
||||
// Err(e) => {
|
||||
// console::error_1(&e.into());
|
||||
// 0
|
||||
// }
|
||||
// }
|
||||
0
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = deallocJson)]
|
||||
pub extern fn dealloc_json(ptr: usize) -> bool {
|
||||
let mut map = CACHE_JSON.lock().unwrap();
|
||||
map.remove(&ptr).is_some()
|
||||
// let mut map = CACHE_JSON.lock().unwrap();
|
||||
// map.remove(&ptr).is_some()
|
||||
false
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -139,32 +145,35 @@ pub fn compile(path: &str) -> JsValue {
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn selector(js_value: JsValue) -> JsValue {
|
||||
let json = match js_value.as_f64() {
|
||||
Some(val) => {
|
||||
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||
Some(json) => json.clone(),
|
||||
_ => return JsValue::from_str("Invalid pointer")
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match into_serde_json::<RefValue>(&js_value) {
|
||||
Ok(json) => json.into(),
|
||||
Err(e) => return JsValue::from_str(e.as_str())
|
||||
}
|
||||
}
|
||||
};
|
||||
// let json = match js_value.as_f64() {
|
||||
// Some(val) => {
|
||||
// match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||
// Some(json) => json.clone(),
|
||||
// _ => return JsValue::from_str("Invalid pointer")
|
||||
// }
|
||||
// }
|
||||
// _ => {
|
||||
// match into_serde_json::<RefValue>(&js_value) {
|
||||
// Ok(json) => json.into(),
|
||||
// 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();
|
||||
cb.forget();
|
||||
ret
|
||||
// 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();
|
||||
// cb.forget();
|
||||
// ret
|
||||
|
||||
JsValue::from_str("")
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
Loading…
x
Reference in New Issue
Block a user