From d2a5d9092ecd35ce0ded8df0dbde7fac23ccef07 Mon Sep 17 00:00:00 2001 From: freestrings Date: Sun, 26 May 2019 23:30:01 +0900 Subject: [PATCH 01/15] refactoring done default --- .gitignore | 3 +- Cargo.toml | 2 +- benches/bench.rs | 57 +++- benches/bench_example.rs | 81 ++++++ profiling.sh | 9 + src/filter/mod.rs | 4 +- src/filter/term.rs | 47 ++-- src/filter/value_filter.rs | 456 +++++++++---------------------- src/filter/value_manager.rs | 524 ++++++++++++++++++++++++++++++++++++ src/filter/value_wrapper.rs | 307 --------------------- src/lib.rs | 6 +- src/ref_value/model.rs | 113 ++++---- src/ref_value/ser.rs | 14 +- src/select/mod.rs | 242 +---------------- src/select/modifiable.rs | 60 +++++ src/select/path_map.rs | 53 ++++ src/select/selector.rs | 266 ++++++++++++++++++ tests/filter.rs | 271 +++++++++---------- tests/modifiable.rs | 31 +++ wasm/src/lib.rs | 139 +++++----- 20 files changed, 1513 insertions(+), 1172 deletions(-) create mode 100644 benches/bench_example.rs create mode 100755 profiling.sh create mode 100644 src/filter/value_manager.rs delete mode 100644 src/filter/value_wrapper.rs create mode 100644 src/select/modifiable.rs create mode 100644 src/select/path_map.rs create mode 100644 src/select/selector.rs create mode 100644 tests/modifiable.rs diff --git a/.gitignore b/.gitignore index 8647db2..5e2c017 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode !.idea/runConfigurations/ /target/ -Cargo.lock \ No newline at end of file +Cargo.lock +callgrind.out.* \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 52ca42a..80354a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,5 +32,5 @@ name = "jsonpath_lib" path = "src/lib.rs" [profile.release] -#debug = true +debug = true #lto = false diff --git a/benches/bench.rs b/benches/bench.rs index 33c5cbf..55fcb58 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -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 = 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 = vec.iter().map(|v| v.clone()).collect(); + } + } }); } \ No newline at end of file diff --git a/benches/bench_example.rs b/benches/bench_example.rs new file mode 100644 index 0000000..d2e8322 --- /dev/null +++ b/benches/bench_example.rs @@ -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); diff --git a/profiling.sh b/profiling.sh new file mode 100755 index 0000000..c262a73 --- /dev/null +++ b/profiling.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +valgrind \ + --tool=callgrind \ + --dump-instr=yes \ + --collect-jumps=yes \ + --simulate-cache=yes $1 -- $2 \ No newline at end of file diff --git a/src/filter/mod.rs b/src/filter/mod.rs index b3b7581..472c2b9 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -1,4 +1,6 @@ mod cmp; mod term; pub mod value_filter; -pub mod value_wrapper; \ No newline at end of file +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; \ No newline at end of file diff --git a/src/filter/term.rs b/src/filter/term.rs index 8a1571f..a5b8d03 100644 --- a/src/filter/term.rs +++ b/src/filter/term.rs @@ -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, ValueWrapper), + Json(Option, ValueManager), } impl TermContext { - fn cmp(&self, other: &TermContext, cmp_fn: F, default: bool) -> TermContext { + fn cmp(&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>) -> 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>) -> 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>) -> TermContext { + self.cmp_cond(other, CmpCondType::Or, path_map) } } diff --git a/src/filter/value_filter.rs b/src/filter/value_filter.rs index fb8c82b..839f4b8 100644 --- a/src/filter/value_filter.rs +++ b/src/filter/value_filter.rs @@ -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>(iter: I) -> Vec { - iter - .map(|v| v.clone()) - .filter(|v| !v.is_null()) - .collect() -} - -fn get_nested_array(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) { +fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec) { 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 { - 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, - filter_mode: bool, + is_relative: bool, + path_map: Arc>, } 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>) -> 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>, filter_stack: Vec, token_stack: Vec, term_stack: Vec, } impl JsonValueFilter { - pub fn new(json: &str) -> Result { - 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>) -> 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(&mut self, indices: Vec) { + fn token_union(&mut self, indices: Vec) { 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, to: Option) { self.token_stack.pop(); - fn _from_to(from: Option, to: Option, 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 { - 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 = _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 = _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)); } _ => {} } diff --git a/src/filter/value_manager.rs b/src/filter/value_manager.rs new file mode 100644 index 0000000..e0a7690 --- /dev/null +++ b/src/filter/value_manager.rs @@ -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(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, + F: FnMut(&RefValueWrapper) -> RefValueWrapper>(iter: I, func: F) -> Vec +{ + iter.map(func) + .filter(|v| !v.is_null()) + .collect() +} + +fn collect_some<'a, + I: Iterator, + F: FnMut(&RefValueWrapper) -> Option>(iter: I, func: F) -> Vec +{ + iter.map(func) + .filter(|v| v.is_some()) + .map(|v| v.unwrap()) + .collect() +} + +fn get_in_array(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option { + 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 { + 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(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option { + 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 { + 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 { + 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>, + is_leaves: bool, +} + +impl ValueManager { + pub fn new(val: RefValueWrapper, is_leaves: bool, path_map: Arc>) -> 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(&self, key: &Option, 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(&self, i: I) -> usize { + i.index(&self.val) + } + + pub fn get_with_num(&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, to: Option) -> Option { + fn _from(from: Option, val: &RefValueWrapper) -> usize { + match from { + Some(v) => v.index(val), + _ => 0 + } + } + + fn _to(to: Option, 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 { + 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(&self, indices: Vec) -> Option { + 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 = 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 = 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) -> 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) -> 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()) + } +} diff --git a/src/filter/value_wrapper.rs b/src/filter/value_wrapper.rs deleted file mode 100644 index 7782f8e..0000000 --- a/src/filter/value_wrapper.rs +++ /dev/null @@ -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(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(&self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option { - fn _filter_with_object 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(&self, key: &Option, et: &ExprTerm, cmp: &F, reverse: bool) -> Option { - match key { - Some(ValueFilterKey::String(key)) => { - self.take_object_in_array(key, et, cmp, reverse) - } - _ => None - } - } - - pub fn take_with(&self, key: &Option, 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 = 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 = 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) -> 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) -> 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) - } -} diff --git a/src/lib.rs b/src/lib.rs index 6fa94e4..5121a55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 result::Result { 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")] diff --git a/src/ref_value/model.rs b/src/ref_value/model.rs index 694dd9d..5c6e76a 100644 --- a/src/ref_value/model.rs +++ b/src/ref_value/model.rs @@ -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>; +type TypeRefValue = Arc>; -#[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(&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), } +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(&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> { 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> { - 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 { + 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 { - 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 for RefValue { fn into(self) -> RefValueWrapper { RefValueWrapper { - data: Arc::new(Box::new(self)) + data: Arc::new(RefCell::new(self)) } } } impl Into 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 for &Value { impl Into 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) } diff --git a/src/ref_value/ser.rs b/src/ref_value/ser.rs index c4b65fb..22e0c68 100644 --- a/src/ref_value/ser.rs +++ b/src/ref_value/ser.rs @@ -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 = 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(()) diff --git a/src/select/mod.rs b/src/select/mod.rs index 66fd576..45c77d9 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -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, -/// 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 { -/// 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::>().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::>().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::(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(), -/// selector.get().unwrap()); -/// -/// selector.value_from_str(input_str()).unwrap() -/// .map_as(|mut v: Vec| { -/// 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::>().unwrap()); -/// ``` -#[derive(Debug)] -pub struct Selector { - pub(crate) node: Option, - pub(crate) value: Option, -} - -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 { - match &self.value { - Some(v) => Ok(JsonValueFilter::new_from_value(v.clone())), - _ => return Err(SelectorErrorMessage::EmptyValue.to_string()) - } - } - - fn select(&self) -> result::Result { - 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 { - 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 { - self.select_as_value() - } - - #[deprecated(since = "0.1.13", note = "Please use the select_as function instead")] - pub fn select_to(&self) -> result::Result { - self.select_as() - } - - pub fn select_as_str(&self) -> result::Result { - serde_json::to_string(self.select()?.deref()).map_err(|e| e.to_string()) - } - - pub fn select_as_value(&self) -> result::Result { - Ok((&self.select()?).into()) - } - - pub fn select_as(&self) -> result::Result { - T::deserialize(self.select()?.deref()).map_err(|e| e.to_string()) - } - - pub fn map(&mut self, func: F) -> result::Result<&mut Self, String> - where F: FnOnce(Value) -> Option - { - self.value = func((&self.select()?).into()).map(|ref v| v.into()); - Ok(self) - } - - pub fn map_as(&mut self, func: F) -> result::Result<&mut Self, String> - where F: FnOnce(D) -> Option, - 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 { - match &self.value { - Some(value) => Ok(value.into()), - _ => Err(SelectorErrorMessage::EmptyValue.to_string()) - } - } - - pub fn get_as(&self) -> result::Result { - 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; \ No newline at end of file diff --git a/src/select/modifiable.rs b/src/select/modifiable.rs new file mode 100644 index 0000000..3fca8f2 --- /dev/null +++ b/src/select/modifiable.rs @@ -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, 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, +} + +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) + } +} \ No newline at end of file diff --git a/src/select/path_map.rs b/src/select/path_map.rs new file mode 100644 index 0000000..82154a0 --- /dev/null +++ b/src/select/path_map.rs @@ -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 +} + +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); + } + } +} \ No newline at end of file diff --git a/src/select/selector.rs b/src/select/selector.rs new file mode 100644 index 0000000..2447ee3 --- /dev/null +++ b/src/select/selector.rs @@ -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, +/// 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 { +/// 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::>().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::>().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::(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(), +/// selector.get().unwrap()); +/// +/// selector.value_from_str(input_str()).unwrap() +/// .map_as(|mut v: Vec| { +/// 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::>().unwrap()); +/// ``` +#[derive(Debug)] +pub struct Selector { + pub(crate) node: Option, + pub(crate) value: Option, + path_builder: Arc>, +} + +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 { + 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 { + 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 { + 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 { + self.select_as_value() + } + + #[deprecated(since = "0.1.13", note = "Please use the select_as function instead")] + pub fn select_to(&self) -> result::Result { + self.select_as() + } + + pub fn select_as_str(&self) -> result::Result { + 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 { + Ok((&self.select()?).into()) + } + + pub fn select_as(&self) -> result::Result { + T::deserialize(self.select()?.deref()).map_err(|e| e.to_string()) + } + + pub fn map(&mut self, func: F) -> result::Result<&mut Self, String> + where F: FnOnce(Value) -> Option + { + match func((&self.select()?).into()).map(|ref v| v.into()) { + Some(value) => { + self.set_value(value) + }, + _ => {} + } + Ok(self) + } + + pub fn map_as(&mut self, func: F) -> result::Result<&mut Self, String> + where F: FnOnce(D) -> Option, + 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 { + match &self.value { + Some(value) => Ok(value.into()), + _ => Err(SelectorErrorMessage::EmptyValue.to_string()) + } + } + + pub fn get_as(&self) -> result::Result { + 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"), + } + } +} diff --git a/tests/filter.rs b/tests/filter.rs index b47e241..b9f22a3 100644 --- a/tests/filter.rs +++ b/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} ])); diff --git a/tests/modifiable.rs b/tests/modifiable.rs new file mode 100644 index 0000000..85ac548 --- /dev/null +++ b/tests/modifiable.rs @@ -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 +//} diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index a495d24..fbf78ad 100644 --- a/wasm/src/lib.rs +++ b/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(js_value: &JsValue) -> Result @@ -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> = Mutex::new(HashMap::new()); - static ref CACHE_JSON_IDX: Mutex = Mutex::new(0); -} +//lazy_static! { +// static ref CACHE_JSON: Mutex> = Mutex::new(HashMap::new()); +// static ref CACHE_JSON_IDX: Mutex = Mutex::new(0); +//} #[wasm_bindgen(js_name = allocJson)] pub extern fn alloc_json(js_value: JsValue) -> usize { - let result: result::Result = 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 = 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::(&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::(&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 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 JsValue>); +// +// let ret = cb.as_ref().clone(); +// cb.forget(); +// ret + + JsValue::from_str("") } #[wasm_bindgen] From 3f89b9b183ff900e6a9af439161b988334e34bb6 Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 27 May 2019 11:42:46 +0900 Subject: [PATCH 02/15] remove alloc, dealloc in wasm --- README.md | 59 +----------------- benches/bench.rs | 10 +++ benches/bench_example.rs | 87 ++++++++++++++++++-------- benches/javascript/bench.js | 33 ---------- src/filter/term.rs | 17 +++--- src/filter/value_filter.rs | 22 ++----- src/filter/value_manager.rs | 27 +++------ src/select/mod.rs | 3 +- src/select/path_map.rs | 53 ---------------- src/select/selector.rs | 15 +---- tests/filter.rs | 107 ++++++++++++++++---------------- wasm/src/lib.rs | 118 +++++++----------------------------- wasm/tests/web.rs | 14 ----- wasm/www_bench/index.js | 9 --- 14 files changed, 176 insertions(+), 398 deletions(-) delete mode 100644 src/select/path_map.rs diff --git a/README.md b/README.md index 0ad07c3..71e19b1 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine writte - [Javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string) - [Javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string) - [Javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject) -- [Javascript - allocJson, deallocJson (Webassembly Only)](#javascript---allocjson-deallocjson-webassembly-only) - [Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples) --- @@ -532,60 +531,4 @@ console.log( ); // => true, true -``` - -#### Javascript - allocJson, deallocJson (Webassembly Only) -wasm-bindgen은 Javascript와 Webassembly간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체는 Webassembly 영역에 생성해 두면 성능에 도움이 된다. - -Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, creating frequently used JSON objects in the WebAssembly area helps performance. - -```javascript -const jsonpath = require('jsonpath-wasm'); - -let jsonObj = { - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] - }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] -}; - -// allocate jsonObj in webassembly -let ptr = jsonpath.allocJson(jsonObj); - -// `0` is invalid pointer -if(ptr == 0) { - console.error('invalid ptr'); -} - -let path = '$..friends[0]'; -let template = jsonpath.compile(path); -let selector = jsonpath.selector(jsonObj); -// create selector as pointer -let ptrSelector = jsonpath.selector(ptr); - -let ret1 = selector(path) -let ret2 = ptrSelector(path) -let ret3 = template(jsonObj); -// select as pointer -let ret4 = template(ptr); -let ret5 = jsonpath.select(jsonObj, path); -// select as pointer -let ret6 = jsonpath.select(ptr, path); - -console.log( - JSON.stringify(ret1) == JSON.stringify(ret2), - JSON.stringify(ret1) == JSON.stringify(ret3), - JSON.stringify(ret1) == JSON.stringify(ret4), - JSON.stringify(ret1) == JSON.stringify(ret5), - JSON.stringify(ret1) == JSON.stringify(ret6)); - -// => true true true true true - -jsonpath.deallocJson(ptr); -``` +``` \ No newline at end of file diff --git a/benches/bench.rs b/benches/bench.rs index 55fcb58..de51826 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -160,4 +160,14 @@ fn refval_copy(b: &mut Bencher) { } } }); +} + +#[bench] +fn value_clone(b: &mut Bencher) { + let json = get_json(); + b.iter(move || { + for _ in 1..100 { + let _ = json.clone(); + } + }); } \ No newline at end of file diff --git a/benches/bench_example.rs b/benches/bench_example.rs index d2e8322..1acf867 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -12,6 +12,7 @@ use std::io::Read; use serde_json::Value; use self::test::Bencher; +use jsonpath::ref_value::model::RefValueWrapper; fn read_json(path: &str) -> String { let mut f = std::fs::File::open(path).unwrap(); @@ -50,32 +51,70 @@ fn get_path(i: usize) -> &'static str { paths[i] } -macro_rules! example { +fn _as_value(b: &mut Bencher, index: usize) { + let json = get_json(); + b.iter(move || { + for _ in 1..100 { + let _ = jsonpath::select(&json, get_path(index)); + } + }); +} + +fn _as_ref_value(b: &mut Bencher, index: usize) { + let ref json = get_json(); + let rv: RefValueWrapper = json.into(); + b.iter(move || { + for _ in 1..100 { + let mut selector = jsonpath::Selector::new(); + let _ = selector.path(get_path(index)); + let _ = selector.value_from_ref_value(rv.clone()); + let _ = selector.select_as_value(); + } + }); +} + +macro_rules! example_val { ($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)); - } - }); - } + fn $name(b: &mut Bencher) { _as_value(b, $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); +macro_rules! example_val_ref { + ($name:ident, $i:expr) => { + #[bench] + fn $name(b: &mut Bencher) { _as_ref_value(b, $i); } + }; +} + +example_val!(example_val_0, 0); +example_val!(example_val_1, 1); +example_val!(example_val_2, 2); +example_val!(example_val_3, 3); +example_val!(example_val_4, 4); +example_val!(example_val_5, 5); +example_val!(example_val_6, 6); +example_val!(example_val_7, 7); +example_val!(example_val_8, 8); +example_val!(example_val_9, 9); +example_val!(example_val_10, 10); +example_val!(example_val_11, 11); +example_val!(example_val_12, 12); +example_val!(example_val_13, 13); +example_val!(example_val_14, 14); + +example_val_ref!(example_val_ref_0, 0); +example_val_ref!(example_val_ref_1, 1); +example_val_ref!(example_val_ref_2, 2); +example_val_ref!(example_val_ref_3, 3); +example_val_ref!(example_val_ref_4, 4); +example_val_ref!(example_val_ref_5, 5); +example_val_ref!(example_val_ref_6, 6); +example_val_ref!(example_val_ref_7, 7); +example_val_ref!(example_val_ref_8, 8); +example_val_ref!(example_val_ref_9, 9); +example_val_ref!(example_val_ref_10, 10); +example_val_ref!(example_val_ref_11, 11); +example_val_ref!(example_val_ref_12, 12); +example_val_ref!(example_val_ref_13, 13); +example_val_ref!(example_val_ref_14, 14); \ No newline at end of file diff --git a/benches/javascript/bench.js b/benches/javascript/bench.js index a4c7a0b..6537aca 100644 --- a/benches/javascript/bench.js +++ b/benches/javascript/bench.js @@ -92,45 +92,12 @@ function wasmCompile() { } } -function wasmCompileAlloc() { - let ptr = jpw.allocJson(getJson()); - if (ptr == 0) { - console.error('Invalid pointer'); - return; - } - - try { - let template = jpw.compile(path); - for (var i = 0; i < iter; i++) { - let _ = template(ptr); - } - } finally { - jpw.deallocJson(ptr); - } -} - function wasmSelect() { for (var i = 0; i < iter; i++) { let _ = jpw.select(getJson(), path); } } -function wasmSelectAlloc() { - let ptr = jpw.allocJson(getJson()); - if (ptr == 0) { - console.error('Invalid pointer'); - return; - } - - try { - for (var i = 0; i < iter; i++) { - let _ = jpw.select(ptr, path); - } - } finally { - jpw.deallocJson(ptr); - } -} - function wasmSelectorClass() { let selector = new jpw.Selector(); for (var i = 0; i < iter; i++) { diff --git a/src/filter/term.rs b/src/filter/term.rs index a5b8d03..476e29f 100644 --- a/src/filter/term.rs +++ b/src/filter/term.rs @@ -1,9 +1,6 @@ use super::cmp::*; use super::value_filter::ValueFilterKey; use super::value_manager::*; -use std::cell::RefCell; -use select::path_map::PathMap; -use std::sync::Arc; #[derive(Debug)] pub enum TermContext { @@ -55,7 +52,7 @@ impl TermContext { } } - fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType, path_map: Arc>) -> TermContext { + fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext { match self { TermContext::Constants(et) => { match other { @@ -70,7 +67,7 @@ impl TermContext { } } TermContext::Json(_, v) => { - TermContext::Json(None, ValueManager::new(v.get_val().clone(), false, path_map)) + TermContext::Json(None, ValueManager::new(v.get_val().clone(), false)) } } } @@ -83,7 +80,7 @@ impl TermContext { } } _ => { - TermContext::Json(None, ValueManager::new(v.get_val().clone(), false, path_map)) + TermContext::Json(None, ValueManager::new(v.get_val().clone(), false)) } } } @@ -120,12 +117,12 @@ impl TermContext { self.cmp(other, CmpLe, false) } - pub fn and(&mut self, other: &mut TermContext, path_map: Arc>) -> TermContext { - self.cmp_cond(other, CmpCondType::And, path_map) + pub fn and(&mut self, other: &mut TermContext) -> TermContext { + self.cmp_cond(other, CmpCondType::And) } - pub fn or(&mut self, other: &mut TermContext, path_map: Arc>) -> TermContext { - self.cmp_cond(other, CmpCondType::Or, path_map) + pub fn or(&mut self, other: &mut TermContext) -> TermContext { + self.cmp_cond(other, CmpCondType::Or) } } diff --git a/src/filter/value_filter.rs b/src/filter/value_filter.rs index 839f4b8..33564f0 100644 --- a/src/filter/value_filter.rs +++ b/src/filter/value_filter.rs @@ -1,6 +1,4 @@ -use std::cell::RefCell; use std::ops::Deref; -use std::sync::Arc; use serde_json::Value; @@ -8,7 +6,6 @@ use filter::term::*; use filter::value_manager::*; use parser::parser::{FilterToken, NodeVisitor, ParseToken}; use ref_value::model::*; -use select::path_map::PathMap; #[derive(Debug, Clone)] pub enum ValueFilterKey { @@ -52,16 +49,14 @@ pub struct ValueFilter { value_mgr: ValueManager, last_key: Option, is_relative: bool, - path_map: Arc>, } impl ValueFilter { - pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool, path_map: Arc>) -> Self { + pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool) -> Self { ValueFilter { - value_mgr: ValueManager::new(v, is_leaves, path_map.clone()), + value_mgr: ValueManager::new(v, is_leaves), last_key: None, is_relative, - path_map, } } @@ -69,7 +64,7 @@ impl ValueFilter { let mut buf = Vec::new(); collect_all(key, &self.value_mgr.get_val(), &mut buf); trace!("step_leaves - {:?}", buf); - self.value_mgr = ValueManager::new(RefValue::Array(buf).into(), true, self.path_map.clone()); + self.value_mgr = ValueManager::new(RefValue::Array(buf).into(), true); } pub fn step_leaves_all(&mut self) -> &ValueManager { @@ -136,17 +131,15 @@ impl ValueFilter { pub struct JsonValueFilter { json: RefValueWrapper, - path_map: Arc>, filter_stack: Vec, token_stack: Vec, term_stack: Vec, } impl JsonValueFilter { - pub fn new(json: RefValueWrapper, path_map: Arc>) -> Self { + pub fn new(json: RefValueWrapper) -> Self { JsonValueFilter { json, - path_map, filter_stack: Vec::new(), token_stack: Vec::new(), term_stack: Vec::new(), @@ -164,7 +157,6 @@ impl JsonValueFilter { ValueFilter::new(vf.value_mgr.get_val().clone(), vf.value_mgr.is_leaves(), is_relative, - self.path_map.clone(), ) }) .and_then(|vf| { @@ -175,7 +167,6 @@ impl JsonValueFilter { self.json.clone(), false, is_relative, - self.path_map.clone(), ); self.filter_stack.push(vf); } @@ -187,7 +178,6 @@ impl JsonValueFilter { v, is_leaves, false, - self.path_map.clone(), )); return; } @@ -348,8 +338,8 @@ impl JsonValueFilter { 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()), + FilterToken::And => left.and(&mut right), + FilterToken::Or => left.or(&mut right), }; self.term_stack.push(tc); } diff --git a/src/filter/value_manager.rs b/src/filter/value_manager.rs index e0a7690..661a0dc 100644 --- a/src/filter/value_manager.rs +++ b/src/filter/value_manager.rs @@ -1,12 +1,9 @@ -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::*; @@ -176,13 +173,12 @@ pub type ValueWrapper = ValueManager; #[derive(Debug)] pub struct ValueManager { val: RefValueWrapper, - path_map: Arc>, is_leaves: bool, } impl ValueManager { - pub fn new(val: RefValueWrapper, is_leaves: bool, path_map: Arc>) -> Self { - ValueManager { val, is_leaves, path_map } + pub fn new(val: RefValueWrapper, is_leaves: bool) -> Self { + ValueManager { val, is_leaves } } pub fn is_leaves(&self) -> bool { @@ -226,16 +222,13 @@ impl ValueManager { } let ret = set.into_iter().collect(); - Self::new( - RefValue::Array(ret).into(), - false, - self.path_map.clone()) + Self::new(RefValue::Array(ret).into(), false) } _ => { if cmp_with_term(&self.val, et, &cmp, false, reverse) { - Self::new(self.val.clone(), false, self.path_map.clone()) + Self::new(self.val.clone(), false) } else { - Self::new(RefValue::Null.into(), false, self.path_map.clone()) + Self::new(RefValue::Null.into(), false) } } } @@ -427,7 +420,7 @@ impl ValueManager { } let vec = ret.into_iter().map(|v| v.clone()).collect(); - ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone()) + ValueManager::new(RefValue::Array(vec).into(), false) } pub fn intersect(&self, other: &Self) -> Self { @@ -450,7 +443,7 @@ impl ValueManager { } let vec = ret.into_iter().map(|v| v.clone()).collect(); - ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone()) + ValueManager::new(RefValue::Array(vec).into(), false) } pub fn union(&self, other: &Self) -> Self { @@ -478,7 +471,7 @@ impl ValueManager { } let vec = ret.into_iter().map(|v| v.clone()).collect(); - ValueManager::new(RefValue::Array(vec).into(), false, self.path_map.clone()) + ValueManager::new(RefValue::Array(vec).into(), false) } pub fn into_term(&self, key: &Option) -> TermContext { @@ -489,7 +482,7 @@ impl ValueManager { _ => TermContext::Json(match key { Some(vk) => Some(vk.clone()), _ => None - }, ValueManager::new(self.val.clone(), false, self.path_map.clone())) + }, ValueManager::new(self.val.clone(), false)) } } @@ -519,6 +512,6 @@ impl ValueManager { _ => self.val.clone() }; - ValueManager::new(v, false, self.path_map.clone()) + ValueManager::new(v, false) } } diff --git a/src/select/mod.rs b/src/select/mod.rs index 45c77d9..ac0856c 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,3 +1,2 @@ pub mod selector; -pub mod modifiable; -pub mod path_map; \ No newline at end of file +pub mod modifiable; \ No newline at end of file diff --git a/src/select/path_map.rs b/src/select/path_map.rs deleted file mode 100644 index 82154a0..0000000 --- a/src/select/path_map.rs +++ /dev/null @@ -1,53 +0,0 @@ -//use std::collections::HashMap; -use std::ops::Deref; - -use ref_value::model::{RefValue, RefValueWrapper}; -use indexmap::IndexMap; - -#[derive(Debug)] -pub struct PathMap { - map: IndexMap -} - -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); - } - } -} \ No newline at end of file diff --git a/src/select/selector.rs b/src/select/selector.rs index 2447ee3..fe759ab 100644 --- a/src/select/selector.rs +++ b/src/select/selector.rs @@ -7,9 +7,6 @@ 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. /// @@ -110,12 +107,11 @@ use std::cell::RefCell; pub struct Selector { pub(crate) node: Option, pub(crate) value: Option, - path_builder: Arc>, } impl Selector { pub fn new() -> Self { - Selector { node: None, value: None, path_builder: Arc::new(RefCell::new(PathMap::new())) } + Selector { node: None, value: None } } fn set_value(&mut self, value: RefValueWrapper) { @@ -157,8 +153,7 @@ impl Selector { fn jf(&self) -> result::Result { match &self.value { - Some(v) => Ok(JsonValueFilter::new(v.clone(), - self.path_builder.clone())), + Some(v) => Ok(JsonValueFilter::new(v.clone())), _ => return Err(SelectorErrorMessage::EmptyValue.to_string()) } } @@ -194,10 +189,6 @@ impl Selector { 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 { Ok((&self.select()?).into()) } @@ -212,7 +203,7 @@ impl Selector { match func((&self.select()?).into()).map(|ref v| v.into()) { Some(value) => { self.set_value(value) - }, + } _ => {} } Ok(self) diff --git a/tests/filter.rs b/tests/filter.rs index b9f22a3..99cee5e 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -8,19 +8,18 @@ use std::io::Read; use serde_json::Value; -use jsonpath::filter::value_filter::{JsonValueFilter, ValueFilter}; -use jsonpath::parser::parser::Parser; use jsonpath::Selector; +use jsonpath::filter::value_filter::ValueFilter; 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 selector(path: &str, file: &str) -> Selector { let string = read_json(file); @@ -37,53 +36,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() { diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index fbf78ad..db0d4c2 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,18 +1,14 @@ extern crate cfg_if; extern crate js_sys; extern crate jsonpath_lib as jsonpath; -#[macro_use] -extern crate lazy_static; extern crate serde; extern crate serde_json; extern crate wasm_bindgen; extern crate web_sys; -use std::collections::HashMap; use std::ops::Deref; use std::result; use std::result::Result; -use std::sync::{Mutex, Arc}; use cfg_if::cfg_if; use jsonpath::filter::value_filter::JsonValueFilter; @@ -23,8 +19,6 @@ 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")] { @@ -45,14 +39,13 @@ cfg_if! { } fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue { -// 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("") + let mut jf = JsonValueFilter::new(json); + 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)) + } } fn into_serde_json(js_value: &JsValue) -> Result @@ -80,51 +73,7 @@ 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) -// } - JsValue::from_str("") -} - -//lazy_static! { -// static ref CACHE_JSON: Mutex> = Mutex::new(HashMap::new()); -// static ref CACHE_JSON_IDX: Mutex = Mutex::new(0); -//} - -#[wasm_bindgen(js_name = allocJson)] -pub extern fn alloc_json(js_value: JsValue) -> usize { -// let result: result::Result = 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() - false + into_ref_value(&js_value, node) } #[wasm_bindgen] @@ -145,35 +94,22 @@ 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::(&js_value) { -// Ok(json) => json.into(), -// Err(e) => return JsValue::from_str(e.as_str()) -// } -// } + let json: RefValueWrapper = match into_serde_json::(&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 JsValue>); -// 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 JsValue>); -// -// let ret = cb.as_ref().clone(); -// cb.forget(); -// ret - - JsValue::from_str("") + let ret = cb.as_ref().clone(); + cb.forget(); + ret } #[wasm_bindgen] @@ -279,14 +215,4 @@ impl Selector { let v = self.selector.get().map_err(|e| JsValue::from_str(&e.to_string()))?; JsValue::from_serde(&v).map_err(|e| JsValue::from_str(&e.to_string())) } -} - -#[wasm_bindgen(catch)] -pub fn testa(js_value: JsValue, path: &str, iter: usize) -> result::Result<(), JsValue> { - for _ in 0..iter { - let mut parser = Parser::new(path); - let node = parser.compile().unwrap(); - into_ref_value(&js_value, node); - } - Ok(()) } \ No newline at end of file diff --git a/wasm/tests/web.rs b/wasm/tests/web.rs index 0dac354..a8ee5df 100644 --- a/wasm/tests/web.rs +++ b/wasm/tests/web.rs @@ -95,20 +95,6 @@ fn selector() { assert_eq!(json, target_json()); } -#[wasm_bindgen_test] -fn alloc_dealloc_json() { - let ptr = jsonpath::alloc_json(JsValue::from_str(json_str())); - assert_eq!(ptr > 0, true); - - let json: Value = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").into_serde().unwrap(); - assert_eq!(json, target_json()); - - assert_eq!(jsonpath::dealloc_json(ptr), true); - - let err = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").as_string().unwrap(); - assert_eq!(err, "Invalid pointer".to_string()); -} - #[wasm_bindgen_test] fn selector_struct() { let mut selector = jsonpath::Selector::new(); diff --git a/wasm/www_bench/index.js b/wasm/www_bench/index.js index 89810ed..535151a 100644 --- a/wasm/www_bench/index.js +++ b/wasm/www_bench/index.js @@ -61,9 +61,6 @@ let path = '$..book[?(@.price<30 && @.category=="fiction")]'; let template = jpw.compile(path); let selector = jpw.selector(json); -let ptr = jpw.allocJson(json); -if(ptr == 0) console.error('invalid ptr'); - let iterCount = 2000; run('jsonpath', iterCount, function() { jp.query(json, path) }) @@ -73,15 +70,9 @@ run('jsonpath', iterCount, function() { jp.query(json, path) }) .then(function() { return run('jsonpath-wasm- compile', iterCount, function() { template(json) }); }) - .then(function() { - return run('jsonpath-wasm- compile-alloc', iterCount, function() { template(ptr) }); - }) .then(function() { return run('jsonpath-wasm- select', iterCount, function() { jpw.select(json, path) }); }) - .then(function() { - return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) }); - }) .finally(function() { if(!jpw.deallocJson(ptr)) { console.error('fail to dealloc'); From 893af2afc04b496e2c0d43592546644b7ca30897 Mon Sep 17 00:00:00 2001 From: freestrings Date: Sun, 2 Jun 2019 22:03:35 +0900 Subject: [PATCH 03/15] 0.2.0 initail commit --- Cargo.toml | 5 +- benches/bench.rs | 70 +-- benches/bench_example.rs | 81 +-- src/filter/cmp.rs | 191 ------ src/filter/mod.rs | 6 - src/filter/term.rs | 154 ----- src/filter/value_filter.rs | 442 -------------- src/filter/value_manager.rs | 517 ---------------- src/lib.rs | 456 +++++++------- src/parser/mod.rs | 526 +++++++++++++++- src/parser/parser.rs | 115 ++-- src/ref_value/de.rs | 1058 --------------------------------- src/ref_value/mod.rs | 4 - src/ref_value/model.rs | 290 --------- src/ref_value/ser.rs | 624 ------------------- src/ref_value/serde_error.rs | 38 -- src/select/mod.rs | 1004 ++++++++++++++++++++++++++++++- src/select/modifiable.rs | 60 -- src/select/selector.rs | 257 -------- tests/common.rs | 44 ++ tests/filter.rs | 577 +++++++----------- tests/lib.rs | 47 +- tests/modifiable.rs | 31 - tests/parser.rs | 312 ---------- tests/readme.rs | 199 +++++-- tests/selector.rs | 209 ------- tests/serde.rs | 39 -- tests/tokenizer.rs | 194 ------ wasm/Cargo.toml | 2 +- wasm/src/lib.rs | 184 +++--- wasm/tests/test/index.spec.js | 58 +- wasm/www_bench/index.js | 6 +- 32 files changed, 2350 insertions(+), 5450 deletions(-) delete mode 100644 src/filter/cmp.rs delete mode 100644 src/filter/mod.rs delete mode 100644 src/filter/term.rs delete mode 100644 src/filter/value_filter.rs delete mode 100644 src/filter/value_manager.rs delete mode 100644 src/ref_value/de.rs delete mode 100644 src/ref_value/mod.rs delete mode 100644 src/ref_value/model.rs delete mode 100644 src/ref_value/ser.rs delete mode 100644 src/ref_value/serde_error.rs delete mode 100644 src/select/modifiable.rs delete mode 100644 src/select/selector.rs create mode 100644 tests/common.rs delete mode 100644 tests/modifiable.rs delete mode 100644 tests/parser.rs delete mode 100644 tests/selector.rs delete mode 100644 tests/serde.rs delete mode 100644 tests/tokenizer.rs diff --git a/Cargo.toml b/Cargo.toml index 80354a4..3daccb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonpath_lib" -version = "0.1.13" +version = "0.2.0" authors = ["Changseok Han "] description = "It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript also. - Webassembly Demo: https://freestrings.github.io/jsonpath" @@ -23,6 +23,7 @@ env_logger = "0.6.0" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } indexmap = "1.0.2" +array_tool = "~1.0.3" [dev-dependencies] bencher = "0.1.5" @@ -32,5 +33,5 @@ name = "jsonpath_lib" path = "src/lib.rs" [profile.release] -debug = true +#debug = true #lto = false diff --git a/benches/bench.rs b/benches/bench.rs index de51826..9a7f78c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,6 +1,5 @@ #![feature(test)] extern crate bencher; -extern crate indexmap; extern crate jsonpath_lib as jsonpath; extern crate serde; extern crate serde_json; @@ -8,13 +7,10 @@ extern crate test; use std::io::Read; -use serde::Serialize; use serde::Deserialize; use serde_json::Value; use self::test::Bencher; -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(); @@ -103,71 +99,7 @@ fn bench_select_as(b: &mut Bencher) { b.iter(move || { for _ in 1..100 { - let _: Book = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap(); - } - }); -} - -#[bench] -fn refval_de(b: &mut Bencher) { - let json = get_json(); - b.iter(move || { - for _ in 1..100 { - let _ = RefValue::deserialize(&json).unwrap(); - } - }); -} - -#[bench] -fn refval_se(b: &mut Bencher) { - let json = get_json(); - b.iter(move || { - for _ in 1..100 { - let _ = &json.serialize(RefValueSerializer).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 = 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 = vec.iter().map(|v| v.clone()).collect(); - } - } - }); -} - -#[bench] -fn value_clone(b: &mut Bencher) { - let json = get_json(); - b.iter(move || { - for _ in 1..100 { - let _ = json.clone(); + let _: Vec = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap(); } }); } \ No newline at end of file diff --git a/benches/bench_example.rs b/benches/bench_example.rs index 1acf867..ad2ba62 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -1,7 +1,6 @@ #![feature(test)] extern crate bencher; -extern crate indexmap; extern crate jsonpath_lib as jsonpath; extern crate serde; extern crate serde_json; @@ -12,7 +11,6 @@ use std::io::Read; use serde_json::Value; use self::test::Bencher; -use jsonpath::ref_value::model::RefValueWrapper; fn read_json(path: &str) -> String { let mut f = std::fs::File::open(path).unwrap(); @@ -44,77 +42,46 @@ fn get_path(i: usize) -> &'static str { "$..book[-2:]", //9 "$..book[2:]", //10 "$..book[?(@.isbn)]", //11 - "$.store.book[?(@.price < 10)]", //12 + "$.store.book[?(@.price == 10)]", //12 "$..*", //13 - "$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]" //14 + "$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]", //14 + "$.store.book[?( (@.price < 10 || @.price > 10) && @.price > 10 )]" ]; paths[i] } -fn _as_value(b: &mut Bencher, index: usize) { +fn _selector(b: &mut Bencher, index: usize) { let json = get_json(); - b.iter(move || { - for _ in 1..100 { - let _ = jsonpath::select(&json, get_path(index)); - } - }); -} - -fn _as_ref_value(b: &mut Bencher, index: usize) { - let ref json = get_json(); - let rv: RefValueWrapper = json.into(); b.iter(move || { for _ in 1..100 { let mut selector = jsonpath::Selector::new(); let _ = selector.path(get_path(index)); - let _ = selector.value_from_ref_value(rv.clone()); - let _ = selector.select_as_value(); + selector.value(&json); + let _ = selector.select(); } }); } -macro_rules! example_val { +macro_rules! selector { ($name:ident, $i:expr) => { #[bench] - fn $name(b: &mut Bencher) { _as_value(b, $i); } + fn $name(b: &mut Bencher) { _selector(b, $i); } }; } -macro_rules! example_val_ref { - ($name:ident, $i:expr) => { - #[bench] - fn $name(b: &mut Bencher) { _as_ref_value(b, $i); } - }; -} - -example_val!(example_val_0, 0); -example_val!(example_val_1, 1); -example_val!(example_val_2, 2); -example_val!(example_val_3, 3); -example_val!(example_val_4, 4); -example_val!(example_val_5, 5); -example_val!(example_val_6, 6); -example_val!(example_val_7, 7); -example_val!(example_val_8, 8); -example_val!(example_val_9, 9); -example_val!(example_val_10, 10); -example_val!(example_val_11, 11); -example_val!(example_val_12, 12); -example_val!(example_val_13, 13); -example_val!(example_val_14, 14); - -example_val_ref!(example_val_ref_0, 0); -example_val_ref!(example_val_ref_1, 1); -example_val_ref!(example_val_ref_2, 2); -example_val_ref!(example_val_ref_3, 3); -example_val_ref!(example_val_ref_4, 4); -example_val_ref!(example_val_ref_5, 5); -example_val_ref!(example_val_ref_6, 6); -example_val_ref!(example_val_ref_7, 7); -example_val_ref!(example_val_ref_8, 8); -example_val_ref!(example_val_ref_9, 9); -example_val_ref!(example_val_ref_10, 10); -example_val_ref!(example_val_ref_11, 11); -example_val_ref!(example_val_ref_12, 12); -example_val_ref!(example_val_ref_13, 13); -example_val_ref!(example_val_ref_14, 14); \ No newline at end of file +selector!(example0_1, 0); +selector!(example1_1, 1); +selector!(example2_1, 2); +selector!(example3_1, 3); +selector!(example4_1, 4); +selector!(example5_1, 5); +selector!(example6_1, 6); +selector!(example7_1, 7); +selector!(example8_1, 8); +selector!(example9_1, 9); +selector!(example_10_1, 10); +selector!(example_11_1, 11); +selector!(example_12_1, 12); +selector!(example_13_1, 13); +selector!(example_14_1, 14); +selector!(example_15_1, 15); \ No newline at end of file diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs deleted file mode 100644 index a83ee16..0000000 --- a/src/filter/cmp.rs +++ /dev/null @@ -1,191 +0,0 @@ -#[derive(Debug)] -pub enum CmpType { - Eq, - Ne, - Gt, - Ge, - Lt, - Le, -} - -#[derive(Debug)] -pub enum CmpCondType { - And, - Or, -} - -pub trait PrivCmp { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool; - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool; - - fn cmp_string(&self, v1: &String, v2: &String) -> bool; -} - -pub trait IntoType { - fn into_type(&self) -> CmpType; -} - -pub struct CmpEq; - -impl PrivCmp for CmpEq { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 == v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 == v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 == v2 - } -} - -impl IntoType for CmpEq { - fn into_type(&self) -> CmpType { - CmpType::Eq - } -} - -pub struct CmpNe; - -impl PrivCmp for CmpNe { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 != v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 != v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 != v2 - } -} - -impl IntoType for CmpNe { - fn into_type(&self) -> CmpType { - CmpType::Ne - } -} - -pub struct CmpGt; - -impl PrivCmp for CmpGt { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 > v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 > v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 > v2 - } -} - -impl IntoType for CmpGt { - fn into_type(&self) -> CmpType { - CmpType::Gt - } -} - -pub struct CmpGe; - -impl PrivCmp for CmpGe { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 >= v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 >= v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 >= v2 - } -} - -impl IntoType for CmpGe { - fn into_type(&self) -> CmpType { - CmpType::Ge - } -} - -pub struct CmpLt; - -impl PrivCmp for CmpLt { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 < v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 < v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 < v2 - } -} - -impl IntoType for CmpLt { - fn into_type(&self) -> CmpType { - CmpType::Lt - } -} - -pub struct CmpLe; - -impl PrivCmp for CmpLe { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - v1 <= v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 <= v2 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - v1 <= v2 - } -} - -impl IntoType for CmpLe { - fn into_type(&self) -> CmpType { - CmpType::Le - } -} - -pub struct CmpAnd; - -impl PrivCmp for CmpAnd { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - *v1 && *v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 > &0_f64 && v2 > &0_f64 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - !v1.is_empty() && !v2.is_empty() - } -} - -pub struct CmpOr; - -impl PrivCmp for CmpOr { - fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { - *v1 || *v2 - } - - fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { - v1 > &0_f64 || v2 > &0_f64 - } - - fn cmp_string(&self, v1: &String, v2: &String) -> bool { - !v1.is_empty() || !v2.is_empty() - } -} \ No newline at end of file diff --git a/src/filter/mod.rs b/src/filter/mod.rs deleted file mode 100644 index 472c2b9..0000000 --- a/src/filter/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod cmp; -mod term; -pub mod value_filter; -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; \ No newline at end of file diff --git a/src/filter/term.rs b/src/filter/term.rs deleted file mode 100644 index 476e29f..0000000 --- a/src/filter/term.rs +++ /dev/null @@ -1,154 +0,0 @@ -use super::cmp::*; -use super::value_filter::ValueFilterKey; -use super::value_manager::*; - -#[derive(Debug)] -pub enum TermContext { - Constants(ExprTerm), - Json(Option, ValueManager), -} - -impl TermContext { - fn cmp(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext { - match self { - TermContext::Constants(et) => { - match other { - TermContext::Constants(oet) => { - trace!("const-const"); - TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default))) - } - TermContext::Json(ref mut key, ref mut v) => { - trace!("const-json"); - TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, true)) - } - } - } - TermContext::Json(key, v) => { - match other { - TermContext::Json(key_other, ov) => { - trace!("json-json"); - - fn is_json(t: &TermContext) -> bool { - match t { - TermContext::Json(_, _) => true, - _ => false - } - } - - 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(&mut oc, cmp_fn, default) - } - } - TermContext::Constants(et) => { - trace!("json-const"); - TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, false)) - } - } - } - } - } - - fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext { - match self { - TermContext::Constants(et) => { - match other { - TermContext::Constants(oet) => { - match cmp_cond_type { - CmpCondType::Or => { - TermContext::Constants(ExprTerm::Bool(et.cmp(oet, CmpOr, false))) - } - CmpCondType::And => { - TermContext::Constants(ExprTerm::Bool(et.cmp(oet, CmpAnd, false))) - } - } - } - TermContext::Json(_, v) => { - TermContext::Json(None, ValueManager::new(v.get_val().clone(), false)) - } - } - } - TermContext::Json(_, v) => { - match other { - TermContext::Json(_, ov) => { - match cmp_cond_type { - CmpCondType::Or => TermContext::Json(None, v.union(ov)), - CmpCondType::And => TermContext::Json(None, v.intersect(ov)), - } - } - _ => { - TermContext::Json(None, ValueManager::new(v.get_val().clone(), false)) - } - } - } - } - } - - pub fn eq(&mut self, other: &mut TermContext) -> TermContext { - trace!("eq"); - self.cmp(other, CmpEq, false) - } - - pub fn ne(&mut self, other: &mut TermContext) -> TermContext { - trace!("ne"); - self.cmp(other, CmpNe, true) - } - - pub fn gt(&mut self, other: &mut TermContext) -> TermContext { - trace!("gt"); - self.cmp(other, CmpGt, false) - } - - pub fn ge(&mut self, other: &mut TermContext) -> TermContext { - trace!("ge"); - self.cmp(other, CmpGe, false) - } - - pub fn lt(&mut self, other: &mut TermContext) -> TermContext { - trace!("lt"); - self.cmp(other, CmpLt, false) - } - - pub fn le(&mut self, other: &mut TermContext) -> TermContext { - trace!("le"); - self.cmp(other, CmpLe, false) - } - - pub fn and(&mut self, other: &mut TermContext) -> TermContext { - self.cmp_cond(other, CmpCondType::And) - } - - pub fn or(&mut self, other: &mut TermContext) -> TermContext { - self.cmp_cond(other, CmpCondType::Or) - } -} - - -#[derive(Debug)] -pub enum ExprTerm { - String(String), - Number(f64), - Bool(bool), -} - -impl ExprTerm { - fn cmp(&self, other: &ExprTerm, cmp_fn: F, default: bool) -> bool { - match self { - ExprTerm::Bool(v1) => match other { - ExprTerm::Bool(v2) => cmp_fn.cmp_bool(v1, v2), - _ => default - } - ExprTerm::Number(v1) => match other { - ExprTerm::Number(v2) => cmp_fn.cmp_f64(v1, v2), - _ => default - } - ExprTerm::String(v1) => match other { - ExprTerm::String(v2) => cmp_fn.cmp_string(v1, v2), - _ => default - } - } - } -} diff --git a/src/filter/value_filter.rs b/src/filter/value_filter.rs deleted file mode 100644 index 33564f0..0000000 --- a/src/filter/value_filter.rs +++ /dev/null @@ -1,442 +0,0 @@ -use std::ops::Deref; - -use serde_json::Value; - -use filter::term::*; -use filter::value_manager::*; -use parser::parser::{FilterToken, NodeVisitor, ParseToken}; -use ref_value::model::*; - -#[derive(Debug, Clone)] -pub enum ValueFilterKey { - Num(usize), - String(String), - All, -} - -fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec) { - match v.deref() { - RefValue::Array(vec) => { - if key.is_none() { - for v in vec.iter() { - buf.push(v.clone()); - } - } - - for v in vec { - collect_all(key, v, buf); - } - } - 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 map { - collect_all(key, v, buf); - } - } - _ => {} - } -} - -#[derive(Debug)] -pub struct ValueFilter { - value_mgr: ValueManager, - last_key: Option, - is_relative: bool, -} - -impl ValueFilter { - pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool) -> Self { - ValueFilter { - value_mgr: ValueManager::new(v, is_leaves), - last_key: None, - is_relative, - } - } - - fn step_leaves(&mut self, key: Option<&String>) { - let mut buf = Vec::new(); - collect_all(key, &self.value_mgr.get_val(), &mut buf); - trace!("step_leaves - {:?}", buf); - self.value_mgr = ValueManager::new(RefValue::Array(buf).into(), true); - } - - pub fn step_leaves_all(&mut self) -> &ValueManager { - debug!("step_leaves_all"); - self.step_leaves(None); - self.last_key = Some(ValueFilterKey::All); - &self.value_mgr - } - - 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) -> &ValueManager { - debug!("step_leaves_string"); - self.step_leaves(Some(key)); - self.last_key = Some(ValueFilterKey::String(key.clone())); - &self.value_mgr - } - - pub fn step_in_all(&mut self) -> &ValueManager { - debug!("step_in_all"); - self.last_key = Some(ValueFilterKey::All); - 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) -> &ValueManager { - debug!("step_in_num"); - trace!("step_in_num - before: leaves {}, filterMode {} - {:?}" - , self.value_mgr.is_leaves() - , self.is_relative - , self.value_mgr.get_val()); - - - 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) -> &ValueManager { - self.step_in_string(&key.to_string()) - } - - pub fn step_in_string(&mut self, key: &String) -> &ValueManager { - debug!("step_in_string"); - trace!("step_in_string - before: {},{},{:?}" - , self.value_mgr.is_leaves() - , self.is_relative - , self.value_mgr.get_val()); - - self.last_key = Some(ValueFilterKey::String(key.clone())); - self.value_mgr.replace(self.value_mgr.get_with_str(key, self.is_relative)); - trace!("step_in_string - after: {},{},{:?}" - , self.value_mgr.is_leaves() - , self.is_relative - , self.value_mgr.get_val()); - &self.value_mgr - } -} - -pub struct JsonValueFilter { - json: RefValueWrapper, - filter_stack: Vec, - token_stack: Vec, - term_stack: Vec, -} - -impl JsonValueFilter { - pub fn new(json: RefValueWrapper) -> Self { - JsonValueFilter { - json, - filter_stack: Vec::new(), - token_stack: Vec::new(), - term_stack: Vec::new(), - } - } - - fn is_peek_token_array(&self) -> bool { - if let Some(ParseToken::Array) = self.token_stack.last() { true } else { false } - } - - fn create_new_filter(&mut self, is_relative: bool) { - if is_relative { - self.filter_stack.last() - .map(|vf| { - ValueFilter::new(vf.value_mgr.get_val().clone(), - vf.value_mgr.is_leaves(), - is_relative, - ) - }) - .and_then(|vf| { - Some(self.filter_stack.push(vf)) - }); - } else { - let vf = ValueFilter::new( - self.json.clone(), - false, - is_relative, - ); - self.filter_stack.push(vf); - } - } - - 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, - )); - 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.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 { - 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(&mut self, indices: Vec) { - self.token_stack.pop(); - - match self.filter_stack.last_mut() { - Some(vf) => { - if let Some(vec) = vf.value_mgr.pick_with_nums(indices) { - vf.value_mgr.replace(vec); - } - } - _ => {} - } - } - - fn token_range(&mut self, from: Option, to: Option) { - self.token_stack.pop(); - - match self.filter_stack.last_mut() { - Some(ref mut vf) => { - if let Some(vec) = vf.value_mgr.range_with(from, to) { - vf.value_mgr.replace(vec); - } - } - _ => {} - } - } - - fn token_key(&mut self, key: String) { - match self.filter_stack.last_mut() { - Some(vf) => { - match self.token_stack.pop() { - Some(ParseToken::In) | Some(ParseToken::Array) => { - vf.step_in_string(&key); - } - Some(ParseToken::Leaves) => { - vf.step_leaves_string(&key); - } - _ => { - self.term_stack.push(TermContext::Constants(ExprTerm::String(key))); - } - } - } - _ => {} - } - } - - fn token_all(&mut self) { - match self.filter_stack.last_mut() { - Some(vf) => { - match self.token_stack.pop() { - Some(ParseToken::In) => { - vf.step_in_all(); - } - Some(ParseToken::Leaves) => { - vf.step_leaves_all(); - } - _ => {} - } - } - _ => {} - } - } - - fn token_end_array(&mut self) { - trace!("array_eof - term_stack: {:?}", self.term_stack); - trace!("array_eof - filter_stack: {:?}", self.filter_stack); - - match self.term_stack.pop() { - Some(TermContext::Constants(ExprTerm::Number(v))) => { - match self.filter_stack.last_mut() { - Some(vf) => { - vf.step_in_num(&v); - } - _ => {} - } - } - Some(TermContext::Constants(ExprTerm::Bool(false))) => { - self.append_to_current_filter(RefValue::Null.into(), false); - } - Some(TermContext::Json(_, vw)) => { - 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) => { - match vf.value_mgr.get_val().deref() { - RefValue::Null | RefValue::Bool(false) => { - self.append_to_current_filter(RefValue::Null.into(), vf.value_mgr.is_leaves()); - } - _ => { - self.append_to_current_filter(vf.value_mgr.get_val().clone(), vf.value_mgr.is_leaves()); - } - } - } - _ => {} - } - } - } - } - - fn token_op(&mut self, ft: &FilterToken) { - let right = self.term_stack.pop(); - let left = self.term_stack.pop(); - - trace!("left {:?}", left); - trace!("right {:?}", right); - - if left.is_some() && right.is_some() { - let mut left = left.unwrap(); - let mut right = right.unwrap(); - - let tc = match ft { - 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), - FilterToken::Or => left.or(&mut right), - }; - self.term_stack.push(tc); - } - - trace!("filter - {:?}", self.term_stack) - } -} - -impl NodeVisitor for JsonValueFilter { - fn visit_token(&mut self, token: ParseToken) { - debug!("visit_token: {:?}", token); - - match token { - ParseToken::Absolute - | ParseToken::Relative => { - if self.is_peek_token_array() { - self.token_stack.pop(); - } - self.create_new_filter(ParseToken::Relative == token); - } - ParseToken::In - | ParseToken::Leaves => { - self.token_stack.push(token); - } - ParseToken::Array => { - if let Some(ParseToken::Leaves) = self.token_stack.last() { - self.token_all(); - } - self.token_stack.push(token); - } - ParseToken::ArrayEof => { - self.token_end_array(); - } - ParseToken::All => { - self.token_all(); - } - ParseToken::Key(key) => { - self.token_key(key); - } - ParseToken::Filter(ref ft) => { - self.token_op(ft); - } - ParseToken::Number(v) => { - self.term_stack.push(TermContext::Constants(ExprTerm::Number(v))) - } - ParseToken::Range(from, to) => { - self.token_range(from, to); - } - ParseToken::Union(v) => { - self.token_union(v); - } - ParseToken::Eof => { - debug!("visit_token eof"); - } - } - } - - fn end_term(&mut self) { - debug!("end_term"); - - if let Some(ParseToken::Array) = self.token_stack.last() { - self.token_stack.pop(); - } - - trace!("end_term - term_stack {:?}", self.term_stack); - trace!("end_term - token_stack {:?}", self.token_stack); - trace!("end_term - filter_stack {:?}", self.filter_stack); - - 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.value_mgr)); - } - _ => {} - } - } - - if match self.token_stack.last() { - Some(ParseToken::Key(_)) - | Some(ParseToken::Number(_)) => true, - _ => false - } { - match self.token_stack.pop() { - Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("true") => { - self.term_stack.push(TermContext::Constants(ExprTerm::Bool(true))) - } - Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("false") => { - self.term_stack.push(TermContext::Constants(ExprTerm::Bool(false))) - } - Some(ParseToken::Key(v)) => { - self.term_stack.push(TermContext::Constants(ExprTerm::String(v))) - } - Some(ParseToken::Number(v)) => { - self.term_stack.push(TermContext::Constants(ExprTerm::Number(v))) - } - _ => {} - } - } - } -} diff --git a/src/filter/value_manager.rs b/src/filter/value_manager.rs deleted file mode 100644 index 661a0dc..0000000 --- a/src/filter/value_manager.rs +++ /dev/null @@ -1,517 +0,0 @@ -use std::ops::Deref; - -use indexmap::{IndexMap, IndexSet}; -use serde_json::Value; - -use ref_value::model::*; - -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(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, - F: FnMut(&RefValueWrapper) -> RefValueWrapper>(iter: I, func: F) -> Vec -{ - iter.map(func) - .filter(|v| !v.is_null()) - .collect() -} - -fn collect_some<'a, - I: Iterator, - F: FnMut(&RefValueWrapper) -> Option>(iter: I, func: F) -> Vec -{ - iter.map(func) - .filter(|v| v.is_some()) - .map(|v| v.unwrap()) - .collect() -} - -fn get_in_array(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option { - 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 { - 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(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option { - 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 { - 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 { - 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, - is_leaves: bool, -} - -impl ValueManager { - pub fn new(val: RefValueWrapper, is_leaves: bool) -> Self { - ValueManager { val, is_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: &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(&self, key: &Option, 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) - } - _ => { - if cmp_with_term(&self.val, et, &cmp, false, reverse) { - Self::new(self.val.clone(), false) - } else { - Self::new(RefValue::Null.into(), false) - } - } - } - } - - pub fn get_index(&self, i: I) -> usize { - i.index(&self.val) - } - - pub fn get_with_num(&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, to: Option) -> Option { - fn _from(from: Option, val: &RefValueWrapper) -> usize { - match from { - Some(v) => v.index(val), - _ => 0 - } - } - - fn _to(to: Option, 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 { - 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(&self, indices: Vec) -> Option { - 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 = 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) - } - - pub fn intersect(&self, other: &Self) -> Self { - trace!("intersect"); - let hashset = self.into_hashset(); - let mut ret: IndexSet = 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) - } - - 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) - } - - pub fn into_term(&self, key: &Option) -> 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)) - } - } - - pub fn filter(&self, key: &Option) -> 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) - } -} diff --git a/src/lib.rs b/src/lib.rs index 5121a55..a26e723 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,187 +1,146 @@ -//! JsonPath implementation for Rust +//! JsonPath implementation written in Rust. //! //! # Example //! ``` -//! extern crate jsonpath_lib as jsonpath; -//! #[macro_use] extern crate serde_json; +//! extern crate jsonpath_lib as jsonpath; +//! #[macro_use] extern crate serde_json; +//! let json_obj = json!({ +//! "store": { +//! "book": [ +//! { +//! "category": "reference", +//! "author": "Nigel Rees", +//! "title": "Sayings of the Century", +//! "price": 8.95 +//! }, +//! { +//! "category": "fiction", +//! "author": "Evelyn Waugh", +//! "title": "Sword of Honour", +//! "price": 12.99 +//! }, +//! { +//! "category": "fiction", +//! "author": "Herman Melville", +//! "title": "Moby Dick", +//! "isbn": "0-553-21311-3", +//! "price": 8.99 +//! }, +//! { +//! "category": "fiction", +//! "author": "J. R. R. Tolkien", +//! "title": "The Lord of the Rings", +//! "isbn": "0-395-19395-8", +//! "price": 22.99 +//! } +//! ], +//! "bicycle": { +//! "color": "red", +//! "price": 19.95 +//! } +//! }, +//! "expensive": 10 +//! }); //! -//! let json_obj = json!({ -//! "store": { -//! "book": [ -//! { -//! "category": "reference", -//! "author": "Nigel Rees", -//! "title": "Sayings of the Century", -//! "price": 8.95 -//! }, -//! { -//! "category": "fiction", -//! "author": "Evelyn Waugh", -//! "title": "Sword of Honour", -//! "price": 12.99 -//! }, -//! { -//! "category": "fiction", -//! "author": "Herman Melville", -//! "title": "Moby Dick", -//! "isbn": "0-553-21311-3", -//! "price": 8.99 -//! }, -//! { -//! "category": "fiction", -//! "author": "J. R. R. Tolkien", -//! "title": "The Lord of the Rings", -//! "isbn": "0-395-19395-8", -//! "price": 22.99 -//! } -//! ], -//! "bicycle": { -//! "color": "red", -//! "price": 19.95 -//! } -//! }, -//! "expensive": 10 -//! }); +//! let mut selector = jsonpath::selector(&json_obj); //! -//! let mut selector = jsonpath::selector(&json_obj); +//! assert_eq!(selector("$.store.book[*].author").unwrap(), +//! vec![ +//! "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" +//! ]); //! -//! // -//! // $.store.book[*].author -//! // -//! let json = selector("$.store.book[*].author").unwrap(); -//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]); -//! assert_eq!(json, ret); +//! assert_eq!(selector("$..author").unwrap(), +//! vec![ +//! "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" +//! ]); //! -//! // -//! // $..author -//! // -//! let json = selector("$..author").unwrap(); -//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]); -//! assert_eq!(json, ret); +//! assert_eq!(selector("$.store.*").unwrap(), +//! vec![ +//! &json!([ +//! { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, +//! { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, +//! { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, +//! { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } +//! ]), +//! &json!({ "color": "red", "price": 19.95 }) +//! ]); //! -//! // -//! // $.store.* -//! // -//! let json = selector("$.store.*").unwrap(); -//! let ret = json!([ -//! [ -//! {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95}, -//! {"category" : "fiction", "author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}, -//! {"category" : "fiction", "author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, -//! {"category" : "fiction", "author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} -//! ], -//! {"color" : "red","price" : 19.95}, -//! ]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$.store..price").unwrap(), +//! vec![ +//! 8.95, 12.99, 8.99, 22.99, 19.95 +//! ]); //! -//! // -//! // $.store..price -//! // -//! let json = selector("$.store..price").unwrap(); -//! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[2]").unwrap(), +//! vec![ +//! &json!({ +//! "category" : "fiction", +//! "author" : "Herman Melville", +//! "title" : "Moby Dick", +//! "isbn" : "0-553-21311-3", +//! "price" : 8.99 +//! }) +//! ]); //! -//! // -//! // $..book[2] -//! // -//! let json = selector("$..book[2]").unwrap(); -//! let ret = json!([{ -//! "category" : "fiction", -//! "author" : "Herman Melville", -//! "title" : "Moby Dick", -//! "isbn" : "0-553-21311-3", -//! "price" : 8.99 -//! }]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[-2]").unwrap(), +//! vec![ +//! &json!({ +//! "category" : "fiction", +//! "author" : "Herman Melville", +//! "title" : "Moby Dick", +//! "isbn" : "0-553-21311-3", +//! "price" : 8.99 +//! }) +//! ]); //! -//! // -//! // $..book[-2] -//! // -//! let json = selector("$..book[-2]").unwrap(); -//! let ret = json!([{ -//! "category" : "fiction", -//! "author" : "Herman Melville", -//! "title" : "Moby Dick", -//! "isbn" : "0-553-21311-3", -//! "price" : 8.99 -//! }]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[0,1]").unwrap(), +//! vec![ +//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), +//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) +//! ]); //! -//! // -//! // $..book[0,1] -//! // -//! let json = selector("$..book[0,1]").unwrap(); -//! let ret = json!([ -//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, -//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99} -//! ]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[:2]").unwrap(), +//! vec![ +//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), +//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) +//! ]); //! -//! // -//! // $..book[:2] -//! // -//! let json = selector("$..book[:2]").unwrap(); -//! let ret = json!([ -//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, -//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99} -//! ]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[:2]").unwrap(), +//! vec![ +//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), +//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) +//! ]); //! -//! // -//! // $..book[2:] -//! // -//! let json = selector("$..book[2:]").unwrap(); -//! let ret = json!([ -//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, -//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} -//! ]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$..book[?(@.isbn)]").unwrap(), +//! vec![ +//! &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}), +//! &json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}) +//! ]); //! -//! // -//! // $..book[?(@.isbn)] -//! // -//! let json = selector("$..book[?(@.isbn)]").unwrap(); -//! let ret = json!([ -//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, -//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} -//! ]); -//! assert_eq!(ret, json); -//! -//! // -//! // $.store.book[?(@.price < 10)] -//! // -//! let json = selector("$.store.book[?(@.price < 10)]").unwrap(); -//! let ret = json!([ -//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, -//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99} -//! ]); -//! assert_eq!(ret, json); +//! assert_eq!(selector("$.store.book[?(@.price < 10)]").unwrap(), +//! vec![ +//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), +//! &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}) +//! ]); //! ``` - +extern crate array_tool; extern crate core; extern crate env_logger; extern crate indexmap; #[macro_use] extern crate log; -#[macro_use] extern crate serde; extern crate serde_json; -use core::borrow::BorrowMut; -use std::result; - use serde_json::Value; -pub use select::selector::Selector; +#[doc(hidden)] +mod parser; +#[doc(hidden)] +mod select; -#[doc(hidden)] -pub mod parser; -#[doc(hidden)] -pub mod filter; -#[doc(hidden)] -pub mod ref_value; -#[doc(hidden)] -pub mod select; +pub use select::Selector; +pub use select::JsonPathError; +pub use parser::parser::Parser; /// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects. /// @@ -192,32 +151,34 @@ pub mod select; /// let mut template = jsonpath::compile("$..friends[0]"); /// /// let json_obj = json!({ -/// "school": { -/// "friends": [ -/// {"name": "친구1", "age": 20}, -/// {"name": "친구2", "age": 20} -/// ] -/// }, -/// "friends": [ -/// {"name": "친구3", "age": 30}, -/// {"name": "친구4"} +/// "school": { +/// "friends": [ +/// {"name": "친구1", "age": 20}, +/// {"name": "친구2", "age": 20} +/// ] +/// }, +/// "friends": [ +/// {"name": "친구3", "age": 30}, +/// {"name": "친구4"} /// ]}); /// /// let json = template(&json_obj).unwrap(); -/// let ret = json!([ -/// {"name": "친구3", "age": 30}, -/// {"name": "친구1", "age": 20} +/// +/// assert_eq!(json, vec![ +/// &json!({"name": "친구3", "age": 30}), +/// &json!({"name": "친구1", "age": 20}) /// ]); -/// assert_eq!(json, ret); /// ``` -pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result + 'a { - let mut selector = Selector::new(); - let _ = selector.path(path); - let mut selector = Box::new(selector); +pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPathError> { + let mut parser = Parser::new(path); + let node = parser.compile(); move |json| { - let s: &mut Selector = selector.borrow_mut(); - let _ = s.value(&json); - s.select_as_value() + let mut selector = Selector::new(); + match &node { + Ok(node) => selector.compiled_path(node.clone()), + Err(e) => return Err(JsonPathError::Path(e.clone())) + }; + selector.value(json).select() } } @@ -228,40 +189,38 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result(json: &Value) -> impl FnMut(&'a str) -> result::Result { +pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result, JsonPathError> { let mut selector = Selector::new(); - let _ = selector.value(json.into()); - let mut selector = Box::new(selector); - move |path: &'a str| { - let s: &mut Selector = selector.borrow_mut(); - s.path(path)?.select_as_value() + let _ = selector.value(json); + move |path: &str| { + selector.path(path)?.reset_value().select() } } @@ -275,26 +234,27 @@ pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result, /// } /// -/// let mut selector = jsonpath::selector_as::>(&json_obj); +/// let mut selector = jsonpath::selector_as::(&json_obj); /// /// let json = selector("$..friends[0]").unwrap(); +/// /// let ret = vec!( /// Friend { name: "친구3".to_string(), age: Some(30) }, /// Friend { name: "친구1".to_string(), age: Some(20) } @@ -302,25 +262,22 @@ pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result(json: &Value) -> impl FnMut(&str) -> result::Result { +pub fn selector_as(json: &Value) -> impl FnMut(&str) -> Result, JsonPathError> + '_ { let mut selector = Selector::new(); - let _ = selector.value(json.into()); + let _ = selector.value(json); move |path: &str| { - selector.path(path)?.select_as() + selector.path(path)?.reset_value().select_as() } } -#[deprecated(since = "0.1.4", note = "Please use the selector function instead")] -pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result { - selector(json) -} - /// This function compile a jsonpath everytime and it convert `serde_json's Value` to `jsonpath's RefValue` everytime and then it return a `serde_json::value::Value`. /// /// ```rust @@ -328,38 +285,26 @@ pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result result::Result { - let mut selector = Selector::new(); - selector.path(path)?.value(json)?.select_as_value() -} - -#[deprecated(since = "0.1.4", note = "Please use the select function instead")] -pub fn read(json: &Value, path: &str) -> result::Result { - select(json, path) -} - -#[deprecated(since = "0.1.7", note = "Please use the select_as_str function instead")] -pub fn select_str(json: &str, path: &str) -> result::Result { - select_as_str(json, path) +pub fn select<'a>(json: &'a Value, path: &'a str) -> Result, JsonPathError> { + Selector::new().path(path)?.value(json).select() } /// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string. @@ -385,11 +330,10 @@ pub fn select_str(json: &str, path: &str) -> result::Result { /// /// assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#); /// ``` -pub fn select_as_str(json: &str, path: &str) -> result::Result { - Selector::new() - .path(path)? - .value_from_str(json)? - .select_as_str() +pub fn select_as_str(json_str: &str, path: &str) -> Result { + let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?; + let ret = Selector::new().path(path)?.value(&json).select()?; + serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string())) } /// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a deserialized-instance of type `T`. @@ -408,7 +352,7 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result { /// phones: Vec, /// } /// -/// let ret: Person = jsonpath::select_as(r#" +/// let ret: Vec = jsonpath::select_as(r#" /// { /// "person": /// { @@ -428,11 +372,9 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result { /// phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()], /// }; /// -/// assert_eq!(person, ret); +/// assert_eq!(ret[0], person); /// ``` -pub fn select_as(json: &str, path: &str) -> result::Result { - Selector::new() - .path(path)? - .value_from_str(json)? - .select_as() +pub fn select_as(json_str: &str, path: &str) -> Result, JsonPathError> { + let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?; + Selector::new().path(path)?.value(&json).select_as() } \ No newline at end of file diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 331b73a..bce22d6 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,3 +1,525 @@ mod path_reader; -pub mod tokenizer; -pub mod parser; \ No newline at end of file +pub(crate) mod tokenizer; +pub mod parser; + +#[cfg(test)] +mod parser_tests { + use parser::parser::{ParseToken, Parser, NodeVisitor, FilterToken}; + + struct NodeVisitorTestImpl<'a> { + input: &'a str, + stack: Vec, + } + + impl<'a> NodeVisitorTestImpl<'a> { + fn new(input: &'a str) -> Self { + NodeVisitorTestImpl { input, stack: Vec::new() } + } + + fn start(&mut self) -> Result, String> { + let mut parser = Parser::new(self.input); + let node = parser.compile()?; + self.visit(&node); + Ok(self.stack.split_off(0)) + } + } + + impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> { + fn visit_token(&mut self, token: &ParseToken) { + self.stack.push(token.clone()); + } + } + + fn setup() { + let _ = env_logger::try_init(); + } + + fn run(input: &str) -> Result, String> { + let mut interpreter = NodeVisitorTestImpl::new(input); + interpreter.start() + } + + #[test] + fn parse_path() { + setup(); + + assert_eq!(run("$.aa"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::Key("aa".to_owned()) + ])); + + assert_eq!(run("$.00.a"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::Key("00".to_owned()), + ParseToken::In, + ParseToken::Key("a".to_owned()) + ])); + + assert_eq!(run("$.00.韓창.seok"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::Key("00".to_owned()), + ParseToken::In, + ParseToken::Key("韓창".to_owned()), + ParseToken::In, + ParseToken::Key("seok".to_owned()) + ])); + + assert_eq!(run("$.*"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::All + ])); + + assert_eq!(run("$..*"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Leaves, + ParseToken::All + ])); + + assert_eq!(run("$..[0]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Leaves, + ParseToken::Array, + ParseToken::Number(0.0), + ParseToken::ArrayEof + ])); + + match run("$.") { + Ok(_) => panic!(), + _ => {} + } + + match run("$..") { + Ok(_) => panic!(), + _ => {} + } + + match run("$. a") { + Ok(_) => panic!(), + _ => {} + } + } + + #[test] + fn parse_array_sytax() { + setup(); + + assert_eq!(run("$.book[?(@.isbn)]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::Key("book".to_string()), + ParseToken::Array, + ParseToken::Relative, + ParseToken::In, + ParseToken::Key("isbn".to_string()), + ParseToken::ArrayEof + ])); + + // + // Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만 + // + assert_eq!(run("$.[*]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[*]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[*].가"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof, + ParseToken::In, ParseToken::Key("가".to_owned()) + ])); + + assert_eq!(run("$.a[0][1]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Number(0_f64), + ParseToken::ArrayEof, + ParseToken::Array, + ParseToken::Number(1_f64), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[1,2]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Union(vec![1, 2]), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[10:]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Range(Some(10), None), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[:11]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Range(None, Some(11)), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[-12:13]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Range(Some(-12), Some(13)), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[?(1>2)]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Greater), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[?($.b>3)]"), Ok(vec![ + ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Array, + ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::Greater), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$[?($.c>@.d && 1==2)]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()), + ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()), + ParseToken::Filter(FilterToken::Greater), + ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal), + ParseToken::Filter(FilterToken::And), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$[?($.c>@.d&&(1==2||3>=4))]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()), + ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()), + ParseToken::Filter(FilterToken::Greater), + ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal), + ParseToken::Number(3_f64), ParseToken::Number(4_f64), ParseToken::Filter(FilterToken::GreaterOrEqual), + ParseToken::Filter(FilterToken::Or), + ParseToken::Filter(FilterToken::And), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$[?(@.a<@.b)]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()), + ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned()), + ParseToken::Filter(FilterToken::Little), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$[*][*][*]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof, + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof, + ParseToken::Array, + ParseToken::All, + ParseToken::ArrayEof + ])); + + assert_eq!(run("$['a']['bb']"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::Key("a".to_string()), + ParseToken::ArrayEof, + ParseToken::Array, + ParseToken::Key("bb".to_string()), + ParseToken::ArrayEof + ])); + + assert_eq!(run("$.a[?(@.e==true)]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::In, + ParseToken::Key("a".to_string()), + ParseToken::Array, + ParseToken::Relative, + ParseToken::In, + ParseToken::Key("e".to_string()), + ParseToken::Bool(true), + ParseToken::Filter(FilterToken::Equal), + ParseToken::ArrayEof + ])); + + match run("$[") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[a]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?($.a)]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?(@.a > @.b]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?(@.a < @.b&&(@.c < @.d)]") { + Ok(_) => panic!(), + _ => {} + } + } + + #[test] + fn parse_array_float() { + setup(); + + assert_eq!(run("$[?(1.1<2.1)]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Array, + ParseToken::Number(1.1), ParseToken::Number(2.1), ParseToken::Filter(FilterToken::Little), + ParseToken::ArrayEof + ])); + + match run("$[1.1]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?(1.1<.2)]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?(1.1<2.)]") { + Ok(_) => panic!(), + _ => {} + } + + match run("$[?(1.1<2.a)]") { + Ok(_) => panic!(), + _ => {} + } + } +} + +#[cfg(test)] +mod tokenizer_tests { + use parser::tokenizer::{Token, TokenError, Tokenizer, PreloadedTokenizer}; + + fn collect_token(input: &str) -> (Vec, Option) { + let mut tokenizer = Tokenizer::new(input); + let mut vec = vec![]; + loop { + match tokenizer.next_token() { + Ok(t) => vec.push(t), + Err(e) => return (vec, Some(e)), + } + } + } + + fn run(input: &str, expected: (Vec, Option)) { + let (vec, err) = collect_token(input.clone()); + assert_eq!((vec, err), expected, "\"{}\"", input); + } + + #[test] + fn peek() { + let mut tokenizer = PreloadedTokenizer::new("$.a"); + match tokenizer.next_token() { + Ok(t) => assert_eq!(Token::Absolute(0), t), + _ => panic!() + } + + match tokenizer.peek_token() { + Ok(t) => assert_eq!(&Token::Dot(1), t), + _ => panic!() + } + + match tokenizer.peek_token() { + Ok(t) => assert_eq!(&Token::Dot(1), t), + _ => panic!() + } + + match tokenizer.next_token() { + Ok(t) => assert_eq!(Token::Dot(1), t), + _ => panic!() + } + } + + #[test] + fn token() { + run("$.01.a", + ( + vec![ + Token::Absolute(0), + Token::Dot(1), + Token::Key(2, "01".to_string()), + Token::Dot(4), + Token::Key(5, "a".to_string()) + ] + , Some(TokenError::Eof) + )); + + run("$. []", + ( + vec![ + Token::Absolute(0), + Token::Dot(1), + Token::Whitespace(2, 2), + Token::OpenArray(5), + Token::CloseArray(6) + ] + , Some(TokenError::Eof) + )); + + run("$..", + ( + vec![ + Token::Absolute(0), + Token::Dot(1), + Token::Dot(2), + ] + , Some(TokenError::Eof) + )); + + run("$..ab", + ( + vec![ + Token::Absolute(0), + Token::Dot(1), + Token::Dot(2), + Token::Key(3, "ab".to_string()) + ] + , Some(TokenError::Eof) + )); + + run("$..가 [", + ( + vec![ + Token::Absolute(0), + Token::Dot(1), + Token::Dot(2), + Token::Key(3, "가".to_string()), + Token::Whitespace(6, 0), + Token::OpenArray(7), + ] + , Some(TokenError::Eof) + )); + + run("[-1, 2 ]", + ( + vec![ + Token::OpenArray(0), + Token::Key(1, "-1".to_string()), + Token::Comma(3), + Token::Whitespace(4, 0), + Token::Key(5, "2".to_string()), + Token::Whitespace(6, 0), + Token::CloseArray(7), + ] + , Some(TokenError::Eof) + )); + + run("[ 1 2 , 3 \"abc\" : -10 ]", + ( + vec![ + Token::OpenArray(0), + Token::Whitespace(1, 0), + Token::Key(2, "1".to_string()), + Token::Whitespace(3, 0), + Token::Key(4, "2".to_string()), + Token::Whitespace(5, 0), + Token::Comma(6), + Token::Whitespace(7, 0), + Token::Key(8, "3".to_string()), + Token::Whitespace(9, 0), + Token::DoubleQuoted(10, "abc".to_string()), + Token::Whitespace(15, 0), + Token::Split(16), + Token::Whitespace(17, 0), + Token::Key(18, "-10".to_string()), + Token::Whitespace(21, 0), + Token::CloseArray(22), + ] + , Some(TokenError::Eof) + )); + + run("?(@.a가 <41.01)", + ( + vec![ + Token::Question(0), + Token::OpenParenthesis(1), + Token::At(2), + Token::Dot(3), + Token::Key(4, "a가".to_string()), + Token::Whitespace(8, 0), + Token::Little(9), + Token::Key(10, "41".to_string()), + Token::Dot(12), + Token::Key(13, "01".to_string()), + Token::CloseParenthesis(15), + ] + , Some(TokenError::Eof) + )); + + run("?(@.a <4a.01)", + ( + vec![ + Token::Question(0), + Token::OpenParenthesis(1), + Token::At(2), + Token::Dot(3), + Token::Key(4, "a".to_string()), + Token::Whitespace(5, 0), + Token::Little(6), + Token::Key(7, "4a".to_string()), + Token::Dot(9), + Token::Key(10, "01".to_string()), + Token::CloseParenthesis(12), + ] + , Some(TokenError::Eof) + )); + + run("?($.c>@.d)", ( + vec![ + Token::Question(0), + Token::OpenParenthesis(1), + Token::Absolute(2), + Token::Dot(3), + Token::Key(4, "c".to_string()), + Token::Greater(5), + Token::At(6), + Token::Dot(7), + Token::Key(8, "d".to_string()), + Token::CloseParenthesis(9) + ] + , Some(TokenError::Eof) + )); + } +} \ No newline at end of file diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 7b3432c..60318ce 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1,5 +1,3 @@ -use std::result::Result; - use super::tokenizer::*; const DUMMY: usize = 0; @@ -7,7 +5,6 @@ const DUMMY: usize = 0; type ParseResult = Result; mod utils { - pub fn string_to_isize(string: &String, msg_handler: F) -> Result where F: Fn() -> String { match string.as_str().parse::() { @@ -52,6 +49,8 @@ pub enum ParseToken { Number(f64), + Bool(bool), + Eof, } @@ -87,12 +86,6 @@ impl<'a> Parser<'a> { Ok(self.json_path()?) } - pub fn parse(&mut self, visitor: &mut V) -> ParseResult<()> { - let node = self.json_path()?; - visitor.visit(node); - Ok(()) - } - fn json_path(&mut self) -> ParseResult { debug!("#json_path"); match self.tokenizer.next_token() { @@ -235,6 +228,18 @@ impl<'a> Parser<'a> { } } + fn boolean(&mut self) -> ParseResult { + debug!("#boolean"); + match self.tokenizer.next_token() { + Ok(Token::Key(_, v)) => { + Ok(self.node(ParseToken::Bool(v.eq_ignore_ascii_case("true")))) + } + _ => { + Err(self.tokenizer.err_msg()) + } + } + } + fn array_quota_value(&mut self) -> ParseResult { debug!("#array_quota_value"); match self.tokenizer.next_token() { @@ -554,8 +559,14 @@ impl<'a> Parser<'a> { | Ok(Token::SingleQuoted(_, _)) => { self.array_quota_value() } - Ok(Token::Key(_, _)) => { - self.term_num() + Ok(Token::Key(_, k)) => { + match k.chars().next() { + Some(ch) => match ch { + '-' | '0'...'9' => self.term_num(), + _ => self.boolean() + } + _ => Err(self.tokenizer.err_msg()) + } } _ => { Err(self.tokenizer.err_msg()) @@ -629,49 +640,81 @@ impl<'a> Parser<'a> { } pub trait NodeVisitor { - fn visit(&mut self, node: Node) { - match node.token { + fn visit(&mut self, node: &Node) { + match &node.token { ParseToken::Absolute | ParseToken::Relative | ParseToken::All - | ParseToken::Key(_) => { - self.visit_token(node.token); + | ParseToken::Key(_) + | ParseToken::Range(_, _) + | ParseToken::Union(_) + | ParseToken::Number(_) + | ParseToken::Bool(_) => { + self.visit_token(&node.token); } ParseToken::In | ParseToken::Leaves => { - node.left.map(|n| self.visit(*n)); - self.visit_token(node.token); - node.right.map(|n| self.visit(*n)); - } - | ParseToken::Range(_, _) - | ParseToken::Union(_) - | ParseToken::Number(_) => { - self.visit_token(node.token); - } + match &node.left { + Some(n) => self.visit(&*n), + _ => {} + } - | ParseToken::Array => { - node.left.map(|n| self.visit(*n)); - self.visit_token(node.token); - node.right.map(|n| self.visit(*n)); - self.visit_token(ParseToken::ArrayEof); + self.visit_token(&node.token); + + match &node.right { + Some(n) => self.visit(&*n), + _ => {} + } + } + ParseToken::Array => { + match &node.left { + Some(n) => self.visit(&*n), + _ => {} + } + + self.visit_token(&node.token); + + match &node.right { + Some(n) => self.visit(&*n), + _ => {} + } + self.visit_token(&ParseToken::ArrayEof); } ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => { - node.left.map(|n| self.visit(*n)); - node.right.map(|n| self.visit(*n)); - self.visit_token(node.token); + match &node.left { + Some(n) => self.visit(&*n), + _ => {} + } + + match &node.right { + Some(n) => self.visit(&*n), + _ => {} + } + + self.visit_token(&node.token); } ParseToken::Filter(_) => { - node.left.map(|n| self.visit(*n)); + match &node.left { + Some(n) => self.visit(&*n), + _ => {} + } + self.end_term(); - node.right.map(|n| self.visit(*n)); + + match &node.right { + Some(n) => self.visit(&*n), + _ => {} + } + self.end_term(); - self.visit_token(node.token); + + self.visit_token(&node.token); } _ => {} } } - fn visit_token(&mut self, token: ParseToken); + fn visit_token(&mut self, token: &ParseToken); fn end_term(&mut self) {} } \ No newline at end of file diff --git a/src/ref_value/de.rs b/src/ref_value/de.rs deleted file mode 100644 index a5765ca..0000000 --- a/src/ref_value/de.rs +++ /dev/null @@ -1,1058 +0,0 @@ -use std::borrow::Cow; -use std::fmt; -use std::ops::Deref; -use std::result::Result; -use std::vec; - -use indexmap::IndexMap; -use serde::{self, Deserialize, Deserializer}; -use serde::de::{DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, VariantAccess, Visitor}; -use serde_json::Value; - -use super::model::*; -use super::serde_error::SerdeError; - -/// -/// see `serde_json/value/de.rs` -/// - -macro_rules! deserialize_prim_number { - ($method:ident) => { - fn $method(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Number(ref n) => { - match n.deserialize_any(visitor) { - Ok(v) => Ok(v), - Err(e) => Err(SerdeError::new(format!("{:?}", e))) - } - } - _ => Err(SerdeError::from_str("invalid type")), - } - } - } -} - -impl<'de> Deserialize<'de> for RefValue { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct RefValueVisitor {} - - impl<'de> Visitor<'de> for RefValueVisitor { - type Value = RefValue; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("any valid JSON value") - } - - #[inline] - fn visit_bool(self, v: bool) -> Result - where - E: serde::de::Error, { - Ok(RefValue::Bool(v)) - } - - #[inline] - fn visit_i64(self, v: i64) -> Result - where - E: serde::de::Error, { - Ok(RefValue::Number(v.into())) - } - - #[inline] - fn visit_u64(self, v: u64) -> Result - where - E: serde::de::Error, { - Ok(RefValue::Number(v.into())) - } - - #[inline] - fn visit_f64(self, v: f64) -> Result - where - E: serde::de::Error, { - let n: Value = v.into(); - if let Value::Number(n) = n { - Ok(RefValue::Number(n)) - } else { - unreachable!() - } - } - - #[inline] - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, { - self.visit_string(String::from(v)) - } - - #[inline] - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, { - Ok(RefValue::String(v)) - } - - #[inline] - fn visit_none(self) -> Result - where - E: serde::de::Error, { - Ok(RefValue::Null) - } - - #[inline] - fn visit_some(self, deserializer: D) -> Result where - D: Deserializer<'de>, { - Deserialize::deserialize(deserializer) - } - - #[inline] - fn visit_unit(self) -> Result - where - E: serde::de::Error, { - Ok(RefValue::Null) - } - - #[inline] - fn visit_seq(self, mut visitor: A) -> Result - where - A: SeqAccess<'de>, { - let mut vec = Vec::new(); - - while let Some(elem) = visitor.next_element()? { - let e: RefValue = elem; - let v: RefValueWrapper = e.into(); - vec.push(v); - } - - Ok(RefValue::Array(vec)) - } - - fn visit_map(self, mut visitor: A) -> Result - where - A: MapAccess<'de>, { - let mut values = IndexMap::new(); - match visitor.next_key() { - Ok(Some(first_key)) => { - let next: RefValue = visitor.next_value()?; - values.insert(first_key, next.into()); - while let Some((k, v)) = visitor.next_entry()? { - let value: RefValue = v; - values.insert(k, value.into()); - } - Ok(RefValue::Object(values)) - } - _ => Ok(RefValue::Object(IndexMap::new())), - } - } - } - - deserializer.deserialize_any(RefValueVisitor {}) - } -} - -fn visit_array<'de, V>(array: Vec, visitor: V) -> Result - where - V: Visitor<'de>, -{ - let mut deserializer = SeqDeserializer::new(array); - let seq = visitor.visit_seq(&mut deserializer)?; - let remaining = deserializer.iter.len(); - if remaining == 0 { - Ok(seq) - } else { - Err(SerdeError::from_str("fewer elements in array")) - } -} - -fn visit_object<'de, V>(object: IndexMap, visitor: V) -> Result - where - V: Visitor<'de>, -{ - let mut deserializer = MapDeserializer::new(object); - let map = visitor.visit_map(&mut deserializer)?; - let remaining = deserializer.iter.len(); - if remaining == 0 { - Ok(map) - } else { - Err(SerdeError::from_str("fewer elements in map")) - } -} - -fn to_vec(vec: &Vec) -> Vec { - vec.iter().map(|v| v.clone()).collect() -} - -fn to_map(object: &IndexMap) -> IndexMap { - let mut map = IndexMap::new(); - for (k, v) in object { - map.insert(k.to_string(), v.clone()); - } - map -} - -impl<'de> serde::Deserializer<'de> for RefValue { - type Error = SerdeError; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result where - V: Visitor<'de> { - match self { - RefValue::Null => visitor.visit_unit(), - RefValue::Bool(v) => visitor.visit_bool(v), - RefValue::Number(n) => { - n.deserialize_any(visitor).map_err(|e| SerdeError::new(format!("{:?}", e))) - } - RefValue::String(v) => visitor.visit_string(v), - RefValue::Array(array) => visit_array(array, visitor), - RefValue::Object(object) => visit_object(object, visitor) - } - } - - deserialize_prim_number!(deserialize_i8); - deserialize_prim_number!(deserialize_i16); - deserialize_prim_number!(deserialize_i32); - deserialize_prim_number!(deserialize_i64); - deserialize_prim_number!(deserialize_u8); - deserialize_prim_number!(deserialize_u16); - deserialize_prim_number!(deserialize_u32); - deserialize_prim_number!(deserialize_u64); - deserialize_prim_number!(deserialize_f32); - deserialize_prim_number!(deserialize_f64); - - #[inline] - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Null => visitor.visit_none(), - _ => visitor.visit_some(self), - } - } - - #[inline] - fn deserialize_enum( - self, - _name: &str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let (variant, value) = match self { - RefValue::Object(value) => { - let mut iter = value.into_iter(); - let (variant, value) = match iter.next() { - Some(v) => v, - None => { - return Err(SerdeError::from_str("map with a single key")); - } - }; - if iter.next().is_some() { - return Err(SerdeError::from_str("map with a single key")); - } - (variant, Some(value)) - } - RefValue::String(variant) => (variant, None), - _ => { - return Err(SerdeError::from_str("string or map")); - } - }; - - visitor.visit_enum(EnumDeserializer { - variant: variant, - value: value, - }) - } - - #[inline] - fn deserialize_newtype_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let _ = name; - visitor.visit_newtype_struct(self) - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Bool(v) => visitor.visit_bool(v), - _ => Err(SerdeError::from_str("invalid type: bool")), - } - } - - fn deserialize_char(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_str(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::String(v) => visitor.visit_string(v), - _ => Err(SerdeError::from_str("invalid type: string")), - } - } - - fn deserialize_bytes(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_byte_buf(visitor) - } - - fn deserialize_byte_buf(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::String(v) => visitor.visit_string(v), - RefValue::Array(v) => visit_array(v, visitor), - _ => Err(SerdeError::from_str("invalid type: string or array")), - } - } - - fn deserialize_unit(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Null => visitor.visit_unit(), - _ => Err(SerdeError::from_str("invalid type: null")), - } - } - - fn deserialize_unit_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_unit(visitor) - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Array(v) => visit_array(v, visitor), - _ => Err(SerdeError::from_str("invalid type: array")), - } - } - - fn deserialize_tuple(self, _len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_seq(visitor) - } - - fn deserialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_seq(visitor) - } - - fn deserialize_map(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Object(v) => visit_object(v, visitor), - _ => Err(SerdeError::from_str("invalid type: object")) - } - } - - fn deserialize_struct( - self, - _name: &'static str, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Array(v) => visit_array(v, visitor), - RefValue::Object(v) => visit_object(v, visitor), - _ => Err(SerdeError::from_str("invalid type: array, object")) - } - } - - fn deserialize_identifier(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_ignored_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - drop(self); - visitor.visit_unit() - } -} - -impl<'de> serde::Deserializer<'de> for &RefValue { - type Error = SerdeError; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result where - V: Visitor<'de> { - match self { - RefValue::Null => visitor.visit_unit(), - RefValue::Bool(v) => visitor.visit_bool(*v), - RefValue::Number(n) => { - n.deserialize_any(visitor).map_err(|e| SerdeError::new(format!("{:?}", e))) - } - RefValue::String(v) => visitor.visit_string(v.to_string()), - RefValue::Array(array) => visit_array(to_vec(array), visitor), - RefValue::Object(object) => { - visit_object(to_map(object), visitor) - } - } - } - - deserialize_prim_number!(deserialize_i8); - deserialize_prim_number!(deserialize_i16); - deserialize_prim_number!(deserialize_i32); - deserialize_prim_number!(deserialize_i64); - deserialize_prim_number!(deserialize_u8); - deserialize_prim_number!(deserialize_u16); - deserialize_prim_number!(deserialize_u32); - deserialize_prim_number!(deserialize_u64); - deserialize_prim_number!(deserialize_f32); - deserialize_prim_number!(deserialize_f64); - - #[inline] - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Null => visitor.visit_none(), - _ => visitor.visit_some(self), - } - } - - #[inline] - fn deserialize_enum( - self, - _name: &str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let (variant, value) = match self { - RefValue::Object(value) => { - let mut iter = value.into_iter(); - let (variant, value) = match iter.next() { - Some(v) => v, - None => { - return Err(SerdeError::from_str("map with a single key")); - } - }; - if iter.next().is_some() { - return Err(SerdeError::from_str("map with a single key")); - } - (variant, Some(value)) - } - RefValue::String(variant) => (variant, None), - _ => { - return Err(SerdeError::from_str("string or map")); - } - }; - - visitor.visit_enum(EnumDeserializer { - variant: variant.to_string(), - value: match value { - Some(v) => Some(v.clone()), - _ => None - }, - }) - } - - #[inline] - fn deserialize_newtype_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let _ = name; - visitor.visit_newtype_struct(self) - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Bool(v) => visitor.visit_bool(*v), - _ => Err(SerdeError::from_str("invalid type: bool")), - } - } - - fn deserialize_char(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_str(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::String(v) => visitor.visit_string(v.to_string()), - _ => Err(SerdeError::from_str("invalid type: string")), - } - } - - fn deserialize_bytes(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_byte_buf(visitor) - } - - fn deserialize_byte_buf(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::String(v) => visitor.visit_string(v.to_string()), - RefValue::Array(vec) => visit_array(to_vec(vec), visitor), - _ => Err(SerdeError::from_str("invalid type: string or array")), - } - } - - fn deserialize_unit(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Null => visitor.visit_unit(), - _ => Err(SerdeError::from_str("invalid type: null")), - } - } - - fn deserialize_unit_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_unit(visitor) - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Array(vec) => visit_array(to_vec(vec), visitor), - _ => Err(SerdeError::from_str("invalid type: array")), - } - } - - fn deserialize_tuple(self, _len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_seq(visitor) - } - - fn deserialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_seq(visitor) - } - - fn deserialize_map(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Object(object) => { - visit_object(to_map(object), visitor) - } - _ => Err(SerdeError::from_str("invalid type: object")) - } - } - - fn deserialize_struct( - self, - _name: &'static str, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self { - RefValue::Array(vec) => visit_array(to_vec(vec), visitor), - RefValue::Object(object) => { - visit_object(to_map(object), visitor) - } - _ => Err(SerdeError::from_str("invalid type: array, object")) - } - } - - fn deserialize_identifier(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_ignored_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - drop(self); - visitor.visit_unit() - } -} - - -struct SeqDeserializer { - iter: vec::IntoIter, -} - -impl SeqDeserializer { - fn new(vec: Vec) -> Self { - SeqDeserializer { - iter: vec.into_iter(), - } - } -} - -impl<'de> serde::Deserializer<'de> for SeqDeserializer { - type Error = SerdeError; - - #[inline] - fn deserialize_any(mut self, visitor: V) -> Result - where - V: Visitor<'de>, - { - let len = self.iter.len(); - if len == 0 { - visitor.visit_unit() - } else { - let ret = visitor.visit_seq(&mut self)?; - let remaining = self.iter.len(); - if remaining == 0 { - Ok(ret) - } else { - Err(SerdeError::from_str("fewer elements in array")) - } - } - } - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct enum identifier ignored_any - } -} - -impl<'de> SeqAccess<'de> for SeqDeserializer { - type Error = SerdeError; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: serde::de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some(value) => seed.deserialize(value.deref()).map(Some), - None => Ok(None), - } - } - - fn size_hint(&self) -> Option { - match self.iter.size_hint() { - (lower, Some(upper)) if lower == upper => Some(upper), - _ => None, - } - } -} - -struct MapDeserializer { - iter: as IntoIterator>::IntoIter, - value: Option, -} - -impl MapDeserializer { - fn new(map: IndexMap) -> Self { - MapDeserializer { - iter: map.into_iter(), - value: None, - } - } -} - -impl<'de> MapAccess<'de> for MapDeserializer { - type Error = SerdeError; - - fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: DeserializeSeed<'de>, - { - match self.iter.next() { - Some((key, value)) => { - self.value = Some(value); - let key_de = MapKeyDeserializer { - key: Cow::Owned(key), - }; - seed.deserialize(key_de).map(Some) - } - None => Ok(None), - } - } - - fn next_value_seed(&mut self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { - match self.value.take() { - Some(value) => seed.deserialize(value.deref()), - None => Err(serde::de::Error::custom("value is missing")), - } - } - - fn size_hint(&self) -> Option { - match self.iter.size_hint() { - (lower, Some(upper)) if lower == upper => Some(upper), - _ => None, - } - } -} - -impl<'de> serde::Deserializer<'de> for MapDeserializer { - type Error = SerdeError; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_map(self) - } - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct enum identifier ignored_any - } -} - -struct MapKeyDeserializer<'de> { - key: Cow<'de, str>, -} - -macro_rules! deserialize_integer_key { - ($method:ident => $visit:ident) => { - fn $method(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match (self.key.parse(), self.key) { - (Ok(integer), _) => visitor.$visit(integer), - (Err(_), Cow::Borrowed(s)) => visitor.visit_borrowed_str(s), - (Err(_), Cow::Owned(s)) => visitor.visit_string(s), - } - } - } -} - -impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { - type Error = SerdeError; - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor) - } - - deserialize_integer_key!(deserialize_i8 => visit_i8); - deserialize_integer_key!(deserialize_i16 => visit_i16); - deserialize_integer_key!(deserialize_i32 => visit_i32); - deserialize_integer_key!(deserialize_i64 => visit_i64); - deserialize_integer_key!(deserialize_u8 => visit_u8); - deserialize_integer_key!(deserialize_u16 => visit_u16); - deserialize_integer_key!(deserialize_u32 => visit_u32); - deserialize_integer_key!(deserialize_u64 => visit_u64); - - serde_if_integer128! { - deserialize_integer_key!(deserialize_i128 => visit_i128); - deserialize_integer_key!(deserialize_u128 => visit_u128); - } - - #[inline] - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - // Map keys cannot be null. - visitor.visit_some(self) - } - - #[inline] - fn deserialize_newtype_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - visitor.visit_newtype_struct(self) - } - - fn deserialize_enum( - self, - name: &'static str, - variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.key - .into_deserializer() - .deserialize_enum(name, variants, visitor) - } - - forward_to_deserialize_any! { - bool f32 f64 char str string bytes byte_buf unit unit_struct seq tuple - tuple_struct map struct identifier ignored_any - } -} - -struct BorrowedCowStrDeserializer<'de> { - value: Cow<'de, str>, -} - -impl<'de> BorrowedCowStrDeserializer<'de> { - fn new(value: Cow<'de, str>) -> Self { - BorrowedCowStrDeserializer { value: value } - } -} - -impl<'de> serde::Deserializer<'de> for BorrowedCowStrDeserializer<'de> { - type Error = SerdeError; - - fn deserialize_any(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - match self.value { - Cow::Borrowed(string) => visitor.visit_borrowed_str(string), - Cow::Owned(string) => visitor.visit_string(string), - } - } - - fn deserialize_enum( - self, - _name: &str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_enum(self) - } - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct identifier ignored_any - } -} - -impl<'de> serde::de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> { - type Error = SerdeError; - type Variant = UnitOnly; - - fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> - where - T: serde::de::DeserializeSeed<'de>, - { - let value = seed.deserialize(self)?; - Ok((value, UnitOnly)) - } -} - -struct UnitOnly; - -impl<'de> serde::de::VariantAccess<'de> for UnitOnly { - type Error = SerdeError; - - fn unit_variant(self) -> Result<(), Self::Error> { - Ok(()) - } - - fn newtype_variant_seed(self, _seed: T) -> Result - where - T: serde::de::DeserializeSeed<'de>, - { - Err(SerdeError::from_str("newtype variant")) - } - - fn tuple_variant(self, _len: usize, _visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - Err(SerdeError::from_str("tuple variant")) - } - - fn struct_variant( - self, - _fields: &'static [&'static str], - _visitor: V, - ) -> Result - where - V: serde::de::Visitor<'de>, - { - Err(SerdeError::from_str("struct variant")) - } -} - -struct EnumDeserializer { - variant: String, - value: Option, -} - -impl<'de> EnumAccess<'de> for EnumDeserializer { - type Error = SerdeError; - type Variant = VariantDeserializer; - - fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer), Self::Error> - where - V: DeserializeSeed<'de>, - { - let variant = self.variant.into_deserializer(); - let visitor = VariantDeserializer { value: self.value }; - seed.deserialize(variant).map(|v| (v, visitor)) - } -} - -struct VariantDeserializer { - value: Option, -} - -impl<'de> VariantAccess<'de> for VariantDeserializer { - type Error = SerdeError; - - fn unit_variant(self) -> Result<(), Self::Error> { - match self.value { - Some(value) => Deserialize::deserialize(value.deref()), - None => Ok(()), - } - } - - fn newtype_variant_seed(self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { - match self.value { - Some(value) => seed.deserialize(value.deref()), - None => Err(SerdeError::from_str("newtype variant")), - } - } - - fn tuple_variant(self, _len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.value { - Some(ref_value) => { - match ref_value.deref() { - RefValue::Array(vec) => { - serde::Deserializer::deserialize_any(SeqDeserializer::new(to_vec(vec)), visitor) - } - _ => Err(SerdeError::from_str("tuple variant")) - } - } - None => Err(SerdeError::from_str("tuple variant")), - } - } - - fn struct_variant( - self, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.value { - Some(ref_value) => { - match ref_value.deref() { - RefValue::Object(vec) => { - serde::Deserializer::deserialize_any(MapDeserializer::new(to_map(vec)), visitor) - } - _ => Err(SerdeError::from_str("struct variant")) - } - } - _ => Err(SerdeError::from_str("struct variant")), - } - } -} \ No newline at end of file diff --git a/src/ref_value/mod.rs b/src/ref_value/mod.rs deleted file mode 100644 index 05dec5f..0000000 --- a/src/ref_value/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod model; -pub mod de; -pub mod ser; -pub mod serde_error; \ No newline at end of file diff --git a/src/ref_value/model.rs b/src/ref_value/model.rs deleted file mode 100644 index 5c6e76a..0000000 --- a/src/ref_value/model.rs +++ /dev/null @@ -1,290 +0,0 @@ -use std::cell::RefCell; -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::sync::Arc; - -use indexmap::map::IndexMap; -use serde::ser::Serialize; -use serde_json::{Number, Value}; -use std::fmt; - -type TypeRefValue = Arc>; - -pub struct RefValueWrapper { - 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 { - fn eq(&self, other: &RefValueWrapper) -> bool { - Arc::ptr_eq(&self.data, &other.data) - } -} - -impl Eq for RefValueWrapper {} - -impl Deref for RefValueWrapper { - type Target = RefValue; - - fn deref(&self) -> &Self::Target { - 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(&self, state: &mut H) { - self.deref().hash(state) - } -} - -impl Clone for RefValueWrapper { - fn clone(&self) -> Self { - RefValueWrapper { - data: self.data.clone() - } - } -} - -/// -/// serde_json::Value 참고 -/// -pub trait RefIndex { - fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper>; - fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper>; - fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper; -} - -impl RefIndex for usize { - fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> { - match *v { - RefValue::Array(ref vec) => vec.get(*self), - _ => None, - } - } - fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> { - match *v { - RefValue::Array(ref mut vec) => vec.get_mut(*self), - _ => None, - } - } - fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper { - match *v { - RefValue::Array(ref mut vec) => { - let len = vec.len(); - vec.get_mut(*self).unwrap_or_else(|| { - panic!( - "cannot access index {} of JSON array of length {}", - self, len - ) - }) - } - _ => panic!("cannot access index {} of JSON {:?}", self, v), - } - } -} - -impl RefIndex for str { - fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> { - match *v { - RefValue::Object(ref map) => map.get(self), - _ => None, - } - } - fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> { - match *v { - RefValue::Object(ref mut map) => map.get_mut(self), - _ => None, - } - } - fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper { - if let RefValue::Null = *v { - *v = RefValue::Object(IndexMap::new()); - } - match *v { - RefValue::Object(ref mut map) => { - map.entry(self.to_owned()).or_insert(RefValue::Null.into()) - } - _ => panic!("cannot access key {:?} in JSON {:?}", self, v), - } - } -} - -impl RefIndex for String { - fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> { - self[..].index_into(v) - } - fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> { - self[..].index_into_mut(v) - } - fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper { - self[..].index_or_insert(v) - } -} - -pub enum RefValue { - Null, - Bool(bool), - Number(Number), - String(String), - Array(Vec), - Object(IndexMap), -} - -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(); - let mut hasher2 = DefaultHasher::new(); - - self.hash(&mut hasher1); - other.hash(&mut hasher2); - - hasher1.finish() == hasher2.finish() - } -} - -static REF_VALUE_NULL: &'static str = "$jsonpath::ref_value::model::RefValue::Null"; - -impl Hash for RefValue { - fn hash(&self, state: &mut H) { - -// println!("###hash - RefValue - {:?}", self); - - match self { - RefValue::Null => { - REF_VALUE_NULL.hash(state) - } - RefValue::Bool(b) => { - b.hash(state) - } - RefValue::Number(n) => { - if n.is_f64() { - n.as_f64().unwrap().to_string().hash(state) - } else if n.is_i64() { - n.as_i64().unwrap().hash(state); - } else { - n.as_u64().unwrap().hash(state); - } - } - RefValue::String(s) => { - s.hash(state) - } - RefValue::Object(map) => { - for (k, v) in map { - k.hash(state); - v.hash(state); - } - } - RefValue::Array(v) => { - for i in v { - i.hash(state); - } - } - } - } -} - -impl Eq for RefValue {} - -impl RefValue { - pub fn get(&self, index: I) -> Option<&RefValueWrapper> { - index.index_into(self) - } - - pub fn is_object(&self) -> bool { - match *self { - RefValue::Object(_) => true, - _ => false, - } - } - - pub fn is_array(&self) -> bool { - match *self { - RefValue::Array(_) => true, - _ => false, - } - } - - pub fn len(&self) -> usize { - match &self { - RefValue::Object(m) => m.len(), - RefValue::Array(v) => v.len(), - _ => 0, - } - } - - 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 { - match *self { - RefValue::Null => true, - _ => false, - } - } -} - -impl Into for RefValue { - fn into(self) -> RefValueWrapper { - RefValueWrapper { - data: Arc::new(RefCell::new(self)) - } - } -} - -impl Into for &Value { - fn into(self) -> RefValue { - match self.serialize(super::ser::RefValueSerializer) { - Ok(v) => v, - Err(e) => panic!("Error Value into RefValue: {:?}", e) - } - } -} - -impl Into for &Value { - fn into(self) -> RefValueWrapper { - match self.serialize(super::ser::RefValueSerializer) { - Ok(v) => v.into(), - Err(e) => panic!("Error Value into RefValue: {:?}", e) - } - } -} - -impl Into for &RefValueWrapper { - fn into(self) -> Value { - match serde_json::to_value(self.deref()) { - Ok(v) => v, - Err(e) => panic!("Error RefValueWrapper into Value: {:?}", e) - } - } -} \ No newline at end of file diff --git a/src/ref_value/ser.rs b/src/ref_value/ser.rs deleted file mode 100644 index 22e0c68..0000000 --- a/src/ref_value/ser.rs +++ /dev/null @@ -1,624 +0,0 @@ -use std::result::Result; - -use indexmap::IndexMap; -use serde::{self, Serialize}; -use serde::ser::Impossible; - -use ref_value::model::{RefValue, RefValueWrapper}; - -use super::serde_error::SerdeError; - -/// -/// see `serde_json/value/ser.rs` -/// -impl Serialize for RefValue { - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: ::serde::Serializer, - { - match *self { - RefValue::Null => serializer.serialize_unit(), - RefValue::Bool(b) => serializer.serialize_bool(b), - RefValue::Number(ref n) => n.serialize(serializer), - RefValue::String(ref s) => serializer.serialize_str(s), - RefValue::Array(ref v) => { - use std::ops::Deref; - let v: Vec<&RefValue> = v.iter().map(|v| v.deref()).collect(); - v.serialize(serializer) - } - RefValue::Object(ref m) => { - use serde::ser::SerializeMap; - use std::ops::Deref; - let mut map = try!(serializer.serialize_map(Some(m.len()))); - for (k, v) in m { - try!(map.serialize_key(k)); - try!(map.serialize_value(v.deref())); - } - map.end() - } - } - } -} - -pub struct RefValueSerializer; - -impl serde::Serializer for RefValueSerializer { - type Ok = RefValue; - type Error = SerdeError; - - type SerializeSeq = SerializeVec; - type SerializeTuple = SerializeVec; - type SerializeTupleStruct = SerializeVec; - type SerializeTupleVariant = SerializeTupleVariant; - type SerializeMap = SerializeMap; - type SerializeStruct = SerializeMap; - type SerializeStructVariant = SerializeStructVariant; - - #[inline] - fn serialize_bool(self, value: bool) -> Result { - Ok(RefValue::Bool(value)) - } - - #[inline] - fn serialize_i8(self, value: i8) -> Result { - self.serialize_i64(value as i64) - } - - #[inline] - fn serialize_i16(self, value: i16) -> Result { - self.serialize_i64(value as i64) - } - - #[inline] - fn serialize_i32(self, value: i32) -> Result { - self.serialize_i64(value as i64) - } - - fn serialize_i64(self, value: i64) -> Result { - Ok(RefValue::Number(value.into())) - } - - #[inline] - fn serialize_u8(self, value: u8) -> Result { - self.serialize_u64(value as u64) - } - - #[inline] - fn serialize_u16(self, value: u16) -> Result { - self.serialize_u64(value as u64) - } - - #[inline] - fn serialize_u32(self, value: u32) -> Result { - self.serialize_u64(value as u64) - } - - #[inline] - fn serialize_u64(self, value: u64) -> Result { - Ok(RefValue::Number(value.into())) - } - - #[inline] - fn serialize_f32(self, value: f32) -> Result { - self.serialize_f64(value as f64) - } - - #[inline] - fn serialize_f64(self, value: f64) -> Result { - Ok(serde_json::Number::from_f64(value).map_or(RefValue::Null, RefValue::Number)) - } - - #[inline] - fn serialize_char(self, value: char) -> Result { - let mut s = String::new(); - s.push(value); - self.serialize_str(&s) - } - - #[inline] - fn serialize_str(self, value: &str) -> Result { - Ok(RefValue::String(value.to_owned())) - } - - fn serialize_bytes(self, value: &[u8]) -> Result { - let vec = value.iter().map(|&b| RefValue::Number(b.into()).into()).collect(); - Ok(RefValue::Array(vec)) - } - - #[inline] - fn serialize_unit(self) -> Result { - Ok(RefValue::Null) - } - - #[inline] - fn serialize_unit_struct(self, _name: &'static str) -> Result { - self.serialize_unit() - } - - #[inline] - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - self.serialize_str(variant) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - let mut values: IndexMap = IndexMap::new(); - values.insert(String::from(variant), { - value.serialize(RefValueSerializer)?.into() - }); - Ok(RefValue::Object(values)) - } - - #[inline] - fn serialize_none(self) -> Result { - self.serialize_unit() - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: Serialize, - { - value.serialize(self) - } - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeVec { - vec: Vec::with_capacity(len.unwrap_or(0)), - }) - } - - fn serialize_tuple(self, len: usize) -> Result { - self.serialize_seq(Some(len)) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.serialize_seq(Some(len)) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - Ok(SerializeTupleVariant { - name: String::from(variant), - vec: Vec::with_capacity(len), - }) - } - - fn serialize_map(self, _len: Option) -> Result { - Ok(SerializeMap::Map { - map: IndexMap::new(), - next_key: None, - }) - } - - fn serialize_struct( - self, - name: &'static str, - len: usize, - ) -> Result { - match name { - _ => self.serialize_map(Some(len)), - } - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeStructVariant { - name: String::from(variant), - map: IndexMap::new(), - }) - } -} - -pub struct SerializeVec { - vec: Vec, -} - -pub struct SerializeTupleVariant { - name: String, - vec: Vec, -} - -pub enum SerializeMap { - Map { - map: IndexMap, - next_key: Option, - }, -} - -pub struct SerializeStructVariant { - name: String, - map: IndexMap, -} - -impl serde::ser::SerializeSeq for SerializeVec { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - self.vec.push({ - value.serialize(RefValueSerializer)?.into() - }); - Ok(()) - } - - fn end(self) -> Result { - Ok(RefValue::Array(self.vec)) - } -} - -impl serde::ser::SerializeTuple for SerializeVec { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - serde::ser::SerializeSeq::serialize_element(self, value) - } - - fn end(self) -> Result { - serde::ser::SerializeSeq::end(self) - } -} - -impl serde::ser::SerializeTupleStruct for SerializeVec { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - serde::ser::SerializeSeq::serialize_element(self, value) - } - - fn end(self) -> Result { - serde::ser::SerializeSeq::end(self) - } -} - -impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - self.vec.push({ - let a: RefValue = value.serialize(RefValueSerializer)?; - a.into() - }); - Ok(()) - } - - fn end(self) -> Result { - let mut object: IndexMap = IndexMap::new(); - - object.insert(self.name, RefValue::Array(self.vec).into()); - - Ok(RefValue::Object(object)) - } -} - -impl serde::ser::SerializeMap for SerializeMap { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - match *self { - SerializeMap::Map { - ref mut next_key, .. - } => { - *next_key = Some(key.serialize(MapKeySerializer)?); - Ok(()) - } - } - } - - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - match *self { - SerializeMap::Map { - ref mut map, - ref mut next_key, - } => { - let key = next_key.take(); - // Panic because this indicates a bug in the program rather than an - // expected failure. - let key = key.expect("serialize_value called before serialize_key"); - map.insert(key, { - let a: RefValue = value.serialize(RefValueSerializer)?; - a.into() - }); - Ok(()) - } - } - } - - fn end(self) -> Result { - match self { - SerializeMap::Map { map, .. } => Ok(RefValue::Object(map)), - } - } -} - -struct MapKeySerializer; - -fn key_must_be_a_string() -> SerdeError { - SerdeError::from_str("key must be string") -} - -impl serde::Serializer for MapKeySerializer { - type Ok = String; - type Error = SerdeError; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - #[inline] - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - Ok(variant.to_owned()) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - value.serialize(self) - } - - fn serialize_bool(self, _value: bool) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_i8(self, value: i8) -> Result { - Ok(value.to_string()) - } - - fn serialize_i16(self, value: i16) -> Result { - Ok(value.to_string()) - } - - fn serialize_i32(self, value: i32) -> Result { - Ok(value.to_string()) - } - - fn serialize_i64(self, value: i64) -> Result { - Ok(value.to_string()) - } - - fn serialize_u8(self, value: u8) -> Result { - Ok(value.to_string()) - } - - fn serialize_u16(self, value: u16) -> Result { - Ok(value.to_string()) - } - - fn serialize_u32(self, value: u32) -> Result { - Ok(value.to_string()) - } - - fn serialize_u64(self, value: u64) -> Result { - Ok(value.to_string()) - } - - fn serialize_f32(self, _value: f32) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_f64(self, _value: f64) -> Result { - Err(key_must_be_a_string()) - } - - #[inline] - fn serialize_char(self, value: char) -> Result { - Ok({ - let mut s = String::new(); - s.push(value); - s - }) - } - - #[inline] - fn serialize_str(self, value: &str) -> Result { - Ok(value.to_owned()) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_unit(self) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - Err(key_must_be_a_string()) - } - - fn serialize_none(self) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_some(self, _value: &T) -> Result - where - T: Serialize, - { - Err(key_must_be_a_string()) - } - - fn serialize_seq(self, _len: Option) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple(self, _len: usize) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_map(self, _len: Option) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } -} - -impl serde::ser::SerializeStruct for SerializeMap { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - match *self { - SerializeMap::Map { .. } => { - serde::ser::SerializeMap::serialize_key(self, key)?; - serde::ser::SerializeMap::serialize_value(self, value) - } - } - } - - fn end(self) -> Result { - match self { - SerializeMap::Map { .. } => serde::ser::SerializeMap::end(self), - } - } -} - -impl serde::ser::SerializeStructVariant for SerializeStructVariant { - type Ok = RefValue; - type Error = SerdeError; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - self.map.insert(String::from(key), { - let a: RefValue = value.serialize(RefValueSerializer)?; - a.into() - }); - Ok(()) - } - - fn end(self) -> Result { - let mut object: IndexMap = IndexMap::new(); - - object.insert(self.name, RefValue::Object(self.map).into()); - - Ok(RefValue::Object(object)) - } -} diff --git a/src/ref_value/serde_error.rs b/src/ref_value/serde_error.rs deleted file mode 100644 index 7deb7f1..0000000 --- a/src/ref_value/serde_error.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::fmt; - -#[derive(Debug)] -pub struct SerdeError { - msg: String, -} - -impl<'a> SerdeError { - pub fn new(msg: String) -> Self { - SerdeError { msg: msg } - } - - pub fn from_str(msg: &str) -> Self { - SerdeError { msg: msg.to_string() } - } -} - -impl serde::de::Error for SerdeError { - #[cold] - fn custom(msg: T) -> SerdeError { - SerdeError { msg: msg.to_string() } - } -} - -impl serde::ser::Error for SerdeError { - #[cold] - fn custom(msg: T) -> SerdeError { - SerdeError { msg: msg.to_string() } - } -} - -impl std::error::Error for SerdeError {} - -impl fmt::Display for SerdeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.msg) - } -} \ No newline at end of file diff --git a/src/select/mod.rs b/src/select/mod.rs index ac0856c..07c4334 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,2 +1,1002 @@ -pub mod selector; -pub mod modifiable; \ No newline at end of file +use array_tool::vec::{Intersect, Union}; +use serde_json::{Number, Value}; + +use parser::parser::*; +use std::collections::HashSet; + +fn to_f64(n: &Number) -> f64 { + if n.is_i64() { + n.as_i64().unwrap() as f64 + } else if n.is_f64() { + n.as_f64().unwrap() + } else { + n.as_u64().unwrap() as f64 + } +} + +trait Cmp { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool; + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool; + + fn cmp_string(&self, v1: &String, v2: &String) -> bool; + + fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value>; + + fn default(&self) -> bool { false } +} + +struct CmpEq; + +impl Cmp for CmpEq { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 == v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 == v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 == v2 + } + + fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> { + v1.intersect(v2.to_vec()) + } +} + +struct CmpNe; + +impl Cmp for CmpNe { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 != v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 != v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 != v2 + } + + fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> { + v1.intersect_if(v2.to_vec(), |a, b| a != b) + } +} + +struct CmpGt; + +impl Cmp for CmpGt { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 > v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 > v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 > v2 + } + + fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> { + Vec::new() + } +} + +struct CmpGe; + +impl Cmp for CmpGe { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 >= v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 >= v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 >= v2 + } + + fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> { + Vec::new() + } +} + +struct CmpLt; + +impl Cmp for CmpLt { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 < v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 < v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 < v2 + } + + fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> { + Vec::new() + } +} + +struct CmpLe; + +impl Cmp for CmpLe { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + v1 <= v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 <= v2 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + v1 <= v2 + } + + fn cmp_json<'a>(&self, _: &Vec<&'a Value>, _: &Vec<&'a Value>) -> Vec<&'a Value> { + Vec::new() + } +} + +struct CmpAnd; + +impl Cmp for CmpAnd { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + *v1 && *v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 > &0_f64 && v2 > &0_f64 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + !v1.is_empty() && !v2.is_empty() + } + + fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> { + v1.intersect(v2.to_vec()) + } +} + +struct CmpOr; + +impl Cmp for CmpOr { + fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool { + *v1 || *v2 + } + + fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool { + v1 > &0_f64 || v2 > &0_f64 + } + + fn cmp_string(&self, v1: &String, v2: &String) -> bool { + !v1.is_empty() || !v2.is_empty() + } + + fn cmp_json<'a>(&self, v1: &Vec<&'a Value>, v2: &Vec<&'a Value>) -> Vec<&'a Value> { + v1.union(v2.to_vec()) + } +} + +#[derive(Debug)] +enum ExprTerm<'a> { + String(String), + Number(Number), + Bool(bool), + Json(Option, Vec<&'a Value>), +} + +impl<'a> ExprTerm<'a> { + fn is_string(&self) -> bool { + match &self { + ExprTerm::String(_) => true, + _ => false + } + } + + fn is_number(&self) -> bool { + match &self { + ExprTerm::Number(_) => true, + _ => false + } + } + + fn is_bool(&self) -> bool { + match &self { + ExprTerm::Bool(_) => true, + _ => false + } + } + + fn is_json(&self) -> bool { + match &self { + ExprTerm::Json(_, _) => true, + _ => false + } + } + + fn cmp(&self, other: &Self, cmp_fn: &C1, reverse_cmp_fn: &C2) -> ExprTerm<'a> { + match &self { + ExprTerm::String(s1) => match &other { + ExprTerm::String(s2) => ExprTerm::Bool(cmp_fn.cmp_string(s1, s2)), + ExprTerm::Json(_, _) => { + other.cmp(&self, reverse_cmp_fn, cmp_fn) + } + _ => ExprTerm::Bool(cmp_fn.default()) + } + ExprTerm::Number(n1) => match &other { + ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2))), + ExprTerm::Json(_, _) => { + other.cmp(&self, reverse_cmp_fn, cmp_fn) + } + _ => ExprTerm::Bool(cmp_fn.default()) + } + ExprTerm::Bool(b1) => match &other { + ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(b1, b2)), + ExprTerm::Json(_, _) => { + other.cmp(&self, reverse_cmp_fn, cmp_fn) + } + _ => ExprTerm::Bool(cmp_fn.default()) + } + ExprTerm::Json(fk1, vec1) if other.is_string() => { + match &other { + ExprTerm::String(s2) => { + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::String(s1) => cmp_fn.cmp_string(s1, s2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::String(s1)) = map1.get(k) { + return cmp_fn.cmp_string(s1, s2); + } + } + cmp_fn.default() + } + _ => cmp_fn.default() + } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + } + _ => unreachable!() + } + } + ExprTerm::Json(fk1, vec1) if other.is_number() => { + match &other { + ExprTerm::Number(n2) => { + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::Number(n1) => cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Number(n1)) = map1.get(k) { + return cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)); + } + } + cmp_fn.default() + } + _ => cmp_fn.default() + } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + } + _ => unreachable!() + } + } + ExprTerm::Json(fk1, vec1) if other.is_bool() => { + match &other { + ExprTerm::Bool(b2) => { + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::Bool(b1) => cmp_fn.cmp_bool(b1, b2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Bool(b1)) = map1.get(k) { + return cmp_fn.cmp_bool(b1, b2); + } + } + cmp_fn.default() + } + _ => cmp_fn.default() + } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + } + _ => unreachable!() + } + } + ExprTerm::Json(_, vec1) if other.is_json() => { + match &other { + ExprTerm::Json(_, vec2) => { + let vec = cmp_fn.cmp_json(vec1, vec2); + if vec.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, vec) } + } + _ => unreachable!() + } + } + _ => unreachable!() + } + } + + fn eq(&self, other: &Self, ret: &mut Option>) { + debug!("eq - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpEq, &CmpEq); + debug!("eq = {:?}", tmp); + *ret = Some(tmp); + } + + fn ne(&self, other: &Self, ret: &mut Option>) { + debug!("ne - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpNe, &CmpNe); + debug!("ne = {:?}", tmp); + *ret = Some(tmp); + } + + fn gt(&self, other: &Self, ret: &mut Option>) { + debug!("gt - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpGt, &CmpLt); + debug!("gt = {:?}", tmp); + *ret = Some(tmp); + } + + fn ge(&self, other: &Self, ret: &mut Option>) { + debug!("ge - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpGe, &CmpLe); + debug!("ge = {:?}", tmp); + *ret = Some(tmp); + } + + fn lt(&self, other: &Self, ret: &mut Option>) { + debug!("lt - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpLt, &CmpGt); + debug!("lt = {:?}", tmp); + *ret = Some(tmp); + } + + fn le(&self, other: &Self, ret: &mut Option>) { + debug!("le - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpLe, &CmpGe); + debug!("le = {:?}", tmp); + *ret = Some(tmp); + } + + fn and(&self, other: &Self, ret: &mut Option>) { + debug!("and - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpAnd, &CmpAnd); + debug!("and = {:?}", tmp); + *ret = Some(tmp); + } + + fn or(&self, other: &Self, ret: &mut Option>) { + debug!("or - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpOr, &CmpOr); + debug!("or = {:?}", tmp); + *ret = Some(tmp); + } +} + +fn walk_all_with_str<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { + if is_filter { + walk(vec, tmp, &|v| { + match v { + Value::Object(map) if map.contains_key(key) => { + Some(vec![v]) + } + _ => None + } + }); + } else { + walk(vec, tmp, &|v| { + match v { + Value::Object(map) => match map.get(key) { + Some(v) => Some(vec![v]), + _ => None + } + _ => None + } + }); + } +} + +fn walk_all<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>) { + walk(vec, tmp, &|v| match v { + Value::Array(vec) => { + Some(vec.iter().collect()) + } + Value::Object(map) => { + let mut tmp = Vec::new(); + for (_, v) in map { + tmp.push(v); + } + Some(tmp) + } + _ => None + }); +} + +fn walk<'a, F>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>, fun: &F) + where F: Fn(&Value) -> Option> +{ + fn _walk<'a, F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) + where F: Fn(&Value) -> Option> + { + if let Some(mut ret) = fun(v) { + tmp.append(&mut ret); + } + + match v { + Value::Array(vec) => { + for v in vec { + _walk(v, tmp, fun); + } + } + Value::Object(map) => { + for (_, v) in map { + _walk(&v, tmp, fun); + } + } + _ => {} + } + } + + for v in vec { + _walk(v, tmp, fun); + } +} + +fn abs_index(n: &isize, len: usize) -> usize { + if n < &0_isize { + (n + len as isize) as usize + } else { + *n as usize + } +} + +#[derive(Debug)] +enum FilterKey { + String(String), + All, +} + +#[derive(Debug)] +pub enum JsonPathError { + EmptyPath, + EmptyValue, + Path(String), + Serde(String), +} + +#[derive(Debug)] +pub struct Selector<'a> { + node: Option, + value: Option<&'a Value>, + tokens: Vec, + terms: Vec>>, + current: Option>, + selectors: Vec>, +} + +impl<'a> Selector<'a> { + pub fn new() -> Self { + Selector { + node: None, + value: None, + tokens: Vec::new(), + terms: Vec::new(), + current: None, + selectors: Vec::new(), + } + } + + pub fn path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { + debug!("path : {}", path); + let mut parser = Parser::new(path); + self.node = Some(parser.compile().map_err(|e| JsonPathError::Path(e))?); + Ok(self) + } + + pub(crate) fn reset_value(&mut self) -> &mut Self { + self.current = None; + self + } + + pub fn compiled_path(&mut self, node: Node) -> &mut Self { + self.node = Some(node); + self + } + + pub fn value(&mut self, v: &'a Value) -> &mut Self { + self.value = Some(v); + self + } + + fn _select(&mut self) -> Result<(), JsonPathError> { + match self.node.take() { + Some(node) => { + self.visit(&node); + self.node = Some(node); + Ok(()) + } + _ => Err(JsonPathError::EmptyPath) + } + } + + pub fn select_as(&mut self) -> Result, JsonPathError> { + self._select()?; + + match &self.current { + Some(vec) => { + let mut ret = Vec::new(); + for v in vec { + match T::deserialize(*v) { + Ok(v) => ret.push(v), + Err(e) => return Err(JsonPathError::Serde(e.to_string())) + } + } + Ok(ret) + } + _ => Err(JsonPathError::EmptyValue) + } + } + + pub fn select_as_str(&mut self) -> Result { + self._select()?; + + match &self.current { + Some(r) => { + Ok(serde_json::to_string(r) + .map_err(|e| JsonPathError::Serde(e.to_string()))?) + } + _ => Err(JsonPathError::EmptyValue) + } + } + + pub fn select(&mut self) -> Result, JsonPathError> { + self._select()?; + + match &self.current { + Some(r) => Ok(r.to_vec()), + _ => Err(JsonPathError::EmptyValue) + } + } + + fn new_filter_context(&mut self) { + self.terms.push(None); + debug!("new_filter_context: {:?}", self.terms); + } + + fn in_filter, &mut Vec<&'a Value>) -> FilterKey>(&mut self, fun: F) { + match self.terms.pop() { + Some(peek) => { + match peek { + Some(v) => { + debug!("in_filter 1.: {:?}", v); + + match v { + ExprTerm::Json(_, vec) => { + let mut tmp = Vec::new(); + let filter_key = fun(&vec, &mut tmp); + self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); + } + _ => unreachable!() + }; + } + _ => { + debug!("in_filter 2.: {:?}", &self.current); + + if let Some(current) = &self.current { + let mut tmp = Vec::new(); + let filter_key = fun(current, &mut tmp); + self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); + } + } + }; + } + _ => {} + } + } + + fn all_in_filter_with_str(&mut self, key: &str) { + self.in_filter(|vec, tmp| { + walk_all_with_str(&vec, tmp, key, true); + FilterKey::All + }); + + debug!("all_in_filter_with_str : {}, {:?}", key, self.terms); + } + + fn next_in_filter_with_str(&mut self, key: &str) { + fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, key: &str, visited: &mut HashSet<*const Value>) { + match v { + Value::Object(map) => if map.contains_key(key) { + let ptr = v as *const Value; + if !visited.contains(&ptr) { + visited.insert(ptr); + tmp.push(v) + } + }, + Value::Array(vec) => for v in vec { + _collect(v, tmp, key, visited); + } + _ => {} + } + } + + self.in_filter(|vec, tmp| { + let mut visited = HashSet::new(); + for v in vec { + _collect(v, tmp, key, &mut visited); + } + FilterKey::String(key.to_owned()) + }); + + debug!("next_in_filter_with_str : {}, {:?}", key, self.terms); + } + + fn next_from_current_with_num(&mut self, index: f64) { + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + for c in current { + if let Value::Array(vec) = c { + let index = abs_index(&(index as isize), vec.len()); + if let Some(v) = c.get(index) { + tmp.push(v); + } + } + } + self.current = Some(tmp); + } + + debug!("next_from_current_with_num : {:?}, {:?}", &index, self.current); + } + + fn next_from_current_with_str(&mut self, key: &str) { + fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, key: &str, visited: &mut HashSet<*const Value>) { + match v { + Value::Object(map) => { + if let Some(v) = map.get(key) { + let ptr = v as *const Value; + if !visited.contains(&ptr) { + visited.insert(ptr); + tmp.push(v) + } + } + } + Value::Array(vec) => for v in vec { + _collect(v, tmp, key, visited); + } + _ => {} + } + } + + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + let mut visited = HashSet::new(); + for c in current { + _collect(c, &mut tmp, key, &mut visited); + } + self.current = Some(tmp); + } + + debug!("next_from_current_with_str : {}, {:?}", key, self.current); + } + + fn next_all_from_current(&mut self) { + fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>) { + match v { + Value::Object(map) => { + for (_, v) in map { + tmp.push(v) + } + } + Value::Array(vec) => for v in vec { + _collect(v, tmp); + } + _ => {} + } + } + + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + for c in current { + _collect(c, &mut tmp); + } + self.current = Some(tmp); + } + + debug!("next_all_from_current : {:?}", self.current); + } + + fn all_from_current(&mut self) { + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + walk_all(¤t, &mut tmp); + self.current = Some(tmp); + } + debug!("all_from_current: {:?}", self.current); + } + + fn all_from_current_with_str(&mut self, key: &str) { + if let Some(current) = self.current.take() { + let mut tmp = Vec::new(); + walk_all_with_str(¤t, &mut tmp, key, false); + self.current = Some(tmp); + } + debug!("all_from_current_with_str: {}, {:?}", key, self.current); + } +} + +impl<'a> NodeVisitor for Selector<'a> { + fn visit_token(&mut self, token: &ParseToken) { + debug!("token: {:?}, stack: {:?}", token, self.tokens); + + if !self.selectors.is_empty() { + match token { + ParseToken::Absolute | ParseToken::Relative | ParseToken::Filter(_) => { + let s = self.selectors.pop().unwrap(); + + if let Some(current) = &s.current { + let term = if current.len() == 1 { + match current[0] { + Value::Number(v) => ExprTerm::Number(v.clone()), + Value::String(v) => ExprTerm::String(v.clone()), + Value::Bool(v) => ExprTerm::Bool(*v), + _ => ExprTerm::Json(None, current.to_vec()) + } + } else { + ExprTerm::Json(None, current.to_vec()) + }; + + if let Some(s) = self.selectors.last_mut() { + s.terms.push(Some(term)); + } else { + self.terms.push(Some(term)); + } + } else { + unreachable!() + } + } + _ => {} + } + } + + if let Some(s) = self.selectors.last_mut() { + s.visit_token(token); + return; + } + + match token { + ParseToken::Absolute => { + if self.current.is_some() { + let mut s = Selector::new(); + if let Some(value) = self.value { + s.value = Some(value); + s.current = Some(vec![value]); + self.selectors.push(s); + } + return; + } + + match &self.value { + Some(v) => self.current = Some(vec![v]), + _ => {} + } + } + ParseToken::Relative => { + self.new_filter_context(); + } + ParseToken::In | ParseToken::Leaves => { + self.tokens.push(token.clone()); + } + ParseToken::Array => { + if let Some(ParseToken::Leaves) = self.tokens.last() { + self.tokens.pop(); + self.all_from_current(); + } + + self.tokens.push(token.clone()); + } + ParseToken::ArrayEof => { + if let Some(Some(e)) = self.terms.pop() { + match e { + ExprTerm::Number(n) => { + self.next_from_current_with_num(to_f64(&n)); + } + ExprTerm::String(key) => { + self.next_from_current_with_str(&key); + } + ExprTerm::Json(_, v) => { + if v.is_empty() { + self.current = Some(vec![&Value::Null]); + } else { + self.current = Some(v); + } + } + ExprTerm::Bool(false) => { + self.current = Some(vec![&Value::Null]); + } + _ => {} + } + } + + self.tokens.pop(); + } + ParseToken::All => { + match self.tokens.last() { + Some(ParseToken::Leaves) => { + self.tokens.pop(); + self.all_from_current(); + } + Some(ParseToken::In) => { + self.tokens.pop(); + self.next_all_from_current(); + } + _ => {} + } + } + ParseToken::Bool(b) => { + self.terms.push(Some(ExprTerm::Bool(*b))); + } + ParseToken::Key(key) => { + if let Some(ParseToken::Array) = self.tokens.last() { + self.terms.push(Some(ExprTerm::String(key.clone()))); + return; + } + + match self.tokens.pop() { + Some(t) => { + if self.terms.is_empty() { + match t { + ParseToken::Leaves => { + self.all_from_current_with_str(key.as_str()) + } + ParseToken::In => { + self.next_from_current_with_str(key.as_str()) + } + _ => {} + } + } else { + match t { + ParseToken::Leaves => { + self.all_in_filter_with_str(key.as_str()); + } + ParseToken::In => { + self.next_in_filter_with_str(key.as_str()); + } + _ => {} + } + } + } + _ => {} + } + } + ParseToken::Number(v) => { + self.terms.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); + } + ParseToken::Filter(ref ft) => { + if let Some(Some(ref right)) = self.terms.pop() { + if let Some(Some(left)) = self.terms.pop() { + let mut ret = None; + match ft { + FilterToken::Equal => left.eq(right, &mut ret), + FilterToken::NotEqual => left.ne(right, &mut ret), + FilterToken::Greater => left.gt(right, &mut ret), + FilterToken::GreaterOrEqual => left.ge(right, &mut ret), + FilterToken::Little => left.lt(right, &mut ret), + FilterToken::LittleOrEqual => left.le(right, &mut ret), + FilterToken::And => left.and(right, &mut ret), + FilterToken::Or => left.or(right, &mut ret), + }; + + if let Some(e) = ret { + self.terms.push(Some(e)); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + ParseToken::Range(from, to) => { + if !self.terms.is_empty() { + unimplemented!("range syntax in filter"); + } + + if let Some(ParseToken::Array) = self.tokens.pop() { + let mut tmp = Vec::new(); + for vec in &self.current { + for v in vec { + if let Value::Array(vec) = v { + let from = if let Some(from) = from { + abs_index(from, vec.len()) + } else { + 0 + }; + + let to = if let Some(to) = to { + abs_index(to, vec.len()) + } else { + vec.len() + }; + + for i in from..to { + if let Some(v) = vec.get(i) { + tmp.push(v); + } + } + } + } + } + + self.current = Some(tmp); + } else { + unreachable!(); + } + } + ParseToken::Union(indices) => { + if !self.terms.is_empty() { + unimplemented!("union syntax in filter"); + } + + if let Some(ParseToken::Array) = self.tokens.pop() { + let mut tmp = Vec::new(); + for vec in &self.current { + for v in vec { + if let Value::Array(vec) = v { + for i in indices { + if let Some(v) = vec.get(abs_index(i, vec.len())) { + tmp.push(v); + } + } + } + } + } + + self.current = Some(tmp); + } else { + unreachable!(); + } + } + ParseToken::Eof => { + debug!("visit_token eof"); + } + } + } +} + + +//pub trait Transform<'a> { +// fn map(&mut self, mut fun: F) -> &mut Self where F: FnMut(&'a mut Value); +//} +// +//impl<'a> Transform<'a> for Selector<'a> { +// fn map(&mut self, mut fun: F) -> &mut Self where F: FnMut(&'a mut Value) { +// match &mut self.current { +// Some(current) => { +// current.iter_mut().for_each(|ref mut v| fun(v)) +// } +// _ => {} +// } +// +// self +// } +//} \ No newline at end of file diff --git a/src/select/modifiable.rs b/src/select/modifiable.rs deleted file mode 100644 index 3fca8f2..0000000 --- a/src/select/modifiable.rs +++ /dev/null @@ -1,60 +0,0 @@ -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, 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, -} - -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) - } -} \ No newline at end of file diff --git a/src/select/selector.rs b/src/select/selector.rs deleted file mode 100644 index fe759ab..0000000 --- a/src/select/selector.rs +++ /dev/null @@ -1,257 +0,0 @@ -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::*; - -/// 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, -/// 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 { -/// 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::>().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::>().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::(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(), -/// selector.get().unwrap()); -/// -/// selector.value_from_str(input_str()).unwrap() -/// .map_as(|mut v: Vec| { -/// 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::>().unwrap()); -/// ``` -#[derive(Debug)] -pub struct Selector { - pub(crate) node: Option, - pub(crate) value: Option, -} - -impl Selector { - pub fn new() -> Self { - Selector { node: None, value: None } - } - - 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 { - match &self.value { - Some(v) => Ok(JsonValueFilter::new(v.clone())), - _ => return Err(SelectorErrorMessage::EmptyValue.to_string()) - } - } - - fn select(&self) -> result::Result { - 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 { - 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 { - self.select_as_value() - } - - #[deprecated(since = "0.1.13", note = "Please use the select_as function instead")] - pub fn select_to(&self) -> result::Result { - self.select_as() - } - - pub fn select_as_str(&self) -> result::Result { - serde_json::to_string(self.select()?.deref()).map_err(|e| e.to_string()) - } - - pub fn select_as_value(&self) -> result::Result { - Ok((&self.select()?).into()) - } - - pub fn select_as(&self) -> result::Result { - T::deserialize(self.select()?.deref()).map_err(|e| e.to_string()) - } - - pub fn map(&mut self, func: F) -> result::Result<&mut Self, String> - where F: FnOnce(Value) -> Option - { - match func((&self.select()?).into()).map(|ref v| v.into()) { - Some(value) => { - self.set_value(value) - } - _ => {} - } - Ok(self) - } - - pub fn map_as(&mut self, func: F) -> result::Result<&mut Self, String> - where F: FnOnce(D) -> Option, - 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 { - match &self.value { - Some(value) => Ok(value.into()), - _ => Err(SelectorErrorMessage::EmptyValue.to_string()) - } - } - - pub fn get_as(&self) -> result::Result { - 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"), - } - } -} diff --git a/tests/common.rs b/tests/common.rs new file mode 100644 index 0000000..98a04fe --- /dev/null +++ b/tests/common.rs @@ -0,0 +1,44 @@ +extern crate env_logger; +extern crate jsonpath_lib as jsonpath; +extern crate serde_json; + +use std::io::Read; + +use serde_json::Value; + +use self::jsonpath::Selector; + +pub fn setup() { + let _ = env_logger::try_init(); +} + +#[allow(dead_code)] +pub fn read_json(path: &str) -> Value { + let mut f = std::fs::File::open(path).unwrap(); + let mut contents = String::new(); + f.read_to_string(&mut contents).unwrap(); + serde_json::from_str(&contents).unwrap() +} + +#[allow(dead_code)] +pub fn read_contents(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 +} + +#[allow(dead_code)] +pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) { + let mut s = Selector::new(); + let _ = s.path(path); + let _ = s.value(&json); + let result = serde_json::to_value(s.select().unwrap()).unwrap(); + assert_eq!(result, target, "{}", path); +} + +#[allow(dead_code)] +pub fn compare_result<'a>(result: Vec<&Value>, target: Value) { + let result = serde_json::to_value(result).unwrap(); + assert_eq!(result, target); +} diff --git a/tests/filter.rs b/tests/filter.rs index 99cee5e..101ec8e 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -1,223 +1,140 @@ -extern crate core; -extern crate env_logger; -extern crate jsonpath_lib as jsonpath; #[macro_use] extern crate serde_json; -use std::io::Read; - use serde_json::Value; -use jsonpath::Selector; -use jsonpath::filter::value_filter::ValueFilter; +use common::{read_json, select_and_then_compare, setup}; -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 selector(path: &str, file: &str) -> Selector { - let string = read_json(file); - let mut s = Selector::new(); - let _ = s.path(path); - let _ = s.value_from_str(&string); - s -} - -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 -} - -#[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()); - } -} +mod common; #[test] fn array() { setup(); - let friends = json!([ - {"id": 1, "name": "Vincent Cannon" }, - {"id": 2, "name": "Gray Berry"} - ]); + select_and_then_compare("$.school.friends[1, 2]", read_json("./benches/data_obj.json"), json!([ + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ])); - let s = selector("$.school.friends[1, 2]", "./benches/data_obj.json"); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$.school.friends[1: ]", read_json("./benches/data_obj.json"), json!([ + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ])); - let s = selector("$.school.friends[1:]", "./benches/data_obj.json"); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$.school.friends[:-2]", read_json("./benches/data_obj.json"), json!([ + {"id": 0, "name": "Millicent Norman"} + ])); - let s = selector("$.school.friends[:-2]", "./benches/data_obj.json"); - let friends = json!([ - {"id": 0, "name": "Millicent Norman"} - ]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$..friends[2].name", read_json("./benches/data_obj.json"), json!([ + "Gray Berry", "Gray Berry" + ])); - let s = selector("$..friends[2].name", "./benches/data_obj.json"); - let friends = json!(["Gray Berry", "Gray Berry"]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$..friends[*].name", read_json("./benches/data_obj.json"), json!([ + "Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry" + ])); - 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, s.select_as_value().unwrap()); + select_and_then_compare("$['school']['friends'][*].['name']", read_json("./benches/data_obj.json"), json!([ + "Millicent Norman","Vincent Cannon","Gray Berry" + ])); - let s = selector("$['school']['friends'][*].['name']", "./benches/data_obj.json"); - let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]); - assert_eq!(friends, s.select_as_value().unwrap()); - - let s = selector("$['school']['friends'][0].['name']", "./benches/data_obj.json"); - let friends = json!("Millicent Norman"); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$['school']['friends'][0].['name']", read_json("./benches/data_obj.json"), json!([ + "Millicent Norman" + ])); } #[test] fn return_type() { setup(); - let friends = json!({ - "friends": [ - {"id": 0, "name": "Millicent Norman"}, - {"id": 1, "name": "Vincent Cannon" }, - {"id": 2, "name": "Gray Berry"} - ] - }); - - let s = selector("$.school", "./benches/data_obj.json"); - assert_eq!(friends, s.select_as_value().unwrap()); - - let s = selector("$.school[?(@.friends[0])]", "./benches/data_obj.json"); - assert_eq!(friends, s.select_as_value().unwrap()); - - let s = selector("$.school[?(@.friends[10])]", "./benches/data_obj.json"); - assert_eq!(Value::Null, s.select_as_value().unwrap()); - - let s = selector("$.school[?(1==1)]", "./benches/data_obj.json"); - assert_eq!(friends, s.select_as_value().unwrap()); - - let s = selector("$.school.friends[?(1==1)]", "./benches/data_obj.json"); - let friends = json!([ + select_and_then_compare("$.school", read_json("./benches/data_obj.json"), json!([{ + "friends": [ {"id": 0, "name": "Millicent Norman"}, {"id": 1, "name": "Vincent Cannon" }, {"id": 2, "name": "Gray Berry"} - ]); - assert_eq!(friends, s.select_as_value().unwrap()); + ] + }])); + + select_and_then_compare("$.school[?(@.friends[0])]", read_json("./benches/data_obj.json"), json!([{ + "friends": [ + {"id": 0, "name": "Millicent Norman"}, + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ] + }])); + + select_and_then_compare("$.school[?(@.friends[10])]", read_json("./benches/data_obj.json"), json!([{ + "friends": [ + {"id": 0, "name": "Millicent Norman"}, + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ] + }])); + + select_and_then_compare("$.school[?(1==1)]", read_json("./benches/data_obj.json"), json!([{ + "friends": [ + {"id": 0, "name": "Millicent Norman"}, + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ] + }])); + + select_and_then_compare("$.school.friends[?(1==1)]", read_json("./benches/data_obj.json"), json!([[ + {"id": 0, "name": "Millicent Norman"}, + {"id": 1, "name": "Vincent Cannon" }, + {"id": 2, "name": "Gray Berry"} + ]])); } #[test] fn op_default() { setup(); - let s = selector("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json"); - let friends = json!({ + select_and_then_compare("$.school[?(@.friends == @.friends)]", read_json("./benches/data_obj.json"), json!([{ "friends": [ {"id": 0, "name": "Millicent Norman"}, {"id": 1, "name": "Vincent Cannon" }, {"id": 2, "name": "Gray Berry"} ] - }); - assert_eq!(friends, s.select_as_value().unwrap()); + }])); - 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, s.select_as_value().unwrap()); + select_and_then_compare("$.friends[?(@.name)]", read_json("./benches/data_obj.json"), json!([ + { "id" : 1, "name" : "Vincent Cannon" }, + { "id" : 2, "name" : "Gray Berry" } + ])); - let s = selector("$.friends[?(@.id >= 2)]", "./benches/data_obj.json"); - let friends = json!([ - { "id" : 2, "name" : "Gray Berry" } - ]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$.friends[?(@.id >= 2)]", read_json("./benches/data_obj.json"), json!([ + { "id" : 2, "name" : "Gray Berry" } + ])); - 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, s.select_as_value().unwrap()); + select_and_then_compare("$.friends[?(@.id >= 2 || @.id == 1)]", read_json("./benches/data_obj.json"), json!([ + { "id" : 2, "name" : "Gray Berry" }, + { "id" : 1, "name" : "Vincent Cannon" } + ])); - let s = selector("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json"); - assert_eq!(Value::Null, s.select_as_value().unwrap()); + select_and_then_compare("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", read_json("./benches/data_obj.json"), json!([ + Value::Null + ])); - let s = selector("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json"); - let friends = json!([0, 0]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$..friends[?(@.id == $.index)].id", read_json("./benches/data_obj.json"), json!([ + 0, 0 + ])); - let s = selector("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json"); - let friends = json!([22.99]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$..book[?($.store.bicycle.price < @.price)].price", read_json("./benches/example.json"), json!([ + 22.99 + ])); - let s = selector("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json"); - let friends = json!([12.99]); - assert_eq!(friends, s.select_as_value().unwrap()); + select_and_then_compare("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", read_json("./benches/example.json"), json!([ + 12.99 + ])); - let ref value = json!([ + select_and_then_compare("$..[?(@.age > 40)]", json!([ { "name": "이름1", "age": 40, "phone": "+33 12341234" }, { "name": "이름2", "age": 42, "phone": "++44 12341234" } - ]); - - 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, s.select_as_value().unwrap()); + ]), json!([ + { "name" : "이름2", "age" : 42, "phone" : "++44 12341234" } + ])); - let ref value = json!({ + select_and_then_compare("$..[?(@.age >= 30)]", json!({ "school": { "friends": [ {"name": "친구1", "age": 20}, @@ -227,246 +144,208 @@ fn op_default() { "friends": [ {"name": "친구3", "age": 30}, {"name": "친구4"} - ]}); - let mut s = Selector::new(); - let _ = s.path("$..[?(@.age >= 30)]"); - let _ = s.value(value); - let friends = json!([{ "name" : "친구3", "age" : 30 }]); - assert_eq!(friends, s.select_as_value().unwrap()); + ]}), json!([ + { "name" : "친구3", "age" : 30 } + ])); } #[test] fn op_number() { setup(); - let json = json!({ "a": 1 }); - let ret = jsonpath::select(&json, "$.[?(@.a == 1)]").unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, "$.[?(@.a != 2)]").unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, "$.[?(@.a < 2)]").unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, "$.[?(@.a <= 1)]").unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, "$.[?(@.a > 0)]").unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, "$.[?(@.a >= 0)]").unwrap(); - assert_eq!(json, ret); + select_and_then_compare("$.[?(@.a == 1)]", json!({ "a": 1 }), json!([{ "a": 1 }])); + select_and_then_compare("$.[?(@.a != 2)]", json!({ "a": 1 }), json!([{ "a": 1 }])); + select_and_then_compare("$.[?(@.a < 2)]", json!({ "a": 1 }), json!([{ "a": 1 }])); + select_and_then_compare("$.[?(@.a <= 1)]", json!({ "a": 1 }), json!([{ "a": 1 }])); + select_and_then_compare("$.[?(@.a > 0)]", json!({ "a": 1 }), json!([{ "a": 1 }])); + select_and_then_compare("$.[?(@.a >= 0)]", json!({ "a": 1 }), json!([{ "a": 1 }])); } #[test] fn op_string() { setup(); - let json = json!({ "a": "b" }); - let ret = jsonpath::select(&json, r#"$.[?(@.a == "b")]"#).unwrap(); - assert_eq!(json!({ "a": "b" }), ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a != "c")]"#).unwrap(); - assert_eq!(json!({ "a": "b" }), ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a < "b")]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a <= "b")]"#).unwrap(); - assert_eq!(json!({ "a": "b" }), ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a > "b")]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a >= "b")]"#).unwrap(); - assert_eq!(json!({ "a": "b" }), ret); + select_and_then_compare(r#"$.[?(@.a == "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }])); + select_and_then_compare(r#"$.[?(@.a != "c")]"#, json!({ "a": "b" }), json!([{ "a": "b" }])); + select_and_then_compare(r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a <= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }])); + select_and_then_compare(r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a >= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }])); } #[test] fn op_object() { setup(); - let json = json!({ - "a": { "1": 1 }, - "b": { "2": 2 }, - "c": { "1": 1 }, - }); - let ret = jsonpath::select(&json, r#"$.[?(@.a == @.c)]"#).unwrap(); - assert_eq!(json, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a != @.c)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a < @.c)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a <= @.c)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a > @.c)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a >= @.c)]"#).unwrap(); - assert_eq!(Value::Null, ret); + select_and_then_compare(r#"$.[?(@.a == @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([{"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}])); + select_and_then_compare(r#"$.[?(@.a != @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a < @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a <= @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a > @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a >= @.c)]"#, + json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}), + json!([Value::Null])); } #[test] fn op_complex() { setup(); - let json = json!({ "a": { "b": 1 } }); - let ret = jsonpath::select(&json, r#"$.[?(1 == @.a)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?("1" != @.a)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a <= 1)]"#).unwrap(); - assert_eq!(Value::Null, ret); - let ret = jsonpath::select(&json, r#"$.[?(@.a > "1")]"#).unwrap(); - assert_eq!(Value::Null, ret); + select_and_then_compare(r#"$.[?(1 == @.a)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null])); + select_and_then_compare(r#"$.[?("1" != @.a)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a <= 1)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null])); + select_and_then_compare(r#"$.[?(@.a > "1")]"#, json!({ "a": { "b": 1 } }), json!([Value::Null])); } #[test] fn example() { setup(); - 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, s.select_as_value().unwrap()); + select_and_then_compare(r#"$.store.book[*].author"#, read_json("./benches/example.json"), json!([ + "Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien" + ])); - let s = selector("$..author", "./benches/example.json"); - assert_eq!(ret, s.select_as_value().unwrap()); + select_and_then_compare(r#"$..author"#, read_json("./benches/example.json"), json!([ + "Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien" + ])); - let s = selector("$.store.*", "./benches/example.json"); - let ret = json!([ - [ + select_and_then_compare(r#"$.store.*"#, read_json("./benches/example.json"), json!([ + [ {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95}, {"category" : "fiction", "author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}, {"category" : "fiction", "author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, {"category" : "fiction", "author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} ], {"color" : "red","price" : 19.95}, - ]); - assert_eq!(ret, s.select_as_value().unwrap()); + ])); - let s = selector("$.store..price", "./benches/example.json"); - let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); - assert_eq!(ret, s.select_as_value().unwrap()); + select_and_then_compare(r#"$.store..price"#, read_json("./benches/example.json"), json!([ + 8.95, 12.99, 8.99, 22.99, 19.95 + ])); - let s = selector("$..book[2]", "./benches/example.json"); - let ret = json!([{ + select_and_then_compare(r#"$..book[2]"#, read_json("./benches/example.json"), json!([ + { + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + } + ])); + + select_and_then_compare(r#"$..book[-2]"#, read_json("./benches/example.json"), json!([ + { "category" : "fiction", "author" : "Herman Melville", "title" : "Moby Dick", "isbn" : "0-553-21311-3", "price" : 8.99 - }]); - assert_eq!(ret, s.select_as_value().unwrap()); + } + ])); - let s = selector("$..book[-2]", "./benches/example.json"); - let ret = json!([{ + select_and_then_compare(r#"$..book[0, 1]"#, read_json("./benches/example.json"), json!([ + { + "category" : "reference", + "author" : "Nigel Rees", + "title" : "Sayings of the Century", + "price" : 8.95 + }, + { + "category" : "fiction", + "author" : "Evelyn Waugh", + "title" : "Sword of Honour", + "price" : 12.99 + } + ])); + + select_and_then_compare(r#"$..book[:2]"#, read_json("./benches/example.json"), json!([ + { + "category" : "reference", + "author" : "Nigel Rees", + "title" : "Sayings of the Century", + "price" : 8.95 + }, + { + "category" : "fiction", + "author" : "Evelyn Waugh", + "title" : "Sword of Honour", + "price" : 12.99 + } + ])); + + select_and_then_compare(r#"$..book[2:]"#, read_json("./benches/example.json"), json!([ + { "category" : "fiction", "author" : "Herman Melville", "title" : "Moby Dick", "isbn" : "0-553-21311-3", "price" : 8.99 - }]); - assert_eq!(ret, s.select_as_value().unwrap()); + }, + { + "category" : "fiction", + "author" : "J. R. R. Tolkien", + "title" : "The Lord of the Rings", + "isbn" : "0-395-19395-8", + "price" : 22.99 + } + ])); - let s = selector("$..book[0,1]", "./benches/example.json"); - let ret = json!([ - { - "category" : "reference", - "author" : "Nigel Rees", - "title" : "Sayings of the Century", - "price" : 8.95 - }, - { - "category" : "fiction", - "author" : "Evelyn Waugh", - "title" : "Sword of Honour", - "price" : 12.99 - } - ]); - assert_eq!(ret, s.select_as_value().unwrap()); + select_and_then_compare(r#"$..book[?(@.isbn)]"#, read_json("./benches/example.json"), json!([ + { + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + }, + { + "category" : "fiction", + "author" : "J. R. R. Tolkien", + "title" : "The Lord of the Rings", + "isbn" : "0-395-19395-8", + "price" : 22.99 + } + ])); - let s = selector("$..book[:2]", "./benches/example.json"); - let ret = json!([ - { - "category" : "reference", - "author" : "Nigel Rees", - "title" : "Sayings of the Century", - "price" : 8.95 - }, - { - "category" : "fiction", - "author" : "Evelyn Waugh", - "title" : "Sword of Honour", - "price" : 12.99 - } - ]); - assert_eq!(ret, s.select_as_value().unwrap()); + select_and_then_compare(r#"$.store.book[?(@.price < 10)]"#, read_json("./benches/example.json"), json!([ + { + "category" : "reference", + "author" : "Nigel Rees", + "title" : "Sayings of the Century", + "price" : 8.95 + }, + { + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + } + ])); - let s = selector("$..book[2:]", "./benches/example.json"); - let ret = json!([ - { - "category" : "fiction", - "author" : "Herman Melville", - "title" : "Moby Dick", - "isbn" : "0-553-21311-3", - "price" : 8.99 - }, - { - "category" : "fiction", - "author" : "J. R. R. Tolkien", - "title" : "The Lord of the Rings", - "isbn" : "0-395-19395-8", - "price" : 22.99 - } - ]); - assert_eq!(ret, s.select_as_value().unwrap()); - - let s = selector("$..book[?(@.isbn)]", "./benches/example.json"); - let ret = json!([ - { - "category" : "fiction", - "author" : "Herman Melville", - "title" : "Moby Dick", - "isbn" : "0-553-21311-3", - "price" : 8.99 - }, - { - "category" : "fiction", - "author" : "J. R. R. Tolkien", - "title" : "The Lord of the Rings", - "isbn" : "0-395-19395-8", - "price" : 22.99 - } - ]); - assert_eq!(ret, s.select_as_value().unwrap()); - - let s = selector("$.store.book[?(@.price < 10)]", "./benches/example.json"); - let ret = json!([ - { - "category" : "reference", - "author" : "Nigel Rees", - "title" : "Sayings of the Century", - "price" : 8.95 - }, - { - "category" : "fiction", - "author" : "Herman Melville", - "title" : "Moby Dick", - "isbn" : "0-553-21311-3", - "price" : 8.99 - } - ]); - assert_eq!(ret, s.select_as_value().unwrap()); - - 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, s.select_as_value().unwrap()); + select_and_then_compare(r#"$..*"#, read_json("./benches/example.json"), + read_json("./benches/giveme_every_thing_result.json")); } #[test] fn filer_same_obj() { setup(); - let mut s = Selector::new(); - let _ = s.path("$..[?(@.a == 1)]"); - let _ = s.value_from_str(r#" - { + select_and_then_compare(r#"$..[?(@.a == 1)]"#, json!({ "a": 1, "b" : {"a": 1}, "c" : {"a": 1} - } - "#); - assert_eq!(s.select_as_value().unwrap(), json!([ + }), json!([ {"a": 1}, {"a": 1} ])); diff --git a/tests/lib.rs b/tests/lib.rs index 6fa8fb0..3ac8f24 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,31 +1,19 @@ -extern crate env_logger; extern crate jsonpath_lib as jsonpath; -extern crate log; extern crate serde; #[macro_use] extern crate serde_json; -use std::io::Read; - -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use serde_json::Value; -fn read_json(path: &str) -> Value { - let mut f = std::fs::File::open(path).unwrap(); - let mut contents = String::new(); - f.read_to_string(&mut contents).unwrap(); - serde_json::from_str(contents.as_str()).unwrap() -} +use common::{compare_result, read_contents, read_json, setup}; -fn read_contents(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 -} +mod common; #[test] fn compile() { + setup(); + let mut template = jsonpath::compile("$..friends[2]"); let json_obj = read_json("./benches/data_obj.json"); let json = template(&json_obj).unwrap(); @@ -33,7 +21,7 @@ fn compile() { {"id": 2,"name": "Gray Berry"}, {"id": 2,"name": "Gray Berry"} ]); - assert_eq!(json, ret); + compare_result(json, ret); let json_obj = read_json("./benches/data_array.json"); let json = template(&json_obj).unwrap(); @@ -41,11 +29,13 @@ fn compile() { {"id": 2,"name": "Gray Berry"}, {"id": 2,"name": "Rosetta Erickson"} ]); - assert_eq!(json, ret); + compare_result(json, ret); } #[test] fn selector() { + setup(); + let json_obj = read_json("./benches/data_obj.json"); let mut reader = jsonpath::selector(&json_obj); let json = reader("$..friends[2]").unwrap(); @@ -53,27 +43,26 @@ fn selector() { {"id": 2,"name": "Gray Berry"}, {"id": 2,"name": "Gray Berry"} ]); - assert_eq!(json, ret); + compare_result(json, ret); let json = reader("$..friends[0]").unwrap(); let ret = json!([ {"id": 0}, {"id": 0,"name": "Millicent Norman"} ]); - assert_eq!(json, ret); + compare_result(json, ret); } #[test] fn selector_as() { - let json_obj = read_json("./benches/data_obj.json"); - let mut selector = jsonpath::selector_as::>(&json_obj); - - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Deserialize, PartialEq, Debug)] struct Friend { id: u8, name: Option, } + let json_obj = read_json("./benches/data_obj.json"); + let mut selector = jsonpath::selector_as::(&json_obj); let json = selector("$..friends[2]").unwrap(); let ret = vec!( @@ -101,7 +90,7 @@ fn select() { "isbn" : "0-553-21311-3", "price" : 8.99 }]); - assert_eq!(json, ret); + compare_result(json, ret); } #[test] @@ -121,14 +110,14 @@ fn select_str() { #[test] fn test_to_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Deserialize, PartialEq, Debug)] struct Person { name: String, age: u8, phones: Vec, } - let ret: Person = jsonpath::select_as(r#" + let ret: Vec = jsonpath::select_as(r#" { "person": { @@ -148,5 +137,5 @@ fn test_to_struct() { phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()], }; - assert_eq!(person, ret); + assert_eq!(vec![person], ret); } \ No newline at end of file diff --git a/tests/modifiable.rs b/tests/modifiable.rs deleted file mode 100644 index 85ac548..0000000 --- a/tests/modifiable.rs +++ /dev/null @@ -1,31 +0,0 @@ -//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 -//} diff --git a/tests/parser.rs b/tests/parser.rs deleted file mode 100644 index b0973fb..0000000 --- a/tests/parser.rs +++ /dev/null @@ -1,312 +0,0 @@ -extern crate env_logger; -extern crate jsonpath_lib as jsonpath; - -use std::result; -use jsonpath::parser::parser::{Parser, ParseToken, NodeVisitor, FilterToken}; - -struct NodeVisitorTestImpl<'a> { - input: &'a str, - stack: Vec, -} - -impl<'a> NodeVisitorTestImpl<'a> { - fn new(input: &'a str) -> Self { - NodeVisitorTestImpl { input, stack: Vec::new() } - } - - fn visit(&mut self) -> result::Result, String> { - let mut parser = Parser::new(self.input); - parser.parse(self)?; - Ok(self.stack.split_off(0)) - } -} - -impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> { - fn visit_token(&mut self, token: ParseToken) { - self.stack.push(token); - } -} - -fn setup() { - let _ = env_logger::try_init(); -} - -fn run(input: &str) -> result::Result, String> { - let mut interpreter = NodeVisitorTestImpl::new(input); - interpreter.visit() -} - -#[test] -fn parse_path() { - setup(); - - assert_eq!(run("$.aa"), Ok(vec![ - ParseToken::Absolute, - ParseToken::In, - ParseToken::Key("aa".to_owned()) - ])); - - assert_eq!(run("$.00.a"), Ok(vec![ - ParseToken::Absolute, - ParseToken::In, - ParseToken::Key("00".to_owned()), - ParseToken::In, - ParseToken::Key("a".to_owned()) - ])); - - assert_eq!(run("$.00.韓창.seok"), Ok(vec![ - ParseToken::Absolute, - ParseToken::In, - ParseToken::Key("00".to_owned()), - ParseToken::In, - ParseToken::Key("韓창".to_owned()), - ParseToken::In, - ParseToken::Key("seok".to_owned()) - ])); - - assert_eq!(run("$.*"), Ok(vec![ - ParseToken::Absolute, - ParseToken::In, - ParseToken::All - ])); - - assert_eq!(run("$..*"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Leaves, - ParseToken::All - ])); - - assert_eq!(run("$..[0]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Leaves, - ParseToken::Array, - ParseToken::Number(0.0), - ParseToken::ArrayEof - ])); - - match run("$.") { - Ok(_) => panic!(), - _ => {} - } - - match run("$..") { - Ok(_) => panic!(), - _ => {} - } - - match run("$. a") { - Ok(_) => panic!(), - _ => {} - } -} - -#[test] -fn parse_array_sytax() { - setup(); - - assert_eq!(run("$.book[?(@.isbn)]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::In, - ParseToken::Key("book".to_string()), - ParseToken::Array, - ParseToken::Relative, - ParseToken::In, - ParseToken::Key("isbn".to_string()), - ParseToken::ArrayEof - ])); - - // - // Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만 - // - assert_eq!(run("$.[*]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[*]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[*].가"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof, - ParseToken::In, ParseToken::Key("가".to_owned()) - ])); - - assert_eq!(run("$.a[0][1]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Number(0_f64), - ParseToken::ArrayEof, - ParseToken::Array, - ParseToken::Number(1_f64), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[1,2]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Union(vec![1, 2]), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[10:]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Range(Some(10), None), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[:11]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Range(None, Some(11)), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[-12:13]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Range(Some(-12), Some(13)), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[?(1>2)]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Greater), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$.a[?($.b>3)]"), Ok(vec![ - ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Array, - ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::Greater), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$[?($.c>@.d && 1==2)]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()), - ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()), - ParseToken::Filter(FilterToken::Greater), - ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal), - ParseToken::Filter(FilterToken::And), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$[?($.c>@.d&&(1==2||3>=4))]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()), - ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()), - ParseToken::Filter(FilterToken::Greater), - ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal), - ParseToken::Number(3_f64), ParseToken::Number(4_f64), ParseToken::Filter(FilterToken::GreaterOrEqual), - ParseToken::Filter(FilterToken::Or), - ParseToken::Filter(FilterToken::And), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$[?(@.a<@.b)]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()), - ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned()), - ParseToken::Filter(FilterToken::Little), - ParseToken::ArrayEof - ])); - - assert_eq!(run("$[*][*][*]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof, - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof, - ParseToken::Array, - ParseToken::All, - ParseToken::ArrayEof - ])); - - assert_eq!(run("$['a']['bb']"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::Key("a".to_string()), - ParseToken::ArrayEof, - ParseToken::Array, - ParseToken::Key("bb".to_string()), - ParseToken::ArrayEof - ])); - - match run("$[") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[a]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?($.a)]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?(@.a > @.b]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?(@.a < @.b&&(@.c < @.d)]") { - Ok(_) => panic!(), - _ => {} - } -} - -#[test] -fn parse_array_float() { - setup(); - - assert_eq!(run("$[?(1.1<2.1)]"), Ok(vec![ - ParseToken::Absolute, - ParseToken::Array, - ParseToken::Number(1.1), ParseToken::Number(2.1), ParseToken::Filter(FilterToken::Little), - ParseToken::ArrayEof - ])); - - match run("$[1.1]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?(1.1<.2)]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?(1.1<2.)]") { - Ok(_) => panic!(), - _ => {} - } - - match run("$[?(1.1<2.a)]") { - Ok(_) => panic!(), - _ => {} - } -} \ No newline at end of file diff --git a/tests/readme.rs b/tests/readme.rs index 4243fa5..dc47853 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -3,14 +3,134 @@ extern crate serde; #[macro_use] extern crate serde_json; -use serde::{Deserialize, Serialize}; -use serde_json::Value; +use serde::Deserialize; use jsonpath::Selector; +#[test] +fn readme() { + let json_obj = json!({ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + }, + "expensive": 10 + }); + + let mut selector = jsonpath::selector(&json_obj); + + assert_eq!(selector("$.store.book[*].author").unwrap(), + vec![ + "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" + ]); + + assert_eq!(selector("$..author").unwrap(), + vec![ + "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" + ]); + + assert_eq!(selector("$.store.*").unwrap(), + vec![ + &json!([ + { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, + { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, + { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, + { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } + ]), + &json!({ "color": "red", "price": 19.95 }) + ]); + + assert_eq!(selector("$.store..price").unwrap(), + vec![ + 8.95, 12.99, 8.99, 22.99, 19.95 + ]); + + assert_eq!(selector("$..book[2]").unwrap(), + vec![ + &json!({ + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + }) + ]); + + assert_eq!(selector("$..book[-2]").unwrap(), + vec![ + &json!({ + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + }) + ]); + + assert_eq!(selector("$..book[0,1]").unwrap(), + vec![ + &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), + &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) + ]); + + assert_eq!(selector("$..book[:2]").unwrap(), + vec![ + &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), + &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) + ]); + + assert_eq!(selector("$..book[:2]").unwrap(), + vec![ + &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), + &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}) + ]); + + assert_eq!(selector("$..book[?(@.isbn)]").unwrap(), + vec![ + &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}), + &json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}) + ]); + + assert_eq!(selector("$.store.book[?(@.price < 10)]").unwrap(), + vec![ + &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}), + &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}) + ]); +} + #[test] fn readme_selector() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Deserialize, PartialEq, Debug)] struct Friend { name: String, age: Option, @@ -32,42 +152,16 @@ fn readme_selector() { let result = selector .path("$..[?(@.age >= 30)]").unwrap() -// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap() -// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap() - .value(&json_obj /*serde_json::value::Value*/).unwrap() - .select_as_value().unwrap(); + .value(&json_obj) + .select().unwrap(); - assert_eq!(json!([{"name": "친구3", "age": 30}]), result); + assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result); let result = selector.select_as_str().unwrap(); assert_eq!(r#"[{"name":"친구3","age":30}]"#, result); - let result = selector.select_as::>().unwrap(); + let result = selector.select_as::().unwrap(); assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); - - let _ = selector.map(|v| { - let r = match v { - Value::Array(mut vec) => { - for v in &mut vec { - v.as_object_mut().unwrap().remove("age"); - } - Value::Array(vec) - } - _ => Value::Null - }; - Some(r) - }); - assert_eq!(json!([{ "name": "친구3"}]), selector.get().unwrap()); - - let _ = selector.value(&json_obj).unwrap() - .map_as(|mut v: Vec| { - let mut f = v.pop().unwrap(); - f.name = "friend3".to_string(); - f.age = None; - Some(vec![f]) - }); - assert_eq!(vec![Friend { name: "friend3".to_string(), age: None }], - selector.get_as::>().unwrap()); } #[test] @@ -86,11 +180,10 @@ fn readme_select() { let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap(); - let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); - assert_eq!(json, ret); } #[test] @@ -122,7 +215,7 @@ fn readme_select_as() { phones: Vec, } - let ret: Person = jsonpath::select_as(r#" + let ret: Vec = jsonpath::select_as(r#" { "person": { @@ -142,7 +235,7 @@ fn readme_select_as() { phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()], }; - assert_eq!(person, ret); + assert_eq!(ret[0], person); } #[test] @@ -163,12 +256,10 @@ fn readme_compile() { let json = template(&json_obj).unwrap(); - let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); - - assert_eq!(json, ret); } #[test] @@ -189,21 +280,17 @@ fn readme_selector_fn() { let json = selector("$..friends[0]").unwrap(); - let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); - assert_eq!(json, ret); - let json = selector("$..friends[1]").unwrap(); - let ret = json!([ - {"name": "친구4"}, - {"name": "친구2", "age": 20} + assert_eq!(json, vec![ + &json!({"name": "친구4"}), + &json!({"name": "친구2", "age": 20}) ]); - - assert_eq!(json, ret); } #[test] @@ -220,13 +307,13 @@ fn readme_selector_as() { {"name": "친구4"} ]}); - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Deserialize, PartialEq, Debug)] struct Friend { name: String, age: Option, } - let mut selector = jsonpath::selector_as::>(&json_obj); + let mut selector = jsonpath::selector_as::(&json_obj); let json = selector("$..friends[0]").unwrap(); diff --git a/tests/selector.rs b/tests/selector.rs deleted file mode 100644 index 464761d..0000000 --- a/tests/selector.rs +++ /dev/null @@ -1,209 +0,0 @@ -extern crate jsonpath_lib as jsonpath; -extern crate serde; -#[macro_use] -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: u8, - phone: String, -} - -fn input_str() -> &'static str { - r#"[ - { - "name": "이름1", - "age": 40, - "phone": "+33 12341234" - }, - { - "name": "이름2", - "age": 42, - "phone": "++44 12341234" - }, - { - "name": "이름3", - "age": 50, - "phone": "++55 111111" - }, - { - "name": "이름4", - "age": 51, - "phone": "++55 12341234" - } - ]"# -} - -fn input_json() -> Value { - serde_json::from_str(input_str()).unwrap() -} - -fn input_person() -> Vec { - serde_json::from_str(input_str()).unwrap() -} - -#[test] -fn selector_value_from() { - let result = Selector::new() - .path("$..[?(@.age > 40)]").unwrap() - .value_from(&input_person()).unwrap() - .select_as::>().unwrap(); - assert_eq!(input_person()[1], result[0]); -} - -#[test] -fn selector_value() { - let result = Selector::new() - .path("$..[?(@.age > 40)]").unwrap() - .value((&input_json()).into()).unwrap() - .select_as_value().unwrap(); - assert_eq!(input_json()[1], result[0]); -} - -#[test] -fn selector_value_from_str() { - let result = Selector::new() - .path("$..[?(@.age > 40)]").unwrap() - .value_from_str(input_str()).unwrap() - .select_as_value().unwrap(); - assert_eq!(input_json()[1], result[0]); -} - -#[test] -fn selector_select_to() { - 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(); - let value: Value = serde_json::from_str(&result).unwrap(); - assert_eq!(input_json()[1], value[0]); - - let result = selector.select_as::>().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::>().unwrap(); - assert_eq!(input_person()[0], result[0]); -} - -fn _remove_name(v: Value) -> Option { - let r = match v { - Value::Array(mut vec) => { - for v in &mut vec { - v.as_object_mut().unwrap().remove("name"); - } - Value::Array(vec) - } - _ => Value::Null - }; - Some(r) -} - -fn _change_phone_number(v: Value) -> Option { - let r = match v { - Value::Array(mut vec) => { - let mut v = vec.pop().unwrap(); - v.as_object_mut().unwrap() - .insert("phone".to_string(), Value::String("1234".to_string())); - v - } - _ => Value::Null - }; - Some(r) -} - -fn _rejuvenate(mut vec: Vec) -> Option> { - for p in &mut vec { - p.age = p.age - 10; - } - Some(vec) -} - -#[test] -fn selector_map_basic() { - let mut selector = Selector::new(); - - let result = selector - .path("$..[?(@.age > 40)]").unwrap() - .value_from_str(input_str()).unwrap() - .map(_remove_name).unwrap() - .get().unwrap(); - - assert_eq!(result, json!([ - {"phone": "++44 12341234", "age": 42}, - {"phone": "++55 111111", "age": 50}, - {"phone": "++55 12341234", "age": 51}, - ])); -} - -#[test] -fn selector_map() { - let mut selector = Selector::new(); - - let result = selector - .path("$..[?(@.age > 40)]").unwrap() - .value_from_str(input_str()).unwrap() - .map(_remove_name).unwrap() - .path("$..[?(@.age == 50)]").unwrap() - .map(_change_phone_number).unwrap() - .get().unwrap(); - - assert_eq!(result, json!({ - "phone": "1234", - "age": 50, - })); -} - -#[test] -fn selector_map_as_basic() { - let mut selector = Selector::new(); - - let result = selector - .path("$..[?(@.age > 40)]").unwrap() - .value_from_str(input_str()).unwrap() - .map_as(_rejuvenate).unwrap() - .get().unwrap(); - - assert_eq!(result, json!([ - {"name": "이름2", "phone": "++44 12341234", "age": 32}, - {"name": "이름3", "phone": "++55 111111", "age": 40}, - {"name": "이름4", "phone": "++55 12341234", "age": 41}, - ])); -} - -#[test] -fn selector_map_as() { - let mut selector = Selector::new(); - - let result = selector - .path("$..[?(@.age > 40)]").unwrap() - .value_from_str(input_str()).unwrap() - .map_as(_rejuvenate).unwrap() - .path("$..[?(@.age == 40)]").unwrap() - .map(_change_phone_number).unwrap() - .get().unwrap(); - - assert_eq!(result, json!({ - "name": "이름3", - "phone": "1234", - "age": 40, - })); -} diff --git a/tests/serde.rs b/tests/serde.rs deleted file mode 100644 index 5723ac0..0000000 --- a/tests/serde.rs +++ /dev/null @@ -1,39 +0,0 @@ -extern crate jsonpath_lib as jsonpath; -extern crate serde; -extern crate serde_json; - -use std::io::Read; - -use serde_json::Value; -use jsonpath::ref_value::model::{RefValue, RefValueWrapper}; - -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 -} - -#[test] -fn de() { - let json_str = read_json("./benches/example.json"); - // RefValue -> Value - let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap(); - let ref value_wrapper: RefValueWrapper = ref_value.into(); - let value: Value = value_wrapper.into(); - - // Value - let json: Value = serde_json::from_str(json_str.as_str()).unwrap(); - assert_eq!(value, json); -} - -#[test] -fn ser() { - let json_str = read_json("./benches/example.json"); - let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap(); - let ref_value_str = serde_json::to_string(&ref_value).unwrap(); - - let json: Value = serde_json::from_str(json_str.as_str()).unwrap(); - let json_str = serde_json::to_string(&json).unwrap(); - assert_eq!(ref_value_str, json_str); -} \ No newline at end of file diff --git a/tests/tokenizer.rs b/tests/tokenizer.rs deleted file mode 100644 index dbd14f8..0000000 --- a/tests/tokenizer.rs +++ /dev/null @@ -1,194 +0,0 @@ -extern crate jsonpath_lib as jsonpath; - -use jsonpath::parser::tokenizer::{Tokenizer, Token, TokenError, PreloadedTokenizer}; - -fn collect_token(input: &str) -> (Vec, Option) { - let mut tokenizer = Tokenizer::new(input); - let mut vec = vec![]; - loop { - match tokenizer.next_token() { - Ok(t) => vec.push(t), - Err(e) => return (vec, Some(e)), - } - } -} - -fn run(input: &str, expected: (Vec, Option)) { - let (vec, err) = collect_token(input.clone()); - assert_eq!((vec, err), expected, "\"{}\"", input); -} - -#[test] -fn peek() { - let mut tokenizer = PreloadedTokenizer::new("$.a"); - match tokenizer.next_token() { - Ok(t) => assert_eq!(Token::Absolute(0), t), - _ => panic!() - } - - match tokenizer.peek_token() { - Ok(t) => assert_eq!(&Token::Dot(1), t), - _ => panic!() - } - - match tokenizer.peek_token() { - Ok(t) => assert_eq!(&Token::Dot(1), t), - _ => panic!() - } - - match tokenizer.next_token() { - Ok(t) => assert_eq!(Token::Dot(1), t), - _ => panic!() - } -} - -#[test] -fn token() { - run("$.01.a", - ( - vec![ - Token::Absolute(0), - Token::Dot(1), - Token::Key(2, "01".to_string()), - Token::Dot(4), - Token::Key(5, "a".to_string()) - ] - , Some(TokenError::Eof) - )); - - run("$. []", - ( - vec![ - Token::Absolute(0), - Token::Dot(1), - Token::Whitespace(2, 2), - Token::OpenArray(5), - Token::CloseArray(6) - ] - , Some(TokenError::Eof) - )); - - run("$..", - ( - vec![ - Token::Absolute(0), - Token::Dot(1), - Token::Dot(2), - ] - , Some(TokenError::Eof) - )); - - run("$..ab", - ( - vec![ - Token::Absolute(0), - Token::Dot(1), - Token::Dot(2), - Token::Key(3, "ab".to_string()) - ] - , Some(TokenError::Eof) - )); - - run("$..가 [", - ( - vec![ - Token::Absolute(0), - Token::Dot(1), - Token::Dot(2), - Token::Key(3, "가".to_string()), - Token::Whitespace(6, 0), - Token::OpenArray(7), - ] - , Some(TokenError::Eof) - )); - - run("[-1, 2 ]", - ( - vec![ - Token::OpenArray(0), - Token::Key(1, "-1".to_string()), - Token::Comma(3), - Token::Whitespace(4, 0), - Token::Key(5, "2".to_string()), - Token::Whitespace(6, 0), - Token::CloseArray(7), - ] - , Some(TokenError::Eof) - )); - - run("[ 1 2 , 3 \"abc\" : -10 ]", - ( - vec![ - Token::OpenArray(0), - Token::Whitespace(1, 0), - Token::Key(2, "1".to_string()), - Token::Whitespace(3, 0), - Token::Key(4, "2".to_string()), - Token::Whitespace(5, 0), - Token::Comma(6), - Token::Whitespace(7, 0), - Token::Key(8, "3".to_string()), - Token::Whitespace(9, 0), - Token::DoubleQuoted(10, "abc".to_string()), - Token::Whitespace(15, 0), - Token::Split(16), - Token::Whitespace(17, 0), - Token::Key(18, "-10".to_string()), - Token::Whitespace(21, 0), - Token::CloseArray(22), - ] - , Some(TokenError::Eof) - )); - - run("?(@.a가 <41.01)", - ( - vec![ - Token::Question(0), - Token::OpenParenthesis(1), - Token::At(2), - Token::Dot(3), - Token::Key(4, "a가".to_string()), - Token::Whitespace(8, 0), - Token::Little(9), - Token::Key(10, "41".to_string()), - Token::Dot(12), - Token::Key(13, "01".to_string()), - Token::CloseParenthesis(15), - ] - , Some(TokenError::Eof) - )); - - run("?(@.a <4a.01)", - ( - vec![ - Token::Question(0), - Token::OpenParenthesis(1), - Token::At(2), - Token::Dot(3), - Token::Key(4, "a".to_string()), - Token::Whitespace(5, 0), - Token::Little(6), - Token::Key(7, "4a".to_string()), - Token::Dot(9), - Token::Key(10, "01".to_string()), - Token::CloseParenthesis(12), - ] - , Some(TokenError::Eof) - )); - - run("?($.c>@.d)", ( - vec![ - Token::Question(0), - Token::OpenParenthesis(1), - Token::Absolute(2), - Token::Dot(3), - Token::Key(4, "c".to_string()), - Token::Greater(5), - Token::At(6), - Token::Dot(7), - Token::Key(8, "d".to_string()), - Token::CloseParenthesis(9) - ] - , Some(TokenError::Eof) - )); -} \ No newline at end of file diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index fa4bd9d..dc13ab0 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonpath-wasm" -version = "0.1.3" +version = "0.2.0" authors = ["Changseok Han "] description = "It is Webassembly version of jsonpath_lib that is JsonPath engine written in Rust - Demo: https://freestrings.github.io/jsonpath" keywords = ["jsonpath", "json", "webassembly", "parsing", "rust"] diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index db0d4c2..ce1eefb 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,4 +1,5 @@ extern crate cfg_if; +extern crate core; extern crate js_sys; extern crate jsonpath_lib as jsonpath; extern crate serde; @@ -6,19 +7,12 @@ extern crate serde_json; extern crate wasm_bindgen; extern crate web_sys; -use std::ops::Deref; -use std::result; -use std::result::Result; - use cfg_if::cfg_if; -use jsonpath::filter::value_filter::JsonValueFilter; -use jsonpath::parser::parser::{Node, NodeVisitor, Parser}; -use jsonpath::ref_value::model::{RefValue, RefValueWrapper}; +use jsonpath::{JsonPathError, Parser}; use jsonpath::Selector as _Selector; use serde_json::Value; use wasm_bindgen::*; use wasm_bindgen::prelude::*; -use web_sys::console; cfg_if! { if #[cfg(feature = "wee_alloc")] { @@ -38,16 +32,6 @@ cfg_if! { } } -fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue { - let mut jf = JsonValueFilter::new(json); - 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)) - } -} - fn into_serde_json(js_value: &JsValue) -> Result where D: for<'a> serde::de::Deserialize<'a> { @@ -64,26 +48,27 @@ fn into_serde_json(js_value: &JsValue) -> Result } } -fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue { - let result: result::Result = into_serde_json::(js_value); - match result { - Ok(json) => filter_ref_value(json.into(), node), - Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e)) - } -} - -fn get_ref_value(js_value: JsValue, node: Node) -> JsValue { - into_ref_value(&js_value, node) -} - #[wasm_bindgen] pub fn compile(path: &str) -> JsValue { let mut parser = Parser::new(path); let node = parser.compile(); + let cb = Closure::wrap(Box::new(move |js_value: JsValue| { + let mut selector = _Selector::new(); match &node { - Ok(node) => get_ref_value(js_value, node.clone()), - Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e)) + Ok(node) => selector.compiled_path(node.clone()), + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) + }; + let json = match into_serde_json(&js_value) { + Ok(json) => json, + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) + }; + match selector.value(&json).select() { + Ok(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => ret, + Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) + }, + Err(e) => JsValue::from_str(&format!("{:?}", e)) } }) as Box JsValue>); @@ -94,16 +79,26 @@ pub fn compile(path: &str) -> JsValue { #[wasm_bindgen] pub fn selector(js_value: JsValue) -> JsValue { - let json: RefValueWrapper = match into_serde_json::(&js_value) { - Ok(json) => json.into(), - Err(e) => return JsValue::from_str(e.as_str()) + let json: Value = match JsValue::into_serde(&js_value) { + Ok(json) => json, + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) }; 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()) + Ok(node) => { + let mut selector = _Selector::new(); + let _ = selector.compiled_path(node); + match selector.value(&json).select() { + Ok(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => ret, + Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) + }, + Err(e) => JsValue::from_str(&format!("{:?}", e)) + } + } + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e))) } }) as Box JsValue>); @@ -114,105 +109,76 @@ pub fn selector(js_value: JsValue) -> JsValue { #[wasm_bindgen] pub fn select(js_value: JsValue, path: &str) -> JsValue { - let mut parser = Parser::new(path); - match parser.compile() { - Ok(node) => get_ref_value(js_value, node), - Err(e) => return JsValue::from_str(e.as_str()) + let mut selector = _Selector::new(); + let _ = selector.path(path); + + let json = match into_serde_json(&js_value) { + Ok(json) => json, + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) + }; + + match selector.value(&json).select() { + Ok(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => ret, + Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) + }, + Err(e) => JsValue::from_str(&format!("{:?}", e)) } } /// /// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다. +/// lifetime 제약으로 Selector를 사용 할 수 없다. /// #[wasm_bindgen] pub struct Selector { - selector: _Selector + path: Option, + value: Option, } #[wasm_bindgen] impl Selector { #[wasm_bindgen(constructor)] pub fn new() -> Self { - Selector { selector: _Selector::new() } + Selector { path: None, value: None } } #[wasm_bindgen(catch)] - pub fn path(&mut self, path: &str) -> result::Result<(), JsValue> { - let _ = self.selector.path(path)?; + pub fn path(&mut self, path: &str) -> Result<(), JsValue> { + self.path = Some(path.to_string()); Ok(()) } #[wasm_bindgen(catch)] - pub fn value(&mut self, value: JsValue) -> result::Result<(), JsValue> { - let ref ref_value = into_serde_json(&value)?; - let _ = self.selector.value(ref_value)?; + pub fn value(&mut self, value: JsValue) -> Result<(), JsValue> { + let json = into_serde_json(&value) + .map_err(|e| JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))))?; + self.value = Some(json); Ok(()) } - #[wasm_bindgen(catch, js_name = selectToStr)] - pub fn select_to_str(&mut self) -> result::Result { - self.select_as_str() - } + #[wasm_bindgen(catch, js_name = select)] + pub fn select(&mut self) -> Result { + let mut selector = _Selector::new(); - #[wasm_bindgen(catch, js_name = selectAsStr)] - pub fn select_as_str(&mut self) -> result::Result { - let json_str = self.selector.select_as_str()?; - Ok(JsValue::from_str(&json_str)) - } - - #[wasm_bindgen(catch, js_name = selectTo)] - pub fn select_to(&mut self) -> result::Result { - self.select_as() - } - - #[wasm_bindgen(catch, js_name = selectAs)] - pub fn select_as(&mut self) -> result::Result { - let ref_value = self.selector.select_as::() - .map_err(|e| JsValue::from_str(&e))?; - Ok(JsValue::from_serde(&ref_value) - .map_err(|e| JsValue::from_str(&e.to_string()))?) - } - - #[wasm_bindgen(catch)] - pub fn map(&mut self, func: JsValue) -> result::Result<(), JsValue> { - if !func.is_function() { - return Err(JsValue::from_str("Not a function argument")); + if let Some(path) = &self.path { + let _ = selector.path(&path).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?; + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath))); } - let cb: &js_sys::Function = JsCast::unchecked_ref(func.as_ref()); + if let Some(value) = &self.value { + let _ = selector.value(value); + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue))); + } - self.selector.map(|v| { - let str_value = match JsValue::from_serde(&v) { - Ok(str_value) => str_value, - Err(e) => return { - console::error_1(&JsValue::from_str(&e.to_string())); - None - } - }; - - match cb.call1(&func, &str_value) { - Ok(ret) => { - match into_serde_json::(&ret) { - Ok(value) => Some(value), - Err(e) => { - console::error_1(&JsValue::from_str(&e.to_string())); - None - } - } - } - Err(e) => { - console::error_1(&e); - None - } - } - }).map_err(|e| JsValue::from_str(&e))?; - - Ok(()) - } - - #[wasm_bindgen(catch)] - pub fn get(&mut self) -> result::Result { - let v = self.selector.get().map_err(|e| JsValue::from_str(&e.to_string()))?; - JsValue::from_serde(&v).map_err(|e| JsValue::from_str(&e.to_string())) + match selector.select() { + Ok(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => Ok(ret), + Err(e) => Err(JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))) + }, + Err(e) => Err(JsValue::from_str(&format!("{:?}", e))) + } } } \ No newline at end of file diff --git a/wasm/tests/test/index.spec.js b/wasm/tests/test/index.spec.js index f64d094..8af3495 100644 --- a/wasm/tests/test/index.spec.js +++ b/wasm/tests/test/index.spec.js @@ -359,7 +359,7 @@ describe('compile test', () => { it('basic', (done) => { let template = jsonpath.compile('$.a'); let result = template({'a': 1}); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -369,7 +369,7 @@ describe('selector test', () => { it('basic', (done) => { let selector = jsonpath.selector({'a': 1}); let result = selector('$.a'); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -378,7 +378,7 @@ describe('selector test', () => { describe('select test', () => { it('basic', (done) => { let result = jsonpath.select({'a': 1}, '$.a'); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -407,7 +407,7 @@ describe('filter test', () => { "b" : {"a": 1}, "c" : {"a": 1} }); - let result = selector.selectAs(); + let result = selector.select(); if (JSON.stringify(result) === JSON.stringify([ {"a": 1}, {"a": 1} ])) { done(); } @@ -415,32 +415,12 @@ describe('filter test', () => { }); describe('Selector test', () => { - it('basic selectTo', (done) => { - let selector = new jsonpath.Selector(); - selector.path('$.a'); - selector.value({'a': 1}); - let result = selector.selectAs(); - if (result === 1) { - done(); - } - }); - - it('basic selectToStr', (done) => { - let selector = new jsonpath.Selector(); - selector.path('$.a'); - selector.value({'a': 1}); - let result = selector.selectToStr(); - if (result === '1') { - done(); - } - }); - it('select', (done) => { let selector = new jsonpath.Selector(); selector.value(jsonObj); for(var i in list) { selector.path(i); - if(JSON.stringify(list[i]) !== selector.selectAsStr()) { + if(JSON.stringify(list[i]) !== JSON.stringify(selector.select())) { throw `fail: ${i}`; } } @@ -468,7 +448,7 @@ describe('README test', () => { { selector.path('$..[?(@.age >= 30)]'); - let jsonObj = selector.selectAs(); + let jsonObj = selector.select(); let resultObj = [{"name": "친구3", "age": 30}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 30)]'; @@ -477,7 +457,7 @@ describe('README test', () => { { selector.path('$..[?(@.age == 20)]'); - let jsonObj = selector.selectAs(); + let jsonObj = selector.select(); let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 20)]'; @@ -486,35 +466,13 @@ describe('README test', () => { { selector.value({"friends": [ {"name": "친구5", "age": 20} ]}); - let jsonObj = selector.selectAs(); + let jsonObj = selector.select(); let resultObj = [{"name": "친구5", "age": 20}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: change value'; } } - { - selector.value(jsonObj); - selector.map(function(v) { - let f1 = v[0]; - f1.age = 30; - return v; - }) - let jsonObj1 = selector.get(); - - let resultObj1 = [{"name": "친구1", "age": 30}, {"name": "친구2", "age": 20}]; - if(JSON.stringify(jsonObj1) !== JSON.stringify(resultObj1)) { - throw 'jsonpath.Selector.map'; - } - - selector.path('$..[?(@.age == 20)]'); - let jsonObj2 = selector.selectAs(); - let resultObj2 = [{"name": "친구2", "age": 20}]; - if(JSON.stringify(jsonObj2) !== JSON.stringify(resultObj2)) { - throw 'jsonpath.Selector.map and then select'; - } - } - done(); }); diff --git a/wasm/www_bench/index.js b/wasm/www_bench/index.js index 535151a..62e69a6 100644 --- a/wasm/www_bench/index.js +++ b/wasm/www_bench/index.js @@ -73,8 +73,4 @@ run('jsonpath', iterCount, function() { jp.query(json, path) }) .then(function() { return run('jsonpath-wasm- select', iterCount, function() { jpw.select(json, path) }); }) - .finally(function() { - if(!jpw.deallocJson(ptr)) { - console.error('fail to dealloc'); - } - }); + .finally(function() {}); From 56a22674bfd80bb911596fde5bc2fb414009b53b Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 3 Jun 2019 11:34:34 +0900 Subject: [PATCH 04/15] fix wasm benches --- benches/bench_example.rs | 5 ++++- benches/bench_native.sh | 2 -- benches/bench_wasm.sh | 5 ----- benches/javascript/bench.js | 19 +------------------ 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/benches/bench_example.rs b/benches/bench_example.rs index ad2ba62..3748ca7 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -57,7 +57,10 @@ fn _selector(b: &mut Bencher, index: usize) { let mut selector = jsonpath::Selector::new(); let _ = selector.path(get_path(index)); selector.value(&json); - let _ = selector.select(); + let r = selector.select(); + if r.is_err() { + panic!() + } } }); } diff --git a/benches/bench_native.sh b/benches/bench_native.sh index efb6a83..c9346c0 100755 --- a/benches/bench_native.sh +++ b/benches/bench_native.sh @@ -35,8 +35,6 @@ __extra () { sleep 1 cd "${DIR}"/javascript && echo "NodeJs - jsonpath-rs - compile: " && time ./bench.sh nativeCompile ${ITER} printf "\n" - sleep 1 - cd "${DIR}"/javascript && echo "NodeJs - jsonpath-rs - selectorClassMap: " && time ./bench.sh nativeSelectorClassMap ${ITER} } if [ "$1" = "extra" ]; then diff --git a/benches/bench_wasm.sh b/benches/bench_wasm.sh index 35be013..90ff812 100755 --- a/benches/bench_wasm.sh +++ b/benches/bench_wasm.sh @@ -36,13 +36,8 @@ __extra () { cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - compile: " && time ./bench.sh wasmCompile ${ITER} printf "\n" sleep 1 - cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - compile-alloc: " && time ./bench.sh wasmCompileAlloc ${ITER} - printf "\n" - sleep 1 cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - Selector: " && time ./bench.sh wasmSelectorClass ${ITER} printf "\n" - sleep 1 - cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - Selector map: " && time ./bench.sh wasmSelectorClassMap ${ITER} } if [ "$1" = "extra" ]; then diff --git a/benches/javascript/bench.js b/benches/javascript/bench.js index 6537aca..6856b3d 100644 --- a/benches/javascript/bench.js +++ b/benches/javascript/bench.js @@ -71,13 +71,6 @@ function nativeSelect() { } } -function nativeSelectorClassMap() { - let selector = new jpwRs.Selector(); - for (var i = 0; i < iter; i++) { - let _ = selector.path(path).value(jsonStr).map((v) => v).get(); - } -} - function wasmSelector() { let selector = jpw.selector(getJson()); for (var i = 0; i < iter; i++) { @@ -103,17 +96,7 @@ function wasmSelectorClass() { for (var i = 0; i < iter; i++) { selector.path(path); selector.value(jsonStr); - let _ = selector.selectToStr(); - } -} - -function wasmSelectorClassMap() { - let selector = new jpw.Selector(); - for (var i = 0; i < iter; i++) { - selector.path(path); - selector.value(jsonStr); - let _1 = selector.map((v) => v); - let _2 = selector.get(); + let _ = selector.select(); } } From 498f2ce4f46fb15f3f78e921e46f4f6c6bd154e1 Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 3 Jun 2019 13:50:44 +0900 Subject: [PATCH 05/15] fix nodejs --- README.md | 101 +++++-------------- nodejs/lib/index.js | 33 +------ nodejs/native/Cargo.toml | 4 +- nodejs/native/src/lib.rs | 201 +++++++++++++++++--------------------- nodejs/test/index.spec.js | 47 ++------- src/lib.rs | 2 +- 6 files changed, 129 insertions(+), 259 deletions(-) diff --git a/README.md b/README.md index 71e19b1..354369a 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ extern crate serde_json; #### Rust - jsonpath::Selector struct ```rust -#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[derive(Deserialize, PartialEq, Debug)] struct Friend { name: String, age: Option, @@ -72,43 +72,16 @@ let mut selector = Selector::new(); let result = selector .path("$..[?(@.age >= 30)]").unwrap() -// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap() -// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap() - .value(&json_obj /*serde_json::value::Value*/).unwrap() - .select_as_value().unwrap(); + .value(&json_obj) + .select().unwrap(); -assert_eq!(json!([{"name": "친구3", "age": 30}]), result); +assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result); let result = selector.select_as_str().unwrap(); assert_eq!(r#"[{"name":"친구3","age":30}]"#, result); -let result = selector.select_as::>().unwrap(); +let result = selector.select_as::().unwrap(); assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); - -let _ = 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!(json!([{ "name": "친구3" }]), selector.get().unwrap()); - -let _ = selector.value(&json_obj).unwrap() - .map_as(|mut v: Vec| { - let mut f = v.pop().unwrap(); - f.name = "friend3".to_string(); - f.age = None; - Some(vec![f]) - }); - -assert_eq!(vec![Friend { name: "friend3".to_string(), age: None }], - selector.get_as::>().unwrap()); ``` #### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str) @@ -128,11 +101,10 @@ let json_obj = json!({ let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap(); -let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} +assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); -assert_eq!(json, ret); ``` #### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str) @@ -166,7 +138,7 @@ struct Person { phones: Vec, } -let ret: Person = jsonpath::select_as(r#" +let ret: Vec = jsonpath::select_as(r#" { "person": { @@ -186,7 +158,7 @@ let person = Person { phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()], }; -assert_eq!(person, ret); +assert_eq!(ret[0], person); ``` #### Rust - jsonpath::compile(jsonpath: &str) @@ -208,12 +180,10 @@ let json_obj = json!({ let json = template(&json_obj).unwrap(); -let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} +assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); - -assert_eq!(json, ret); ``` #### Rust - jsonpath::selector(json: &serde_json::value::Value) @@ -235,21 +205,17 @@ let mut selector = jsonpath::selector(&json_obj); let json = selector("$..friends[0]").unwrap(); -let ret = json!([ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} +assert_eq!(json, vec![ + &json!({"name": "친구3", "age": 30}), + &json!({"name": "친구1", "age": 20}) ]); -assert_eq!(json, ret); - let json = selector("$..friends[1]").unwrap(); -let ret = json!([ - {"name": "친구4"}, - {"name": "친구2", "age": 20} +assert_eq!(json, vec![ + &json!({"name": "친구4"}), + &json!({"name": "친구2", "age": 20}) ]); - -assert_eq!(json, ret); ``` #### Rust - jsonpath::selector_as\(json: &serde_json::value::Value) @@ -267,13 +233,13 @@ let json_obj = json!({ {"name": "친구4"} ]}); -#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[derive(Deserialize, PartialEq, Debug)] struct Friend { name: String, age: Option, } -let mut selector = jsonpath::selector_as::>(&json_obj); +let mut selector = jsonpath::selector_as::(&json_obj); let json = selector("$..friends[0]").unwrap(); @@ -346,21 +312,10 @@ let selector = new jsonpath.Selector(); selector.path('$..friends[0]'); selector.value(jsonObj); -let selectAsObj = selector.selectAs(); -let selectAsString = selector.selectAsStr(); +let retObj = selector.select(); -console.log( - JSON.stringify(ret) == JSON.stringify(selectAsObj), - JSON.stringify(ret) == selectAsString -); +console.log(JSON.stringify(ret) == JSON.stringify(retObj)); -selector.map(function(v) { - let f1 = v[0]; - f1.name = 'friend3'; - return [f1]; -}); - -console.log(JSON.stringify(selector.get()) === JSON.stringify([{"name": "friend3", "age": 30}])); // => true ``` @@ -389,15 +344,11 @@ let selector = new jsonpath.Selector() .path('$..friends[0]') .value(jsonObj); -let selectAsObj = selector.selectAs(); -let selectAsString = selector.selectAsStr(); +let retObj = selector.select(); -console.log( - JSON.stringify(ret) == JSON.stringify(selectAsObj), - JSON.stringify(ret) == selectAsString -); +console.log(JSON.stringify(ret) == JSON.stringify(retObj)); -// => true, true +// => true ``` #### Javascript - jsonpath.select(json: string|object, jsonpath: string) diff --git a/nodejs/lib/index.js b/nodejs/lib/index.js index 20032c7..68e0122 100644 --- a/nodejs/lib/index.js +++ b/nodejs/lib/index.js @@ -42,39 +42,12 @@ class Selector { if(typeof json != 'string') { json = JSON.stringify(json) } - this._selector.valueFromStr(json); + this._selector.value(json); return this; } - selectToStr() { - return this.selectAsStr(); - } - - selectTo() { - return this.selectAs(); - } - - selectAsStr() { - return this._selector.selectAsStr(); - } - - selectAs() { - return JSON.parse(this.selectAsStr()); - } - - map(func) { - this._selector.map((json) => { - var result = func.call(null, JSON.parse(json)); - if(typeof result !== 'string') { - result = JSON.stringify(result); - } - return result; - }); - return this; - } - - get() { - return JSON.parse(this._selector.get()); + select() { + return JSON.parse(this._selector.select()); } } diff --git a/nodejs/native/Cargo.toml b/nodejs/native/Cargo.toml index 2e6238a..9b0f1ce 100644 --- a/nodejs/native/Cargo.toml +++ b/nodejs/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonpath4nodejs" -version = "0.1.3" +version = "0.2.0" authors = ["Changseok Han "] description = "jsonpath_lib bindings for nodejs" keywords = ["library", "jsonpath", "json", "nodejs"] @@ -14,7 +14,7 @@ exclude = ["artifacts.json", "index.node"] neon-build = "0.2.0" [dependencies] -jsonpath_lib = "0.1.13" +jsonpath_lib = "0.2.0" neon = "0.2.0" neon-serde = "0.1.1" serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index 09f5c72..6056220 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -4,13 +4,9 @@ extern crate neon; extern crate neon_serde; extern crate serde_json; -use jsonpath::filter::value_filter::JsonValueFilter; -use jsonpath::parser::parser::{Node, NodeVisitor, Parser}; -use jsonpath::ref_value::model::{RefValue, RefValueWrapper}; -use jsonpath::Selector; +use jsonpath::{JsonPathError, Node, Parser, Selector}; use neon::prelude::*; use serde_json::Value; -use std::ops::Deref; /// /// `neon_serde::from_value` has very poor performance. @@ -35,96 +31,124 @@ fn select_str(mut ctx: FunctionContext) -> JsResult { } } -pub struct CompileFn { - node: Node -} - -pub struct SelectorFn { - json: RefValueWrapper -} pub struct SelectorCls { - selector: Selector + node: Option, + value: Option, +} + +impl SelectorCls { + fn path(&mut self, path: &str) { + let mut parser = Parser::new(path); + let node = match parser.compile() { + Ok(node) => node, + Err(e) => panic!("{:?}", e) + }; + + self.node = Some(node); + } + + fn value(&mut self, json_str: &str) { + let value: Value = match serde_json::from_str(&json_str) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }; + + self.value = Some(value); + } + + fn select(&self) -> String { + let node = match &self.node { + Some(node) => node.clone(), + None => panic!("{:?}", JsonPathError::EmptyPath) + }; + + let value = match &self.value { + Some(value) => value, + None => panic!("{:?}", JsonPathError::EmptyValue) + }; + + let mut selector = Selector::new(); + selector.compiled_path(node.clone()); + selector.value(&value); + match selector.select_as_str() { + Ok(ret) => ret, + Err(e) => panic!("{:?}", e) + } + } } declare_types! { - pub class JsCompileFn for CompileFn { + pub class JsCompileFn for SelectorCls { init(mut ctx) { let path = ctx.argument::(0)?.value(); let mut parser = Parser::new(path.as_str()); - let node = match parser.compile() { Ok(node) => node, Err(e) => panic!("{:?}", e) }; - Ok(CompileFn { node }) + Ok(SelectorCls { node: Some(node), value: None }) } method template(mut ctx) { - let this = ctx.this(); - - let node = { - let guard = ctx.lock(); - let this = this.borrow(&guard); - this.node.clone() - }; + let mut this = ctx.this(); let json_str = ctx.argument::(0)?.value(); - let ref_value: RefValue = match serde_json::from_str(&json_str) { - Ok(ref_value) => ref_value, - Err(e) => panic!("{:?}", e) + { + let guard = ctx.lock(); + let mut this = this.borrow_mut(&guard); + let value: Value = match serde_json::from_str(&json_str) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }; + this.value = Some(value); }; - let mut jf = JsonValueFilter::new_from_value(ref_value.into()); - jf.visit(node); - match serde_json::to_string(&jf.take_value().deref()) { - Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()), - Err(e) => panic!("{:?}", e) - } + let result_str = { + let guard = ctx.lock(); + let this = this.borrow(&guard); + this.select() + }; + + Ok(JsString::new(&mut ctx, &result_str).upcast()) } } - pub class JsSelectorFn for SelectorFn { + pub class JsSelectorFn for SelectorCls { init(mut ctx) { let json_str = ctx.argument::(0)?.value(); - let ref_value: RefValue = match serde_json::from_str(&json_str) { - Ok(ref_value) => ref_value, - Err(e) => panic!("{:?}", e) + let value: Value = match serde_json::from_str(&json_str) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) }; - Ok(SelectorFn { json: ref_value.into() }) + Ok(SelectorCls { node: None, value: Some(value) }) } method select(mut ctx) { - let this = ctx.this(); - - let json = { - let guard = ctx.lock(); - let this = this.borrow(&guard); - this.json.clone() - }; + let mut this = ctx.this(); let path = ctx.argument::(0)?.value(); - let mut parser = Parser::new(path.as_str()); + { + let guard = ctx.lock(); + let mut this = this.borrow_mut(&guard); + this.path(&path); + } - let node = match parser.compile() { - Ok(node) => node, - Err(e) => panic!("{:?}", e) + let result_str = { + let guard = ctx.lock(); + let this = this.borrow(&guard); + this.select() }; - let mut jf = JsonValueFilter::new_from_value(json); - jf.visit(node); - match serde_json::to_string(&jf.take_value().deref()) { - Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()), - Err(e) => panic!("{:?}", e) - } + Ok(JsString::new(&mut ctx, &result_str).upcast()) } } pub class JsSelector for SelectorCls { init(mut _ctx) { - Ok(SelectorCls { selector: Selector::new() }) + Ok(SelectorCls { node: None, value: None }) } method path(mut ctx) { @@ -134,80 +158,35 @@ declare_types! { { let guard = ctx.lock(); let mut this = this.borrow_mut(&guard); - let _ = this.selector.path(&path); + let _ = this.path(&path); } + Ok(JsUndefined::new().upcast()) } - method valueFromStr(mut ctx) { + method value(mut ctx) { let mut this = ctx.this(); let json_str = ctx.argument::(0)?.value(); { let guard = ctx.lock(); let mut this = this.borrow_mut(&guard); - let _ = this.selector.value_from_str(&json_str); + let _ = this.value(&json_str); } + Ok(JsUndefined::new().upcast()) } - method selectAsStr(mut ctx) { - let mut this = ctx.this(); + method select(mut ctx) { + let this = ctx.this(); - let result = { + let result_str = { let guard = ctx.lock(); - let this = this.borrow_mut(&guard); - this.selector.select_as_str() + let this = this.borrow(&guard); + this.select() }; - match result { - Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()), - Err(e) => panic!("{:?}", e) - } - } - - method map(mut ctx) { - let null = ctx.null(); - let mut this = ctx.this(); - - let func = ctx.argument::(0)?; - - let value = { - let guard = ctx.lock(); - let this = this.borrow_mut(&guard); - match this.selector.select_as_str() { - Ok(v) => v, - Err(e) => panic!("{:?}", e) - } - }; - - let js_value = JsString::new(&mut ctx, &value); - let json_str = func.call(&mut ctx, null, vec![js_value])? - .downcast::() - .or_throw(&mut ctx)? - .value(); - { - let guard = ctx.lock(); - let mut this = this.borrow_mut(&guard); - let _ = this.selector.value_from_str(&json_str); - } - - Ok(JsUndefined::new().upcast()) - } - - method get(mut ctx) { - let mut this = ctx.this(); - - let result = { - let guard = ctx.lock(); - let this = this.borrow_mut(&guard); - match this.selector.get() { - Ok(v) => v, - Err(e) => panic!("{:?}", e) - } - }; - - Ok(JsString::new(&mut ctx, &result.to_string()).upcast()) + Ok(JsString::new(&mut ctx, &result_str).upcast()) } } } diff --git a/nodejs/test/index.spec.js b/nodejs/test/index.spec.js index 99ee6e8..e4d50ba 100644 --- a/nodejs/test/index.spec.js +++ b/nodejs/test/index.spec.js @@ -359,7 +359,7 @@ describe('compile test', () => { it('basic', (done) => { let template = jsonpath.compile('$.a'); let result = template({'a': 1}); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -369,7 +369,7 @@ describe('selector test', () => { it('basic', (done) => { let selector = jsonpath.selector({'a': 1}); let result = selector('$.a'); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -378,7 +378,7 @@ describe('selector test', () => { describe('select test', () => { it('basic', (done) => { let result = jsonpath.select({'a': 1}, '$.a'); - if (result === 1) { + if (result[0] === 1) { done(); } }); @@ -401,24 +401,10 @@ describe('filter test', () => { }); describe('Selector test', () => { - it('basic selectTo', (done) => { - let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectTo(); - if (result === 1) { - done(); - } - }); - - it('basic selectToStr', (done) => { - let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectToStr(); - if (result === '1') { - done(); - } - }); - it('select', (done) => { let selector = new jsonpath.Selector().value(jsonObj); for(var i in list) { - if(JSON.stringify(list[i]) !== selector.path(i).selectToStr()) { + if(JSON.stringify(list[i]) !== JSON.stringify(selector.path(i).select())) { throw `fail: ${i}`; } } @@ -444,7 +430,7 @@ describe('README test', () => { let selector = new jsonpath.Selector().value(jsonObj); { - let jsonObj = selector.path('$..[?(@.age >= 30)]').selectAs(); + let jsonObj = selector.path('$..[?(@.age >= 30)]').select(); let resultObj = [{"name": "친구3", "age": 30}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 30)]'; @@ -452,7 +438,7 @@ describe('README test', () => { } { - let jsonObj = selector.path('$..[?(@.age == 20)]').selectAs(); + let jsonObj = selector.path('$..[?(@.age == 20)]').select(); let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 20)]'; @@ -460,32 +446,13 @@ describe('README test', () => { } { - let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectAs(); + let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).select(); let resultObj = [{"name": "친구5", "age": 20}]; if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: change value'; } } - { - let jsonObj1 = selector.value(jsonObj).map(function(v) { - let f1 = v[0]; - f1.age = 30; - return v; - }).get(); - - let resultObj1 = [{"name": "친구1", "age": 30}, {"name": "친구2", "age": 20}]; - if(JSON.stringify(jsonObj1) !== JSON.stringify(resultObj1)) { - throw 'jsonpath.Selector.map'; - } - - let jsonObj2 = selector.path('$..[?(@.age == 20)]').selectAs(); - let resultObj2 = [{"name": "친구2", "age": 20}]; - if(JSON.stringify(jsonObj2) !== JSON.stringify(resultObj2)) { - throw 'jsonpath.Selector.map and then select'; - } - } - done(); }); diff --git a/src/lib.rs b/src/lib.rs index a26e723..2a3401a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ mod select; pub use select::Selector; pub use select::JsonPathError; -pub use parser::parser::Parser; +pub use parser::parser::{Node, Parser}; /// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects. /// From ac3224892bb5a3cd0b31d995e1fccc2842dd2756 Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 3 Jun 2019 18:45:26 +0900 Subject: [PATCH 06/15] Remove Parser's lifetime --- nodejs/native/src/lib.rs | 6 +- src/lib.rs | 3 +- src/parser/mod.rs | 7 +- src/parser/parser.rs | 376 +++++++++++++++++++-------------------- src/parser/tokenizer.rs | 6 +- src/select/mod.rs | 3 +- wasm/src/lib.rs | 6 +- 7 files changed, 198 insertions(+), 209 deletions(-) diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index 6056220..cb5b494 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -39,8 +39,7 @@ pub struct SelectorCls { impl SelectorCls { fn path(&mut self, path: &str) { - let mut parser = Parser::new(path); - let node = match parser.compile() { + let node = match Parser::compile(path) { Ok(node) => node, Err(e) => panic!("{:?}", e) }; @@ -82,8 +81,7 @@ declare_types! { pub class JsCompileFn for SelectorCls { init(mut ctx) { let path = ctx.argument::(0)?.value(); - let mut parser = Parser::new(path.as_str()); - let node = match parser.compile() { + let node = match Parser::compile(path.as_str()) { Ok(node) => node, Err(e) => panic!("{:?}", e) }; diff --git a/src/lib.rs b/src/lib.rs index 2a3401a..9c9dc74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,8 +170,7 @@ pub use parser::parser::{Node, Parser}; /// ]); /// ``` pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPathError> { - let mut parser = Parser::new(path); - let node = parser.compile(); + let node = Parser::compile(path); move |json| { let mut selector = Selector::new(); match &node { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index bce22d6..42ac385 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17,8 +17,7 @@ mod parser_tests { } fn start(&mut self) -> Result, String> { - let mut parser = Parser::new(self.input); - let node = parser.compile()?; + let node = Parser::compile(self.input)?; self.visit(&node); Ok(self.stack.split_off(0)) } @@ -330,7 +329,7 @@ mod parser_tests { #[cfg(test)] mod tokenizer_tests { - use parser::tokenizer::{Token, TokenError, Tokenizer, PreloadedTokenizer}; + use parser::tokenizer::{Token, TokenError, Tokenizer, TokenReader}; fn collect_token(input: &str) -> (Vec, Option) { let mut tokenizer = Tokenizer::new(input); @@ -350,7 +349,7 @@ mod tokenizer_tests { #[test] fn peek() { - let mut tokenizer = PreloadedTokenizer::new("$.a"); + let mut tokenizer = TokenReader::new("$.a"); match tokenizer.next_token() { Ok(t) => assert_eq!(Token::Absolute(0), t), _ => panic!() diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 60318ce..253252f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -73,44 +73,40 @@ pub struct Node { token: ParseToken, } -pub struct Parser<'a> { - tokenizer: PreloadedTokenizer<'a> -} +pub struct Parser; -impl<'a> Parser<'a> { - pub fn new(input: &'a str) -> Self { - Parser { tokenizer: PreloadedTokenizer::new(input) } +impl Parser { + + pub fn compile(input: &str) -> ParseResult { + let mut tokenizer = TokenReader::new(input); + Ok(Self::json_path(&mut tokenizer)?) } - pub fn compile(&mut self) -> ParseResult { - Ok(self.json_path()?) - } - - fn json_path(&mut self) -> ParseResult { + fn json_path(tokenizer: &mut TokenReader) -> ParseResult { debug!("#json_path"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Absolute(_)) => { - let node = self.node(ParseToken::Absolute); - self.paths(node) + let node = Self::node(ParseToken::Absolute); + Self::paths(node, tokenizer) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn paths(&mut self, prev: Node) -> ParseResult { + fn paths(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#paths"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Dot(_)) => { - self.eat_token(); - self.paths_dot(prev) + Self::eat_token(tokenizer); + Self::paths_dot(prev, tokenizer) } Ok(Token::OpenArray(_)) => { - self.eat_token(); - self.eat_whitespace(); - let node = self.array(prev)?; - self.paths(node) + Self::eat_token(tokenizer); + Self::eat_whitespace(tokenizer); + let node = Self::array(prev, tokenizer)?; + Self::paths(node, tokenizer) } _ => { Ok(prev) @@ -118,10 +114,10 @@ impl<'a> Parser<'a> { } } - fn paths_dot(&mut self, prev: Node) -> ParseResult { + fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#paths_dot"); - let node = self.path(prev)?; - match self.tokenizer.peek_token() { + let node = Self::path(prev, tokenizer)?; + match tokenizer.peek_token() { Ok(Token::Equal(_)) | Ok(Token::NotEqual(_)) | Ok(Token::Little(_)) @@ -133,331 +129,331 @@ impl<'a> Parser<'a> { Ok(node) } _ => { - self.paths(node) + Self::paths(node, tokenizer) } } } - fn path(&mut self, prev: Node) -> ParseResult { + fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Dot(_)) => { - self.path_leaves(prev) + Self::path_leaves(prev, tokenizer) } Ok(Token::Asterisk(_)) => { - self.path_in_all(prev) + Self::path_in_all(prev, tokenizer) } Ok(Token::Key(_, _)) => { - self.path_in_key(prev) + Self::path_in_key(prev, tokenizer) } Ok(Token::OpenArray(_)) => { - self.eat_token(); - self.array(prev) + Self::eat_token(tokenizer); + Self::array(prev, tokenizer) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn path_leaves(&mut self, prev: Node) -> ParseResult { + fn path_leaves(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path_leaves"); - self.eat_token(); - match self.tokenizer.peek_token() { + Self::eat_token(tokenizer); + match tokenizer.peek_token() { Ok(Token::Asterisk(_)) => { - self.path_leaves_all(prev) + Self::path_leaves_all(prev, tokenizer) } Ok(Token::OpenArray(_)) => { - let mut leaves_node = self.node(ParseToken::Leaves); + let mut leaves_node = Self::node(ParseToken::Leaves); leaves_node.left = Some(Box::new(prev)); - Ok(self.paths(leaves_node)?) + Ok(Self::paths(leaves_node, tokenizer)?) } _ => { - self.path_leaves_key(prev) + Self::path_leaves_key(prev, tokenizer) } } } - fn path_leaves_key(&mut self, prev: Node) -> ParseResult { + fn path_leaves_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path_leaves_key"); Ok(Node { token: ParseToken::Leaves, left: Some(Box::new(prev)), - right: Some(Box::new(self.key()?)), + right: Some(Box::new(Self::key(tokenizer)?)), }) } - fn path_leaves_all(&mut self, prev: Node) -> ParseResult { + fn path_leaves_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path_leaves_all"); - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::Leaves, left: Some(Box::new(prev)), - right: Some(Box::new(self.node(ParseToken::All))), + right: Some(Box::new(Self::node(ParseToken::All))), }) } - fn path_in_all(&mut self, prev: Node) -> ParseResult { + fn path_in_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path_in_all"); - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::In, left: Some(Box::new(prev)), - right: Some(Box::new(self.node(ParseToken::All))), + right: Some(Box::new(Self::node(ParseToken::All))), }) } - fn path_in_key(&mut self, prev: Node) -> ParseResult { + fn path_in_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#path_in_key"); Ok(Node { token: ParseToken::In, left: Some(Box::new(prev)), - right: Some(Box::new(self.key()?)), + right: Some(Box::new(Self::key(tokenizer)?)), }) } - fn key(&mut self) -> ParseResult { + fn key(tokenizer: &mut TokenReader) -> ParseResult { debug!("#key"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(_, v)) => { - Ok(self.node(ParseToken::Key(v))) + Ok(Self::node(ParseToken::Key(v))) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn boolean(&mut self) -> ParseResult { + fn boolean(tokenizer: &mut TokenReader) -> ParseResult { debug!("#boolean"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(_, v)) => { - Ok(self.node(ParseToken::Bool(v.eq_ignore_ascii_case("true")))) + Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true")))) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn array_quota_value(&mut self) -> ParseResult { + fn array_quota_value(tokenizer: &mut TokenReader) -> ParseResult { debug!("#array_quota_value"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => { - Ok(self.node(ParseToken::Key(val))) + Ok(Self::node(ParseToken::Key(val))) } Err(TokenError::Eof) => { - Ok(self.node(ParseToken::Eof)) + Ok(Self::node(ParseToken::Eof)) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn array_start(&mut self, prev: Node) -> ParseResult { + fn array_start(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#array_start"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Question(_)) => { - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::Array, left: Some(Box::new(prev)), - right: Some(Box::new(self.filter()?)), + right: Some(Box::new(Self::filter(tokenizer)?)), }) } Ok(Token::Asterisk(_)) => { - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::Array, left: Some(Box::new(prev)), - right: Some(Box::new(self.node(ParseToken::All))), + right: Some(Box::new(Self::node(ParseToken::All))), }) } _ => { Ok(Node { token: ParseToken::Array, left: Some(Box::new(prev)), - right: Some(Box::new(self.array_value()?)), + right: Some(Box::new(Self::array_value(tokenizer)?)), }) } } } - fn array(&mut self, prev: Node) -> ParseResult { + fn array(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#array"); - let ret = self.array_start(prev)?; - self.eat_whitespace(); - self.close_token(ret, Token::CloseArray(DUMMY)) + let ret = Self::array_start(prev, tokenizer)?; + Self::eat_whitespace(tokenizer); + Self::close_token(ret, Token::CloseArray(DUMMY), tokenizer) } - fn array_value_key(&mut self) -> ParseResult { + fn array_value_key(tokenizer: &mut TokenReader) -> ParseResult { debug!("#array_value_key"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(pos, ref val)) => { - let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?; - self.eat_whitespace(); + let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?; + Self::eat_whitespace(tokenizer); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Comma(_)) => { - self.union(digit) + Self::union(digit, tokenizer) } Ok(Token::Split(_)) => { - self.range_from(digit) + Self::range_from(digit, tokenizer) } _ => { - Ok(self.node(ParseToken::Number(digit as f64))) + Ok(Self::node(ParseToken::Number(digit as f64))) } } } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn array_value(&mut self) -> ParseResult { + fn array_value(tokenizer: &mut TokenReader) -> ParseResult { debug!("#array_value"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Key(_, _)) => { - self.array_value_key() + Self::array_value_key(tokenizer) } Ok(Token::Split(_)) => { - self.eat_token(); - self.range_to() + Self::eat_token(tokenizer); + Self::range_to(tokenizer) } Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => { - self.array_quota_value() + Self::array_quota_value(tokenizer) } Err(TokenError::Eof) => { - Ok(self.node(ParseToken::Eof)) + Ok(Self::node(ParseToken::Eof)) } _ => { - self.eat_token(); - Err(self.tokenizer.err_msg()) + Self::eat_token(tokenizer); + Err(tokenizer.err_msg()) } } } - fn union(&mut self, num: isize) -> ParseResult { + fn union(num: isize, tokenizer: &mut TokenReader) -> ParseResult { debug!("#union"); let mut values = vec![num]; - while match self.tokenizer.peek_token() { + while match tokenizer.peek_token() { Ok(Token::Comma(_)) => true, _ => false } { - self.eat_token(); - self.eat_whitespace(); - match self.tokenizer.next_token() { + Self::eat_token(tokenizer); + Self::eat_whitespace(tokenizer); + match tokenizer.next_token() { Ok(Token::Key(pos, ref val)) => { - let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?; + let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?; values.push(digit); } _ => { - return Err(self.tokenizer.err_msg()); + return Err(tokenizer.err_msg()); } } } - Ok(self.node(ParseToken::Union(values))) + Ok(Self::node(ParseToken::Union(values))) } - fn range_from(&mut self, num: isize) -> ParseResult { + fn range_from(num: isize, tokenizer: &mut TokenReader) -> ParseResult { debug!("#range_from"); - self.eat_token(); - self.eat_whitespace(); - match self.tokenizer.peek_token() { + Self::eat_token(tokenizer); + Self::eat_whitespace(tokenizer); + match tokenizer.peek_token() { Ok(Token::Key(_, _)) => { - self.range(num) + Self::range(num, tokenizer) } _ => { - Ok(self.node(ParseToken::Range(Some(num), None))) + Ok(Self::node(ParseToken::Range(Some(num), None))) } } } - fn range_to(&mut self) -> ParseResult { + fn range_to(tokenizer: &mut TokenReader) -> ParseResult { debug!("#range_to"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(pos, ref val)) => { - let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?; - Ok(self.node(ParseToken::Range(None, Some(digit)))) + let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?; + Ok(Self::node(ParseToken::Range(None, Some(digit)))) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn range(&mut self, num: isize) -> ParseResult { + fn range(num: isize, tokenizer: &mut TokenReader) -> ParseResult { debug!("#range"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(pos, ref val)) => { - let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?; - Ok(self.node(ParseToken::Range(Some(num), Some(digit)))) + let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?; + Ok(Self::node(ParseToken::Range(Some(num), Some(digit)))) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn filter(&mut self) -> ParseResult { + fn filter(tokenizer: &mut TokenReader) -> ParseResult { debug!("#filter"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::OpenParenthesis(_)) => { - let ret = self.exprs()?; - self.eat_whitespace(); - self.close_token(ret, Token::CloseParenthesis(DUMMY)) + let ret = Self::exprs(tokenizer)?; + Self::eat_whitespace(tokenizer); + Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer) } Err(TokenError::Eof) => { - Ok(self.node(ParseToken::Eof)) + Ok(Self::node(ParseToken::Eof)) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn exprs(&mut self) -> ParseResult { - self.eat_whitespace(); + fn exprs(tokenizer: &mut TokenReader) -> ParseResult { + Self::eat_whitespace(tokenizer); debug!("#exprs"); - let node = match self.tokenizer.peek_token() { + let node = match tokenizer.peek_token() { Ok(Token::OpenParenthesis(_)) => { - self.eat_token(); + Self::eat_token(tokenizer); trace!("\t-exprs - open_parenthesis"); - let ret = self.exprs()?; - self.eat_whitespace(); - self.close_token(ret, Token::CloseParenthesis(DUMMY))? + let ret = Self::exprs(tokenizer)?; + Self::eat_whitespace(tokenizer); + Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)? } _ => { trace!("\t-exprs - else"); - self.expr()? + Self::expr(tokenizer)? } }; - self.eat_whitespace(); - self.condition_expr(node) + Self::eat_whitespace(tokenizer); + Self::condition_expr(node, tokenizer) } - fn condition_expr(&mut self, prev: Node) -> ParseResult { + fn condition_expr(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#condition_expr"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::And(_)) => { - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::Filter(FilterToken::And), left: Some(Box::new(prev)), - right: Some(Box::new(self.exprs()?)), + right: Some(Box::new(Self::exprs(tokenizer)?)), }) } Ok(Token::Or(_)) => { - self.eat_token(); + Self::eat_token(tokenizer); Ok(Node { token: ParseToken::Filter(FilterToken::Or), left: Some(Box::new(prev)), - right: Some(Box::new(self.exprs()?)), + right: Some(Box::new(Self::exprs(tokenizer)?)), }) } _ => { @@ -466,18 +462,18 @@ impl<'a> Parser<'a> { } } - fn expr(&mut self) -> ParseResult { + fn expr(tokenizer: &mut TokenReader) -> ParseResult { debug!("#expr"); - let has_prop_candidate = match self.tokenizer.peek_token() { + let has_prop_candidate = match tokenizer.peek_token() { Ok(Token::At(_)) => true, _ => false }; - let node = self.term()?; - self.eat_whitespace(); + let node = Self::term(tokenizer)?; + Self::eat_whitespace(tokenizer); - if match self.tokenizer.peek_token() { + if match tokenizer.peek_token() { Ok(Token::Equal(_)) | Ok(Token::NotEqual(_)) | Ok(Token::Little(_)) @@ -486,97 +482,97 @@ impl<'a> Parser<'a> { | Ok(Token::GreaterOrEqual(_)) => true, _ => false } { - self.op(node) + Self::op(node, tokenizer) } else if has_prop_candidate { Ok(node) } else { - return Err(self.tokenizer.err_msg()); + return Err(tokenizer.err_msg()); } } - fn term_num(&mut self) -> ParseResult { + fn term_num(tokenizer: &mut TokenReader) -> ParseResult { debug!("#term_num"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(Token::Key(pos, val)) => { - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Dot(_)) => { - self.term_num_float(val.as_str()) + Self::term_num_float(val.as_str(), tokenizer) } _ => { - let number = utils::string_to_f64(&val, || self.tokenizer.err_msg_with_pos(pos))?; - Ok(self.node(ParseToken::Number(number))) + let number = utils::string_to_f64(&val, || tokenizer.err_msg_with_pos(pos))?; + Ok(Self::node(ParseToken::Number(number))) } } } Err(TokenError::Eof) => { - Ok(self.node(ParseToken::Eof)) + Ok(Self::node(ParseToken::Eof)) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn term_num_float(&mut self, mut num: &str) -> ParseResult { + fn term_num_float(mut num: &str, tokenizer: &mut TokenReader) -> ParseResult { debug!("#term_num_float"); - self.eat_token(); - match self.tokenizer.next_token() { + Self::eat_token(tokenizer); + match tokenizer.next_token() { Ok(Token::Key(pos, frac)) => { let mut f = String::new(); f.push_str(&mut num); f.push('.'); f.push_str(frac.as_str()); - let number = utils::string_to_f64(&f, || self.tokenizer.err_msg_with_pos(pos))?; - Ok(self.node(ParseToken::Number(number))) + let number = utils::string_to_f64(&f, || tokenizer.err_msg_with_pos(pos))?; + Ok(Self::node(ParseToken::Number(number))) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn term(&mut self) -> ParseResult { + fn term(tokenizer: &mut TokenReader) -> ParseResult { debug!("#term"); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::At(_)) => { - self.eat_token(); - let node = self.node(ParseToken::Relative); + Self::eat_token(tokenizer); + let node = Self::node(ParseToken::Relative); - match self.tokenizer.peek_token() { + match tokenizer.peek_token() { Ok(Token::Whitespace(_, _)) => { - self.eat_whitespace(); + Self::eat_whitespace(tokenizer); Ok(node) } _ => { - self.paths(node) + Self::paths(node, tokenizer) } } } Ok(Token::Absolute(_)) => { - self.json_path() + Self::json_path(tokenizer) } Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => { - self.array_quota_value() + Self::array_quota_value(tokenizer) } Ok(Token::Key(_, k)) => { match k.chars().next() { Some(ch) => match ch { - '-' | '0'...'9' => self.term_num(), - _ => self.boolean() + '-' | '0'...'9' => Self::term_num(tokenizer), + _ => Self::boolean(tokenizer) } - _ => Err(self.tokenizer.err_msg()) + _ => Err(tokenizer.err_msg()) } } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } - fn op(&mut self, prev: Node) -> ParseResult { + fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { debug!("#op"); - let token = match self.tokenizer.next_token() { + let token = match tokenizer.next_token() { Ok(Token::Equal(_)) => { ParseToken::Filter(FilterToken::Equal) } @@ -599,41 +595,41 @@ impl<'a> Parser<'a> { ParseToken::Eof } _ => { - return Err(self.tokenizer.err_msg()); + return Err(tokenizer.err_msg()); } }; - self.eat_whitespace(); + Self::eat_whitespace(tokenizer); Ok(Node { token, left: Some(Box::new(prev)), - right: Some(Box::new(self.term()?)), + right: Some(Box::new(Self::term(tokenizer)?)), }) } - fn eat_whitespace(&mut self) { - while let Ok(Token::Whitespace(_, _)) = self.tokenizer.peek_token() { - let _ = self.tokenizer.next_token(); + fn eat_whitespace(tokenizer: &mut TokenReader) { + while let Ok(Token::Whitespace(_, _)) = tokenizer.peek_token() { + let _ = tokenizer.next_token(); } } - fn eat_token(&mut self) { - let _ = self.tokenizer.next_token(); + fn eat_token(tokenizer: &mut TokenReader) { + let _ = tokenizer.next_token(); } - fn node(&mut self, token: ParseToken) -> Node { - Node { left: None, right: None, token: token } + fn node(token: ParseToken) -> Node { + Node { left: None, right: None, token } } - fn close_token(&mut self, ret: Node, token: Token) -> ParseResult { + fn close_token(ret: Node, token: Token, tokenizer: &mut TokenReader) -> ParseResult { debug!("#close_token"); - match self.tokenizer.next_token() { + match tokenizer.next_token() { Ok(ref t) if t.partial_eq(token) => { Ok(ret) } _ => { - Err(self.tokenizer.err_msg()) + Err(tokenizer.err_msg()) } } } diff --git a/src/parser/tokenizer.rs b/src/parser/tokenizer.rs index 9090a06..4a777f2 100644 --- a/src/parser/tokenizer.rs +++ b/src/parser/tokenizer.rs @@ -275,7 +275,7 @@ impl<'a> Tokenizer<'a> { } } -pub struct PreloadedTokenizer<'a> { +pub struct TokenReader<'a> { origin_input: &'a str, err: TokenError, err_pos: usize, @@ -283,7 +283,7 @@ pub struct PreloadedTokenizer<'a> { curr_pos: Option, } -impl<'a> PreloadedTokenizer<'a> { +impl<'a> TokenReader<'a> { pub fn new(input: &'a str) -> Self { let mut tokenizer = Tokenizer::new(input); let mut tokens = vec![]; @@ -293,7 +293,7 @@ impl<'a> PreloadedTokenizer<'a> { tokens.insert(0, (tokenizer.current_pos(), t)); } Err(e) => { - return PreloadedTokenizer { + return TokenReader { origin_input: input.clone(), err: e, err_pos: tokenizer.current_pos(), diff --git a/src/select/mod.rs b/src/select/mod.rs index 07c4334..3faa073 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -508,8 +508,7 @@ impl<'a> Selector<'a> { pub fn path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { debug!("path : {}", path); - let mut parser = Parser::new(path); - self.node = Some(parser.compile().map_err(|e| JsonPathError::Path(e))?); + self.node = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?); Ok(self) } diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index ce1eefb..c184dc4 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -50,8 +50,7 @@ fn into_serde_json(js_value: &JsValue) -> Result #[wasm_bindgen] pub fn compile(path: &str) -> JsValue { - let mut parser = Parser::new(path); - let node = parser.compile(); + let node = Parser::compile(path); let cb = Closure::wrap(Box::new(move |js_value: JsValue| { let mut selector = _Selector::new(); @@ -85,8 +84,7 @@ pub fn selector(js_value: JsValue) -> JsValue { }; let cb = Closure::wrap(Box::new(move |path: String| { - let mut parser = Parser::new(path.as_str()); - match parser.compile() { + match Parser::compile(path.as_str()) { Ok(node) => { let mut selector = _Selector::new(); let _ = selector.compiled_path(node); From 9a08df7843ab0bfe8e6c2a2df90b0e9e14cb3eba Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 3 Jun 2019 21:41:08 +0900 Subject: [PATCH 07/15] re-indent --- src/select/mod.rs | 193 ++++++++++++++++++++-------------------------- 1 file changed, 85 insertions(+), 108 deletions(-) diff --git a/src/select/mod.rs b/src/select/mod.rs index 3faa073..a3b4c5a 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -247,73 +247,62 @@ impl<'a> ExprTerm<'a> { _ => ExprTerm::Bool(cmp_fn.default()) } ExprTerm::Json(fk1, vec1) if other.is_string() => { - match &other { - ExprTerm::String(s2) => { - let ret: Vec<&Value> = vec1.iter().filter(|v1| { - match v1 { - Value::String(s1) => cmp_fn.cmp_string(s1, s2), - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::String(s1)) = map1.get(k) { - return cmp_fn.cmp_string(s1, s2); - } - } - cmp_fn.default() - } - _ => cmp_fn.default() - } - }).map(|v| *v).collect(); + let s2 = if let ExprTerm::String(s2) = &other { s2 } else { unreachable!() }; - if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::String(s1) => cmp_fn.cmp_string(s1, s2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::String(s1)) = map1.get(k) { + return cmp_fn.cmp_string(s1, s2); + } + } + cmp_fn.default() + } + _ => cmp_fn.default() } - _ => unreachable!() - } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } } ExprTerm::Json(fk1, vec1) if other.is_number() => { - match &other { - ExprTerm::Number(n2) => { - let ret: Vec<&Value> = vec1.iter().filter(|v1| { - match v1 { - Value::Number(n1) => cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)), - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::Number(n1)) = map1.get(k) { - return cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)); - } - } - cmp_fn.default() + let n2 = if let ExprTerm::Number(n2) = &other { n2 } else { unreachable!() }; + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::Number(n1) => cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Number(n1)) = map1.get(k) { + return cmp_fn.cmp_f64(&to_f64(n1), &to_f64(n2)); } - _ => cmp_fn.default() } - }).map(|v| *v).collect(); - - if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + cmp_fn.default() + } + _ => cmp_fn.default() } - _ => unreachable!() - } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } } ExprTerm::Json(fk1, vec1) if other.is_bool() => { - match &other { - ExprTerm::Bool(b2) => { - let ret: Vec<&Value> = vec1.iter().filter(|v1| { - match v1 { - Value::Bool(b1) => cmp_fn.cmp_bool(b1, b2), - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::Bool(b1)) = map1.get(k) { - return cmp_fn.cmp_bool(b1, b2); - } - } - cmp_fn.default() + let b2 = if let ExprTerm::Bool(b2) = &other { b2 } else { unreachable!() }; + let ret: Vec<&Value> = vec1.iter().filter(|v1| { + match v1 { + Value::Bool(b1) => cmp_fn.cmp_bool(b1, b2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Bool(b1)) = map1.get(k) { + return cmp_fn.cmp_bool(b1, b2); } - _ => cmp_fn.default() } - }).map(|v| *v).collect(); - - if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } + cmp_fn.default() + } + _ => cmp_fn.default() } - _ => unreachable!() - } + }).map(|v| *v).collect(); + + if ret.is_empty() { ExprTerm::Bool(cmp_fn.default()) } else { ExprTerm::Json(None, ret) } } ExprTerm::Json(_, vec1) if other.is_json() => { match &other { @@ -395,23 +384,19 @@ impl<'a> ExprTerm<'a> { fn walk_all_with_str<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { if is_filter { - walk(vec, tmp, &|v| { - match v { - Value::Object(map) if map.contains_key(key) => { - Some(vec![v]) - } - _ => None + walk(vec, tmp, &|v| match v { + Value::Object(map) if map.contains_key(key) => { + Some(vec![v]) } + _ => None }); } else { - walk(vec, tmp, &|v| { - match v { - Value::Object(map) => match map.get(key) { - Some(v) => Some(vec![v]), - _ => None - } + walk(vec, tmp, &|v| match v { + Value::Object(map) => match map.get(key) { + Some(v) => Some(vec![v]), _ => None } + _ => None }); } } @@ -584,31 +569,29 @@ impl<'a> Selector<'a> { fn in_filter, &mut Vec<&'a Value>) -> FilterKey>(&mut self, fun: F) { match self.terms.pop() { - Some(peek) => { - match peek { - Some(v) => { - debug!("in_filter 1.: {:?}", v); + Some(peek) => match peek { + Some(v) => { + debug!("in_filter 1.: {:?}", v); - match v { - ExprTerm::Json(_, vec) => { - let mut tmp = Vec::new(); - let filter_key = fun(&vec, &mut tmp); - self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); - } - _ => unreachable!() - }; - } - _ => { - debug!("in_filter 2.: {:?}", &self.current); - - if let Some(current) = &self.current { + match v { + ExprTerm::Json(_, vec) => { let mut tmp = Vec::new(); - let filter_key = fun(current, &mut tmp); + let filter_key = fun(&vec, &mut tmp); self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); } + _ => unreachable!() + }; + } + _ => { + debug!("in_filter 2.: {:?}", &self.current); + + if let Some(current) = &self.current { + let mut tmp = Vec::new(); + let filter_key = fun(current, &mut tmp); + self.terms.push(Some(ExprTerm::Json(Some(filter_key), tmp))); } - }; - } + } + }, _ => {} } } @@ -922,8 +905,8 @@ impl<'a> NodeVisitor for Selector<'a> { if let Some(ParseToken::Array) = self.tokens.pop() { let mut tmp = Vec::new(); - for vec in &self.current { - for v in vec { + if let Some(current) = &self.current { + for v in current { if let Value::Array(vec) = v { let from = if let Some(from) = from { abs_index(from, vec.len()) @@ -945,7 +928,6 @@ impl<'a> NodeVisitor for Selector<'a> { } } } - self.current = Some(tmp); } else { unreachable!(); @@ -958,8 +940,8 @@ impl<'a> NodeVisitor for Selector<'a> { if let Some(ParseToken::Array) = self.tokens.pop() { let mut tmp = Vec::new(); - for vec in &self.current { - for v in vec { + if let Some(current) = &self.current { + for v in current { if let Value::Array(vec) = v { for i in indices { if let Some(v) = vec.get(abs_index(i, vec.len())) { @@ -982,20 +964,15 @@ impl<'a> NodeVisitor for Selector<'a> { } } +pub trait Modifiable { + fn delete_from_selected(&mut self, value: &mut Value); +} -//pub trait Transform<'a> { -// fn map(&mut self, mut fun: F) -> &mut Self where F: FnMut(&'a mut Value); -//} -// -//impl<'a> Transform<'a> for Selector<'a> { -// fn map(&mut self, mut fun: F) -> &mut Self where F: FnMut(&'a mut Value) { -// match &mut self.current { -// Some(current) => { -// current.iter_mut().for_each(|ref mut v| fun(v)) -// } -// _ => {} -// } -// -// self -// } -//} \ No newline at end of file +impl<'a> Modifiable for Selector<'a> { + fn delete_from_selected(&mut self, value: &mut Value) { + match &self.current { + Some(current) => {} + _ => {} + } + } +} \ No newline at end of file From dd9315bc90c8a50ffcba382c741c5ab7c3c0edf5 Mon Sep 17 00:00:00 2001 From: freestrings Date: Sun, 9 Jun 2019 22:55:35 +0900 Subject: [PATCH 08/15] SelectorMut first commit --- benches/bench.rs | 31 ++++++ benches/bench_example.rs | 2 +- src/lib.rs | 20 ++-- src/select/mod.rs | 199 +++++++++++++++++++++++++++++++++------ tests/common.rs | 2 +- tests/mutable.rs | 40 ++++++++ tests/readme.rs | 2 +- wasm/src/lib.rs | 4 +- 8 files changed, 254 insertions(+), 46 deletions(-) create mode 100644 tests/mutable.rs diff --git a/benches/bench.rs b/benches/bench.rs index 9a7f78c..3cc6b1c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -10,6 +10,8 @@ use std::io::Read; use serde::Deserialize; use serde_json::Value; +use jsonpath::{SelectorMut, Selector}; + use self::test::Bencher; fn read_json(path: &str) -> String { @@ -102,4 +104,33 @@ fn bench_select_as(b: &mut Bencher) { let _: Vec = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap(); } }); +} + +#[bench] +fn bench_delete(b: &mut Bencher) { + let json = get_json(); + let mut selector = SelectorMut::new(); + let _ = selector.str_path(get_path()); + + b.iter(move || { + for _ in 1..100 { + let _ = selector.value(json.clone()).delete(); + } + }); +} + +#[bench] +fn bench_select_to_compare_with_delete(b: &mut Bencher) { + let json = &get_json(); + + let mut selector = Selector::new(); + let _ = selector.str_path(get_path()); + let _ = selector.value(json); + + b.iter(move || { + for _ in 1..100 { + let _ = json.clone(); + let _ = selector.reset_value().select(); + } + }); } \ No newline at end of file diff --git a/benches/bench_example.rs b/benches/bench_example.rs index 3748ca7..1d00866 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -55,7 +55,7 @@ fn _selector(b: &mut Bencher, index: usize) { b.iter(move || { for _ in 1..100 { let mut selector = jsonpath::Selector::new(); - let _ = selector.path(get_path(index)); + let _ = selector.str_path(get_path(index)); selector.value(&json); let r = selector.select(); if r.is_err() { diff --git a/src/lib.rs b/src/lib.rs index 9c9dc74..236a3f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,23 +125,23 @@ extern crate array_tool; extern crate core; extern crate env_logger; -extern crate indexmap; #[macro_use] extern crate log; extern crate serde; extern crate serde_json; +extern crate indexmap; use serde_json::Value; +pub use parser::parser::{Node, Parser}; +pub use select::{Selector, SelectorMut}; +pub use select::JsonPathError; + #[doc(hidden)] mod parser; #[doc(hidden)] mod select; -pub use select::Selector; -pub use select::JsonPathError; -pub use parser::parser::{Node, Parser}; - /// 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 @@ -219,7 +219,7 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result(json: &Value) -> impl FnMut(& let mut selector = Selector::new(); let _ = selector.value(json); move |path: &str| { - selector.path(path)?.reset_value().select_as() + selector.str_path(path)?.reset_value().select_as() } } @@ -303,7 +303,7 @@ pub fn selector_as(json: &Value) -> impl FnMut(& /// ]); /// ``` pub fn select<'a>(json: &'a Value, path: &'a str) -> Result, JsonPathError> { - Selector::new().path(path)?.value(json).select() + Selector::new().str_path(path)?.value(json).select() } /// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string. @@ -331,7 +331,7 @@ pub fn select<'a>(json: &'a Value, path: &'a str) -> Result, Json /// ``` pub fn select_as_str(json_str: &str, path: &str) -> Result { let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?; - let ret = Selector::new().path(path)?.value(&json).select()?; + let ret = Selector::new().str_path(path)?.value(&json).select()?; serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string())) } @@ -375,5 +375,5 @@ pub fn select_as_str(json_str: &str, path: &str) -> Result(json_str: &str, path: &str) -> Result, JsonPathError> { let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?; - Selector::new().path(path)?.value(&json).select_as() + Selector::new().str_path(path)?.value(&json).select_as() } \ No newline at end of file diff --git a/src/select/mod.rs b/src/select/mod.rs index a3b4c5a..1888054 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,8 +1,10 @@ +use std::collections::HashSet; + use array_tool::vec::{Intersect, Union}; use serde_json::{Number, Value}; use parser::parser::*; -use std::collections::HashSet; +use indexmap::IndexSet; fn to_f64(n: &Number) -> f64 { if n.is_i64() { @@ -382,6 +384,21 @@ impl<'a> ExprTerm<'a> { } } +impl<'a> Into> for &Vec<&'a Value> { + fn into(self) -> ExprTerm<'a> { + if self.len() == 1 { + match &self[0] { + Value::Number(v) => return ExprTerm::Number(v.clone()), + Value::String(v) => return ExprTerm::String(v.clone()), + Value::Bool(v) => return ExprTerm::Bool(*v), + _ => {} + } + } + + ExprTerm::Json(None, self.to_vec()) + } +} + fn walk_all_with_str<'a>(vec: &Vec<&'a Value>, tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { if is_filter { walk(vec, tmp, &|v| match v { @@ -491,19 +508,19 @@ impl<'a> Selector<'a> { } } - pub fn path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { + pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { debug!("path : {}", path); self.node = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?); Ok(self) } - pub(crate) fn reset_value(&mut self) -> &mut Self { - self.current = None; + pub fn compiled_path(&mut self, node: Node) -> &mut Self { + self.node = Some(node); self } - pub fn compiled_path(&mut self, node: Node) -> &mut Self { - self.node = Some(node); + pub fn reset_value(&mut self) -> &mut Self { + self.current = None; self } @@ -733,19 +750,10 @@ impl<'a> NodeVisitor for Selector<'a> { if !self.selectors.is_empty() { match token { ParseToken::Absolute | ParseToken::Relative | ParseToken::Filter(_) => { - let s = self.selectors.pop().unwrap(); + let selector = self.selectors.pop().unwrap(); - if let Some(current) = &s.current { - let term = if current.len() == 1 { - match current[0] { - Value::Number(v) => ExprTerm::Number(v.clone()), - Value::String(v) => ExprTerm::String(v.clone()), - Value::Bool(v) => ExprTerm::Bool(*v), - _ => ExprTerm::Json(None, current.to_vec()) - } - } else { - ExprTerm::Json(None, current.to_vec()) - }; + if let Some(current) = &selector.current { + let term = current.into(); if let Some(s) = self.selectors.last_mut() { s.terms.push(Some(term)); @@ -760,19 +768,20 @@ impl<'a> NodeVisitor for Selector<'a> { } } - if let Some(s) = self.selectors.last_mut() { - s.visit_token(token); + if let Some(selector) = self.selectors.last_mut() { + selector.visit_token(token); return; } match token { ParseToken::Absolute => { if self.current.is_some() { - let mut s = Selector::new(); + let mut selector = Selector::new(); + if let Some(value) = self.value { - s.value = Some(value); - s.current = Some(vec![value]); - self.selectors.push(s); + selector.value = Some(value); + selector.current = Some(vec![value]); + self.selectors.push(selector); } return; } @@ -964,15 +973,143 @@ impl<'a> NodeVisitor for Selector<'a> { } } -pub trait Modifiable { - fn delete_from_selected(&mut self, value: &mut Value); +pub struct SelectorMut { + path: Option, + value: Option, } -impl<'a> Modifiable for Selector<'a> { - fn delete_from_selected(&mut self, value: &mut Value) { - match &self.current { - Some(current) => {} - _ => {} +impl SelectorMut { + pub fn new() -> Self { + SelectorMut { path: None, value: None } + } + + pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { + self.path = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?); + Ok(self) + } + + pub fn value(&mut self, value: Value) -> &mut Self { + self.value = Some(value); + self + } + + pub fn take(&mut self) -> Option { + self.value.take() + } + + fn compute_paths(&self, result: &Vec<&Value>) -> Vec> { + fn _walk(origin: &Value, target: &Value, tokens: &mut Vec, visited: &mut IndexSet>) -> bool { + if visited.contains(tokens) { + return false; + } + + if std::ptr::eq(origin, target) { + debug!("tokens: {:?}", tokens); + return true; + } + + match origin { + Value::Array(vec) => for (i, v) in vec.iter().enumerate() { + tokens.push(i.to_string()); + if _walk(v, target, tokens, visited) { + return true; + } + tokens.pop(); + }, + Value::Object(map) => for (k, v) in map { + tokens.push(k.clone()); + if _walk(v, target, tokens, visited) { + return true; + } + tokens.pop(); + } + _ => {} + } + + return false; + } + + let mut visited = IndexSet::new(); + + if let Some(origin) = &self.value { + for v in result { + let mut tokens = Vec::new(); + if _walk(origin, v, &mut tokens, &mut visited) { + visited.insert(tokens); + } + } + } + + visited.iter().map(|v| v.to_vec()).collect() + } + + pub fn delete(&mut self) -> Result<&mut Self, JsonPathError> { + self.replace_with(&mut |_| Value::Null) + } + + pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { + let mut selector = Selector::new(); + + if let Some(path) = self.path.take() { + selector.compiled_path(path); + } + + if let Some(value) = &self.value { + selector.value(value); + } + + let result = selector.select(); + + self.path = Some(selector.node.unwrap()); + + let paths = self.compute_paths(&result?); + + if let Some(mut value) = self.value.take() { + for tokens in paths { + self.replace_value(tokens, &mut value, fun); + } + self.value = Some(value); + } + + Ok(self) + } + + fn replace_value Value>(&mut self, tokens: Vec, value: &mut Value, fun: &mut F) { + let mut target = value; + + for (i, token) in tokens.iter().enumerate() { + let target_once = target; + let is_last = i == tokens.len() - 1; + let target_opt = match *target_once { + Value::Object(ref mut map) => { + if is_last { + if let Some(v) = map.remove(token) { + map.insert(token.clone(), fun(&v)); + return; + } + } + map.get_mut(token) + } + Value::Array(ref mut vec) => { + if let Ok(x) = token.parse::() { + if is_last { + let v = &vec[x]; + vec[x] = fun(v); + return; + } + vec.get_mut(x) + } else { + None + } + } + _ => None, + }; + + if let Some(t) = target_opt { + target = t; + } else { + break; + } } } } \ No newline at end of file diff --git a/tests/common.rs b/tests/common.rs index 98a04fe..ecd25c0 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -31,7 +31,7 @@ pub fn read_contents(path: &str) -> String { #[allow(dead_code)] pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) { let mut s = Selector::new(); - let _ = s.path(path); + let _ = s.str_path(path); let _ = s.value(&json); let result = serde_json::to_value(s.select().unwrap()).unwrap(); assert_eq!(result, target, "{}", path); diff --git a/tests/mutable.rs b/tests/mutable.rs new file mode 100644 index 0000000..b61fa07 --- /dev/null +++ b/tests/mutable.rs @@ -0,0 +1,40 @@ +extern crate jsonpath_lib as jsonpath; +#[macro_use] +extern crate serde_json; + +use common::{read_json, setup}; +use jsonpath::{SelectorMut, Selector}; +use serde_json::Value; + +mod common; + +#[test] +fn selector_mut() { + setup(); + + let mut selector_mut = SelectorMut::new(); + + let mut nums = Vec::new(); + let result = selector_mut + .str_path(r#"$.store..price"#).unwrap() + .value(read_json("./benches/example.json")) + .replace_with(&mut |v| { + match v { + Value::Number(n) => { + nums.push(n.as_f64().unwrap()); + } + _ => {} + } + Value::String("a".to_string()) + }).unwrap() + .take().unwrap(); + + assert_eq!(nums, vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]); + + let mut selector = Selector::new(); + let result = selector.str_path(r#"$.store..price"#).unwrap() + .value(&result) + .select().unwrap(); + + assert_eq!(vec![&json!("a"), &json!("a"), &json!("a"), &json!("a"), &json!("a")], result); +} \ No newline at end of file diff --git a/tests/readme.rs b/tests/readme.rs index dc47853..cb6e38e 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -151,7 +151,7 @@ fn readme_selector() { let mut selector = Selector::new(); let result = selector - .path("$..[?(@.age >= 30)]").unwrap() + .str_path("$..[?(@.age >= 30)]").unwrap() .value(&json_obj) .select().unwrap(); diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index c184dc4..1288afb 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -108,7 +108,7 @@ pub fn selector(js_value: JsValue) -> JsValue { #[wasm_bindgen] pub fn select(js_value: JsValue, path: &str) -> JsValue { let mut selector = _Selector::new(); - let _ = selector.path(path); + let _ = selector.str_path(path); let json = match into_serde_json(&js_value) { Ok(json) => json, @@ -160,7 +160,7 @@ impl Selector { let mut selector = _Selector::new(); if let Some(path) = &self.path { - let _ = selector.path(&path).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?; + let _ = selector.str_path(&path).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?; } else { return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath))); } From 24d18efb6f2d043560d480af1eed9ba90abaae2b Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 10 Jun 2019 14:48:29 +0900 Subject: [PATCH 09/15] SelectorMut documentation --- README.md | 114 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 120 ++++++++++++++++++++++++++++++++++++++++------ src/select/mod.rs | 5 ++ tests/readme.rs | 117 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 339 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 354369a..8aaa4fd 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,15 @@ It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine writte - [jsonpath_lib crate](#jsonpath_lib-crate) - [Rust - jsonpath::Selector struct](#rust---jsonpathselector-struct) +- [Rust - jsonpath::SelectorMut struct](#rust---jsonpathselectormut-struct) - [Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str) - [Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str) - [Rust - jsonpath::select_as\(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str) - [Rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str) - [Rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue) - [Rust - jsonpath::selector_as\(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue) +- [Rust - jsonpath::delete(value: &Value, path: &str)](#rust---jsonpathdeletevalue-value-path-str) +- [Rust - jsonpath::replace_with\ Value`\>(value: &Value, path: &str, fun: &mut F)](#rust---jsonpathreplace_withf-fnmutvalue---valuevalue-value-path-str-fun-mut-f) - [Rust - Other Examples](https://github.com/freestrings/jsonpath/wiki/rust-examples) ## Javascript API @@ -84,6 +87,50 @@ let result = selector.select_as::().unwrap(); assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); ``` +#### Rust - jsonpath::SelectorMut struct + +```rust +let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]}); + +let mut selector_mut = SelectorMut::new(); + +let result = selector_mut + .str_path("$..[?(@.age == 20)].age").unwrap() + .value(json_obj) + .replace_with(&mut |v| { + let age = if let Value::Number(n) = v { + n.as_u64().unwrap() * 2 + } else { + 0 + }; + + json!(age) + }).unwrap() + .take().unwrap(); + +assert_eq!(result, json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 40} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]})); +``` + #### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str) ```rust @@ -259,6 +306,73 @@ let ret = vec!( assert_eq!(json, ret); ``` +#### Rust - jsonpath::delete(value: &Value, path: &str) + +```rust +let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]}); + +let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap(); + +assert_eq!(ret, json!({ + "school": { + "friends": [ + null, + null + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]})); +``` + +#### Rust - jsonpath::replace_with\ Value`\>(value: &Value, path: &str, fun: &mut F) + +```rust +let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]}); + +let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| { + let age = if let Value::Number(n) = v { + n.as_u64().unwrap() * 2 + } else { + 0 + }; + + json!(age) +}).unwrap(); + +assert_eq!(ret, json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 40} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} +]})); +``` --- ### Javascript API diff --git a/src/lib.rs b/src/lib.rs index 236a3f9..cc9c12d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,11 +125,11 @@ extern crate array_tool; extern crate core; extern crate env_logger; +extern crate indexmap; #[macro_use] extern crate log; extern crate serde; extern crate serde_json; -extern crate indexmap; use serde_json::Value; @@ -142,13 +142,13 @@ mod parser; #[doc(hidden)] mod select; -/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects. +/// It is a high-order function. it compile a jsonpath and then returns a closure that has JSON as argument. if you need to reuse a jsonpath, it is good for performance. /// /// ```rust /// extern crate jsonpath_lib as jsonpath; /// #[macro_use] extern crate serde_json; /// -/// let mut template = jsonpath::compile("$..friends[0]"); +/// let mut first_firend = jsonpath::compile("$..friends[0]"); /// /// let json_obj = json!({ /// "school": { @@ -162,7 +162,7 @@ mod select; /// {"name": "친구4"} /// ]}); /// -/// let json = template(&json_obj).unwrap(); +/// let json = first_firend(&json_obj).unwrap(); /// /// assert_eq!(json, vec![ /// &json!({"name": "친구3", "age": 30}), @@ -172,16 +172,20 @@ mod select; pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPathError> { let node = Parser::compile(path); move |json| { - let mut selector = Selector::new(); match &node { - Ok(node) => selector.compiled_path(node.clone()), - Err(e) => return Err(JsonPathError::Path(e.clone())) - }; - selector.value(json).select() + Ok(node) => { + let mut selector = Selector::new(); + // + // TODO remove node.clone() + // + selector.compiled_path(node.clone()).value(json).select() + } + Err(e) => Err(JsonPathError::Path(e.clone())) + } } } -/// It is a high-order function that return a function. this return-function has a jsonpath as argument and return a serde_json::value::Value. so you can use different JsonPath for one JsonObject. +/// It is a high-order function. it returns a closure that has a jsonpath string as argument. you can use diffenent jsonpath for one JSON object. /// /// ```rust /// extern crate jsonpath_lib as jsonpath; @@ -223,7 +227,7 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result(json: &Value) -> impl FnMut(& } } -/// This function compile a jsonpath everytime and it convert `serde_json's Value` to `jsonpath's RefValue` everytime and then it return a `serde_json::value::Value`. +/// It is a simple select function. but it compile the jsonpath argument every time. /// /// ```rust /// extern crate jsonpath_lib as jsonpath; @@ -306,7 +310,7 @@ pub fn select<'a>(json: &'a Value, path: &'a str) -> Result, Json Selector::new().str_path(path)?.value(json).select() } -/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string. +/// It is the same to `select` function but it return the result as string. /// /// ```rust /// extern crate jsonpath_lib as jsonpath; @@ -335,7 +339,7 @@ pub fn select_as_str(json_str: &str, path: &str) -> Result Result(json_str: &str, path: &str) -> Result, JsonPathError> { let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?; Selector::new().str_path(path)?.value(&json).select_as() +} + +/// Delete(= replace with null) the JSON property using the jsonpath. +/// +/// ```rust +/// extern crate jsonpath_lib as jsonpath; +/// #[macro_use] extern crate serde_json; +/// +/// let json_obj = json!({ +/// "school": { +/// "friends": [ +/// {"name": "친구1", "age": 20}, +/// {"name": "친구2", "age": 20} +/// ] +/// }, +/// "friends": [ +/// {"name": "친구3", "age": 30}, +/// {"name": "친구4"} +/// ]}); +/// +/// let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap(); +/// +/// assert_eq!(ret, json!({ +/// "school": { +/// "friends": [ +/// null, +/// null +/// ] +/// }, +/// "friends": [ +/// {"name": "친구3", "age": 30}, +/// {"name": "친구4"} +/// ]})); +/// ``` +pub fn delete(value: Value, path: &str) -> Result { + let mut selector = SelectorMut::new(); + let ret = selector.str_path(path)?.value(value).delete()?.take().unwrap_or(Value::Null); + Ok(ret) +} + +/// Select JSON properties using a jsonpath and transform the result and then replace it. via closure that implements `FnMut` you can transform the selected results. +/// +/// ```rust +/// extern crate jsonpath_lib as jsonpath; +/// #[macro_use] extern crate serde_json; +/// +/// use serde_json::Value; +/// +/// let json_obj = json!({ +/// "school": { +/// "friends": [ +/// {"name": "친구1", "age": 20}, +/// {"name": "친구2", "age": 20} +/// ] +/// }, +/// "friends": [ +/// {"name": "친구3", "age": 30}, +/// {"name": "친구4"} +/// ]}); +/// +/// let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| { +/// let age = if let Value::Number(n) = v { +/// n.as_u64().unwrap() * 2 +/// } else { +/// 0 +/// }; +/// +/// json!(age) +/// }).unwrap(); +/// +/// assert_eq!(ret, json!({ +/// "school": { +/// "friends": [ +/// {"name": "친구1", "age": 40}, +/// {"name": "친구2", "age": 40} +/// ] +/// }, +/// "friends": [ +/// {"name": "친구3", "age": 30}, +/// {"name": "친구4"} +/// ]})); +/// ``` +pub fn replace_with(value: Value, path: &str, fun: &mut F) -> Result + where F: FnMut(&Value) -> Value +{ + let mut selector = SelectorMut::new(); + let ret = selector.str_path(path)?.value(value).replace_with(fun)?.take().unwrap_or(Value::Null); + Ok(ret) } \ No newline at end of file diff --git a/src/select/mod.rs b/src/select/mod.rs index 1888054..af57cb5 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -988,6 +988,11 @@ impl SelectorMut { Ok(self) } + pub fn compiled_path(&mut self, node: Node) -> &mut Self { + self.path = Some(node); + self + } + pub fn value(&mut self, value: Value) -> &mut Self { self.value = Some(value); self diff --git a/tests/readme.rs b/tests/readme.rs index cb6e38e..f328c79 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -4,8 +4,9 @@ extern crate serde; extern crate serde_json; use serde::Deserialize; +use serde_json::Value; -use jsonpath::Selector; +use jsonpath::{Selector, SelectorMut}; #[test] fn readme() { @@ -164,6 +165,49 @@ fn readme_selector() { assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); } +#[test] +fn readme_selector_mut() { + let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]}); + + let mut selector_mut = SelectorMut::new(); + + let result = selector_mut + .str_path("$..[?(@.age == 20)].age").unwrap() + .value(json_obj) + .replace_with(&mut |v| { + let age = if let Value::Number(n) = v { + n.as_u64().unwrap() * 2 + } else { + 0 + }; + + json!(age) + }).unwrap() + .take().unwrap(); + + assert_eq!(result, json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 40} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]})); +} + #[test] fn readme_select() { let json_obj = json!({ @@ -240,7 +284,7 @@ fn readme_select_as() { #[test] fn readme_compile() { - let mut template = jsonpath::compile("$..friends[0]"); + let mut first_firend = jsonpath::compile("$..friends[0]"); let json_obj = json!({ "school": { @@ -254,7 +298,7 @@ fn readme_compile() { {"name": "친구4"} ]}); - let json = template(&json_obj).unwrap(); + let json = first_firend(&json_obj).unwrap(); assert_eq!(json, vec![ &json!({"name": "친구3", "age": 30}), @@ -331,4 +375,71 @@ fn readme_selector_as() { ); assert_eq!(json, ret); +} + + +#[test] +fn readme_delete() { + let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]}); + + let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap(); + + assert_eq!(ret, json!({ + "school": { + "friends": [ + null, + null + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]})); +} + +#[test] +fn readme_replace_with() { + let json_obj = json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]}); + + let result = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| { + let age = if let Value::Number(n) = v { + n.as_u64().unwrap() * 2 + } else { + 0 + }; + + json!(age) + }).unwrap(); + + assert_eq!(result, json!({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 40} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ]})); } \ No newline at end of file From ec5d76d2d636dfc63bef3c94708692b64406adec Mon Sep 17 00:00:00 2001 From: freestrings Date: Mon, 10 Jun 2019 18:16:08 +0900 Subject: [PATCH 10/15] =?UTF-8?q?SelectorMut=20WASM=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-wasm.sh | 104 +++++ build.sh | 2 +- src/select/mod.rs | 12 +- tests/common.rs | 1 + tests/readme.rs | 22 ++ wasm/src/lib.rs | 172 ++++++++- wasm/tests/test/index.spec.js | 697 +++++++++++++++++++--------------- 7 files changed, 697 insertions(+), 313 deletions(-) create mode 100755 build-wasm.sh diff --git a/build-wasm.sh b/build-wasm.sh new file mode 100755 index 0000000..fe7039a --- /dev/null +++ b/build-wasm.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +set -e + +# project_root +DIR="$(pwd)" +WASM="${DIR}"/wasm +WASM_WWW="${WASM}"/www +WASM_WWW_BENCH="${WASM}"/www_bench +WASM_BROWSER_PKG="${WASM}"/browser_pkg +WASM_NODEJS_PKG="${WASM}"/nodejs_pkg +WASM_ALL_PKG="${WASM}"/all_pkg +WASM_TEST="${WASM}"/tests +DOCS="${DIR}"/docs +DOCS_BENCH="${DOCS}"/bench + +__msg () { + echo ">>>>>>>>>>$1<<<<<<<<<<" +} + +__cargo_clean () { + cd "${WASM}" && cargo clean && \ + cd "${DIR}" && cargo clean +} + +echo +__msg "clean wasm" +rm -rf \ + "${WASM_NODEJS_PKG}" \ + "${WASM_BROWSER_PKG}" \ + "${WASM_ALL_PKG}" \ + "${WASM_WWW}"/node_modules \ + "${WASM_WWW_BENCH}"/node_modules \ + "${WASM_WWW}"/dist \ + "${WASM_WWW_BENCH}"/dist \ + "${WASM_TEST}"/node_modules + +if [ "$1" = "all" ]; then + __msg "clean all wasm" + __cargo_clean +fi + +__msg "npm install: wasm" +cd "${WASM_WWW}" && npm install +__msg "npm install: wasm_bench" +cd "${WASM_WWW_BENCH}" && npm install +__msg "npm install: wasm test" +cd "${WASM_TEST}" && npm install + +echo +echo +__msg "wasm-pack" +cd "${WASM}" && \ + wasm-pack build --release --target=nodejs --out-dir "${WASM_NODEJS_PKG}" + +cd "${WASM}" && \ + wasm-pack build --release --target=browser --out-dir "${WASM_BROWSER_PKG}" +# && \ +# wasm-pack test --chrome --firefox --headless + +__msg "wasm npm packaging" +cp -r "${WASM_BROWSER_PKG}" "${WASM_ALL_PKG}/" && \ + sed "s/require[\(]'\.\/jsonpath_wasm_bg/require\('\.\/jsonpath_wasm_nodejs/" "${WASM_NODEJS_PKG}/jsonpath_wasm.js" \ + > "${WASM_ALL_PKG}/jsonpath_wasm_main.js" && \ + sed "s/require[\(]'\.\/jsonpath_wasm/require\('\.\/jsonpath_wasm_main/" "${WASM_NODEJS_PKG}/jsonpath_wasm_bg.js" \ + > "${WASM_ALL_PKG}/jsonpath_wasm_nodejs.js" && \ + jq ".files += [\"jsonpath_wasm_nodejs.js\"]" ${WASM_ALL_PKG}/package.json \ + | jq ".main = \"jsonpath_wasm_main.js\"" \ + | jq ".keywords += [\"jsonpath\", \"json\", \"webassembly\", \"parsing\", \"rust\"]" \ + > ${WASM_ALL_PKG}/temp.json && \ + mv -v "${WASM_ALL_PKG}/temp.json" "${WASM_ALL_PKG}/package.json" && \ + cd "${WASM_ALL_PKG}" && npm link + +echo +__msg "link" +cd "${WASM_WWW}" && \ + npm link jsonpath-wasm + +cd "${WASM_WWW_BENCH}" && \ + npm link jsonpath-wasm + +cd "${WASM_TEST}" && \ + npm link jsonpath-wasm + +echo +echo +__msg "wasm test" +cd "${WASM_TEST}" && npm test + +if [ "$1" = "all" ] || [ "$1" = "docs" ]; then + echo + __msg "docs" + cd "${WASM_WWW}" && \ + npm run build && + rm -f "${DOCS}"/*.js "${DOCS}"/*.wasm "${DOCS}"/*.html && \ + cp "${WASM_WWW}"/dist/*.* "${DOCS}"/ + + cd "${WASM_WWW_BENCH}" && \ + npm run build && + rm -f "${DOCS_BENCH}"/*.js "${DOCS_BENCH}"/*.wasm "${DOCS_BENCH}"/*.html && \ + cp "${WASM_WWW_BENCH}"/dist/*.* "${DOCS_BENCH}"/ +fi + +__msg "wasm done" \ No newline at end of file diff --git a/build.sh b/build.sh index 446fc36..70d0d7f 100755 --- a/build.sh +++ b/build.sh @@ -120,4 +120,4 @@ cd "${WASM_WWW_BENCH}" && \ rm -f "${DOCS_BENCH}"/*.js "${DOCS_BENCH}"/*.wasm "${DOCS_BENCH}"/*.html && \ cp "${WASM_WWW_BENCH}"/dist/*.* "${DOCS_BENCH}"/ -__msg "done" +__msg "done" \ No newline at end of file diff --git a/src/select/mod.rs b/src/select/mod.rs index af57cb5..e1581bd 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,10 +1,10 @@ use std::collections::HashSet; use array_tool::vec::{Intersect, Union}; +use indexmap::IndexSet; use serde_json::{Number, Value}; use parser::parser::*; -use indexmap::IndexSet; fn to_f64(n: &Number) -> f64 { if n.is_i64() { @@ -1088,10 +1088,14 @@ impl SelectorMut { let target_opt = match *target_once { Value::Object(ref mut map) => { if is_last { - if let Some(v) = map.remove(token) { - map.insert(token.clone(), fun(&v)); + let v = if let Some(v) = map.get(token) { + fun(v) + } else { return; - } + }; + + map.insert(token.clone(), v); + return; } map.get_mut(token) } diff --git a/tests/common.rs b/tests/common.rs index ecd25c0..a2884f7 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -8,6 +8,7 @@ use serde_json::Value; use self::jsonpath::Selector; +#[allow(dead_code)] pub fn setup() { let _ = env_logger::try_init(); } diff --git a/tests/readme.rs b/tests/readme.rs index f328c79..ef98673 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -8,6 +8,8 @@ use serde_json::Value; use jsonpath::{Selector, SelectorMut}; +mod common; + #[test] fn readme() { let json_obj = json!({ @@ -407,6 +409,26 @@ fn readme_delete() { ]})); } +#[test] +fn readme_delete2() { + let json_obj = common::read_json("./benches/example.json"); + + let ret = jsonpath::delete(json_obj, "$.store.book").unwrap(); + + println!("{:?}", ret); + + assert_eq!(ret, json!({ + "store": { + "book": null, + "bicycle": { + "color": "red", + "price": 19.95 + } + }, + "expensive": 10 + })); +} + #[test] fn readme_replace_with() { let json_obj = json!({ diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 1288afb..530827e 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,17 +1,14 @@ extern crate cfg_if; -extern crate core; extern crate js_sys; extern crate jsonpath_lib as jsonpath; -extern crate serde; extern crate serde_json; extern crate wasm_bindgen; -extern crate web_sys; use cfg_if::cfg_if; use jsonpath::{JsonPathError, Parser}; use jsonpath::Selector as _Selector; +use jsonpath::SelectorMut as _SelectorMut; use serde_json::Value; -use wasm_bindgen::*; use wasm_bindgen::prelude::*; cfg_if! { @@ -32,6 +29,16 @@ cfg_if! { } } +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn error(s: &str); +} + +macro_rules! console_error { + ($($t:tt)*) => (error(&format_args!($($t)*).to_string())) +} + fn into_serde_json(js_value: &JsValue) -> Result where D: for<'a> serde::de::Deserialize<'a> { @@ -48,6 +55,32 @@ fn into_serde_json(js_value: &JsValue) -> Result } } +fn replace_fun(v: &Value, fun: &js_sys::Function) -> Value { + match JsValue::from_serde(v) { + Ok(js_v) => { + match fun.call1(&JsValue::NULL, &js_v) { + Ok(result) => { + match into_serde_json(&result) { + Ok(json) => json, + Err(e) => { + console_error!("replace_with - closure returned a invalid JSON: {:?}", e); + Value::Null + } + } + } + Err(e) => { + console_error!("replace_with - fail to call closure: {:?}", e); + Value::Null + } + } + } + Err(e) => { + console_error!("replace_with - invalid JSON object: {:?}", e); + Value::Null + } + } +} + #[wasm_bindgen] pub fn compile(path: &str) -> JsValue { let node = Parser::compile(path); @@ -107,15 +140,46 @@ pub fn selector(js_value: JsValue) -> JsValue { #[wasm_bindgen] pub fn select(js_value: JsValue, path: &str) -> JsValue { - let mut selector = _Selector::new(); - let _ = selector.str_path(path); - let json = match into_serde_json(&js_value) { Ok(json) => json, Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) }; - match selector.value(&json).select() { + match jsonpath::select(&json, path) { + Ok(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => ret, + Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) + }, + Err(e) => JsValue::from_str(&format!("{:?}", e)) + } +} + +#[wasm_bindgen(catch, js_name = "deleteValue")] +pub fn delete(js_value: JsValue, path: &str) -> JsValue { + let json = match into_serde_json(&js_value) { + Ok(json) => json, + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) + }; + + match jsonpath::delete(json, path) { + Ok(ret) => { + match JsValue::from_serde(&ret) { + Ok(ret) => ret, + Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) + } + } + Err(e) => JsValue::from_str(&format!("{:?}", e)) + } +} + +#[wasm_bindgen(catch, js_name = "replaceWith")] +pub fn replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsValue { + let json = match into_serde_json(&js_value) { + Ok(json) => json, + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) + }; + + match jsonpath::replace_with(json, path, &mut |v| replace_fun(v, &fun)) { Ok(ret) => match JsValue::from_serde(&ret) { Ok(ret) => ret, Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))) @@ -179,4 +243,96 @@ impl Selector { Err(e) => Err(JsValue::from_str(&format!("{:?}", e))) } } +} + +/// +/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다. +/// +#[wasm_bindgen] +pub struct SelectorMut { + path: Option, + value: Option, +} + +#[wasm_bindgen] +impl SelectorMut { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + SelectorMut { path: None, value: None } + } + + #[wasm_bindgen(catch)] + pub fn path(&mut self, path: &str) -> Result<(), JsValue> { + self.path = Some(path.to_string()); + Ok(()) + } + + #[wasm_bindgen(catch)] + pub fn value(&mut self, value: JsValue) -> Result<(), JsValue> { + let json = into_serde_json(&value) + .map_err(|e| JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))))?; + self.value = Some(json); + Ok(()) + } + + #[wasm_bindgen(catch, js_name = "deleteValue")] + pub fn delete(&mut self) -> Result<(), JsValue> { + let mut selector = _SelectorMut::new(); + + if let Some(path) = &self.path { + let _ = selector.str_path(path); + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath))); + }; + + if let Some(value) = self.value.take() { + selector.value(value); + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue))); + }; + + match selector.delete() { + Err(e) => Err(JsValue::from_str(&format!("{:?}", e))), + _ => { + self.value = selector.take(); + Ok(()) + } + } + } + + #[wasm_bindgen(catch, js_name = replaceWith)] + pub fn replace_with(&mut self, fun: js_sys::Function) -> Result<(), JsValue> { + let mut selector = _SelectorMut::new(); + + if let Some(path) = &self.path { + let _ = selector.str_path(path); + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath))); + }; + + if let Some(value) = self.value.take() { + selector.value(value); + } else { + return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue))); + }; + + match selector.replace_with(&mut |v| replace_fun(v, &fun)) { + Err(e) => Err(JsValue::from_str(&format!("{:?}", e))), + _ => { + self.value = selector.take(); + Ok(()) + } + } + } + + #[wasm_bindgen(catch)] + pub fn take(&mut self) -> Result { + match self.value.take() { + Some(ret) => match JsValue::from_serde(&ret) { + Ok(ret) => Ok(ret), + Err(e) => Err(JsValue::from_str(&format!("{:?}", e))) + }, + None => Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue))) + } + } } \ No newline at end of file diff --git a/wasm/tests/test/index.spec.js b/wasm/tests/test/index.spec.js index 8af3495..c17bcbd 100644 --- a/wasm/tests/test/index.spec.js +++ b/wasm/tests/test/index.spec.js @@ -1,358 +1,358 @@ const jsonpath = require('jsonpath-wasm'); let jsonObj = { - "store": { - "book": [ + 'store': { + 'book': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], - "bicycle": { - "color": "red", - "price": 19.95 - } + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, }, - "expensive": 10 + 'expensive': 10, }; let list = { '$.store.book[*].author': [ - "Nigel Rees", - "Evelyn Waugh", - "Herman Melville", - "J. R. R. Tolkien" + 'Nigel Rees', + 'Evelyn Waugh', + 'Herman Melville', + 'J. R. R. Tolkien', ], - '$..author':[ - "Nigel Rees", - "Evelyn Waugh", - "Herman Melville", - "J. R. R. Tolkien" + '$..author': [ + 'Nigel Rees', + 'Evelyn Waugh', + 'Herman Melville', + 'J. R. R. Tolkien', ], '$.store.*': [ [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], { - "color": "red", - "price": 19.95 - } + 'color': 'red', + 'price': 19.95, + }, ], - '$.store..price':[ + '$.store..price': [ 8.95, 12.99, 8.99, 22.99, - 19.95 + 19.95, ], '$..book[2]': [ { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 - } + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, + }, ], '$..book[-2]': [ { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 - } + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, + }, ], '$..book[0,1]': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 - } + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, + }, ], '$..book[:2]': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 - } + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, + }, ], '$..book[1:2]': [ { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 - } + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, + }, ], '$..book[-2:]': [ { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], '$..book[2:]': [ { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], '$..book[?(@.isbn)]': [ { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], '$.store.book[?(@.price < 10)]': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 - } + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, + }, ], '$..*': [ { - "book": [ + 'book': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], - "bicycle": { - "color": "red", - "price": 19.95 - } + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, }, 10, [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 - } + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, + }, ], { - "color": "red", - "price": 19.95 + 'color': 'red', + 'price': 19.95, }, { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99 + 'category': 'fiction', + 'author': 'Evelyn Waugh', + 'title': 'Sword of Honour', + 'price': 12.99, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, }, { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99 + 'category': 'fiction', + 'author': 'J. R. R. Tolkien', + 'title': 'The Lord of the Rings', + 'isbn': '0-395-19395-8', + 'price': 22.99, }, - "reference", - "Nigel Rees", - "Sayings of the Century", + 'reference', + 'Nigel Rees', + 'Sayings of the Century', 8.95, - "fiction", - "Evelyn Waugh", - "Sword of Honour", + 'fiction', + 'Evelyn Waugh', + 'Sword of Honour', 12.99, - "fiction", - "Herman Melville", - "Moby Dick", - "0-553-21311-3", + 'fiction', + 'Herman Melville', + 'Moby Dick', + '0-553-21311-3', 8.99, - "fiction", - "J. R. R. Tolkien", - "The Lord of the Rings", - "0-395-19395-8", + 'fiction', + 'J. R. R. Tolkien', + 'The Lord of the Rings', + '0-395-19395-8', 22.99, - "red", - 19.95 + 'red', + 19.95, ], '$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]': [ { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95 + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 8.95, }, { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99 - } - ] + 'category': 'fiction', + 'author': 'Herman Melville', + 'title': 'Moby Dick', + 'isbn': '0-553-21311-3', + 'price': 8.99, + }, + ], }; describe('compile test', () => { @@ -393,34 +393,132 @@ describe('filter test', () => { } } - for( var i in list ) { + for (var i in list) { it(i, (done) => { - run (done, i, list[i]); - }) + run(done, i, list[i]); + }); } it('object equal', (done) => { let selector = new jsonpath.Selector(); selector.path('$..[?(@.a == 1)]'); selector.value({ - "a": 1, - "b" : {"a": 1}, - "c" : {"a": 1} + 'a': 1, + 'b': {'a': 1}, + 'c': {'a': 1}, }); let result = selector.select(); - if (JSON.stringify(result) === JSON.stringify([ {"a": 1}, {"a": 1} ])) { + if (JSON.stringify(result) === JSON.stringify([{'a': 1}, {'a': 1}])) { done(); } }); }); +describe('SelectorMut test', () => { + it('delete', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let result = jsonpath.deleteValue(jsonObjNew, '$.store.book'); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': null, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); + + it('replaceWith', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let result = jsonpath.replaceWith(jsonObjNew, '$.store.book', (v) => { + let ret = v[0]; + ret.price = 9; + return ret; + }); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': { + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 9, + }, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); + + it('SeletorMut delete', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let selector = new jsonpath.SelectorMut(); + selector.path('$.store.book'); + selector.value(jsonObjNew); + selector.deleteValue(); + + let result = selector.take(); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': null, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }) + + it('SeletorMut replaceWith', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let selector = new jsonpath.SelectorMut(); + selector.path('$.store.book'); + selector.value(jsonObjNew); + selector.replaceWith((v) => { + let ret = v[0]; + ret.price = 9; + return ret; + }); + + let result = selector.take(); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': { + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 9, + }, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }) +}); + describe('Selector test', () => { it('select', (done) => { let selector = new jsonpath.Selector(); selector.value(jsonObj); - for(var i in list) { + for (var i in list) { selector.path(i); - if(JSON.stringify(list[i]) !== JSON.stringify(selector.select())) { + if (JSON.stringify(list[i]) !== JSON.stringify(selector.select())) { throw `fail: ${i}`; } } @@ -431,16 +529,16 @@ describe('Selector test', () => { describe('README test', () => { it('jsonpath.Selector', (done) => { let jsonObj = { - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], }; let selector = new jsonpath.Selector(); @@ -449,8 +547,8 @@ describe('README test', () => { { selector.path('$..[?(@.age >= 30)]'); let jsonObj = selector.select(); - let resultObj = [{"name": "친구3", "age": 30}]; - if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { + let resultObj = [{'name': '친구3', 'age': 30}]; + if (JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 30)]'; } } @@ -458,17 +556,17 @@ describe('README test', () => { { selector.path('$..[?(@.age == 20)]'); let jsonObj = selector.select(); - let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}]; - if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { + let resultObj = [{'name': '친구1', 'age': 20}, {'name': '친구2', 'age': 20}]; + if (JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: $..[?(@.age >= 20)]'; } } { - selector.value({"friends": [ {"name": "친구5", "age": 20} ]}); + selector.value({'friends': [{'name': '친구5', 'age': 20}]}); let jsonObj = selector.select(); - let resultObj = [{"name": "친구5", "age": 20}]; - if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { + let resultObj = [{'name': '친구5', 'age': 20}]; + if (JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { throw 'jsonpath.Selector: change value'; } } @@ -478,28 +576,27 @@ describe('README test', () => { it('jsonpath.select(json: string|object, jsonpath: string)', (done) => { let jsonObj = { - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], }; let ret = [ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + {'name': '친구3', 'age': 30}, + {'name': '친구1', 'age': 20}, ]; - let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]'); let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]'); - if( + if ( JSON.stringify(ret) !== JSON.stringify(selectAsString) || JSON.stringify(ret) !== JSON.stringify(selectAsObj) ) { @@ -513,27 +610,27 @@ describe('README test', () => { let template = jsonpath.compile('$..friends[0]'); let jsonObj = { - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], }; let ret = [ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + {'name': '친구3', 'age': 30}, + {'name': '친구1', 'age': 20}, ]; let selectAsString = template(JSON.stringify(jsonObj)); let selectAsObj = template(jsonObj); - if( + if ( JSON.stringify(ret) !== JSON.stringify(selectAsString) || JSON.stringify(ret) !== JSON.stringify(selectAsObj) ) { @@ -541,24 +638,24 @@ describe('README test', () => { } let jsonObj2 = { - "school": { - "friends": [ - {"name": "Millicent Norman"}, - {"name": "Vincent Cannon"} - ] + 'school': { + 'friends': [ + {'name': 'Millicent Norman'}, + {'name': 'Vincent Cannon'}, + ], }, - "friends": [ {"age": 30}, {"age": 40} ] + 'friends': [{'age': 30}, {'age': 40}], }; let ret2 = [ - {"age": 30}, - {"name": "Millicent Norman"} + {'age': 30}, + {'name': 'Millicent Norman'}, ]; let selectAsString2 = template(JSON.stringify(jsonObj2)); let selectAsObj2 = template(jsonObj2); - if( + if ( JSON.stringify(ret2) !== JSON.stringify(selectAsString2) || JSON.stringify(ret2) !== JSON.stringify(selectAsObj2) ) { @@ -570,33 +667,33 @@ describe('README test', () => { it('jsonpath.selector(json: string|object)', (done) => { let jsonObj = { - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], }; let ret1 = [ - {"name": "친구3", "age": 30}, - {"name": "친구1", "age": 20} + {'name': '친구3', 'age': 30}, + {'name': '친구1', 'age': 20}, ]; let ret2 = [ - {"name": "친구4"}, - {"name": "친구2", "age": 20} + {'name': '친구4'}, + {'name': '친구2', 'age': 20}, ]; let selector = jsonpath.selector(jsonObj); let select1 = selector('$..friends[0]'); let select2 = selector('$..friends[1]'); - if( + if ( JSON.stringify(ret1) !== JSON.stringify(select1) || JSON.stringify(ret2) !== JSON.stringify(select2) ) { From e096e62dbf84efddc9192db040924a6bd8dc90e3 Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 00:02:05 +0900 Subject: [PATCH 11/15] =?UTF-8?q?SelectorMut=20NodeJs=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nodejs/lib/index.js | 94 ++++++++++++++++++++++++++++++++++++++- nodejs/native/src/lib.rs | 71 +++++++++++++++++++++++++++++ nodejs/test/index.spec.js | 94 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+), 2 deletions(-) diff --git a/nodejs/lib/index.js b/nodejs/lib/index.js index 68e0122..5a6eb82 100644 --- a/nodejs/lib/index.js +++ b/nodejs/lib/index.js @@ -1,4 +1,12 @@ -const { CompileFn, SelectorFn, selectStr, Selector: _Selector } = require('../native'); +const { + CompileFn, + SelectorFn, + selectStr, + deleteValue: _deleteValue, + replaceWith: _replaceWith, + Selector: _Selector, + SelectorMut: _SelectorMut +} = require('../native'); function compile(path) { let compile = new CompileFn(path); @@ -27,6 +35,30 @@ function select(json, path) { return JSON.parse(selectStr(json, path)); } +function deleteValue(json, path) { + if(typeof json != 'string') { + json = JSON.stringify(json) + } + return JSON.parse(_deleteValue(json, path)); +} + +function replaceWith(json, path, fun) { + if(typeof json != 'string') { + json = JSON.stringify(json) + } + let result = _replaceWith(json, path, (v) => { + let result = fun(JSON.parse(v)); + if(typeof result != 'string') { + result = JSON.stringify(result) + } + return result; + }); + if(typeof result == 'string') { + result = JSON.parse(result); + } + return result; +} + class Selector { constructor() { this._selector = new _Selector(); @@ -51,9 +83,67 @@ class Selector { } } +class SelectorMut { + constructor() { + return this; + } + + path(path) { + this.path = path; + return this; + } + + value(json) { + if(typeof json != 'string') { + json = JSON.stringify(json) + } + this.json = json; + return this; + } + + deleteValue() { + let selector = new _SelectorMut(); + if(!this.path) { + selector.emptyPathError(); + return; + } + + if(!this.json) { + selector.emptyValueError(); + return; + } + + this.json = deleteValue(this.json, this.path); + return this; + } + + replaceWith(fun) { + let selector = new _SelectorMut(); + if(!this.path) { + selector.emptyPathError(); + return; + } + if(!this.json) { + selector.emptyValueError(); + return; + } + this.json = replaceWith(this.json, this.path, fun); + return this; + } + + take() { + let json = this.json; + delete this.json; + return json; + } +} + module.exports = { compile, selector, select, - Selector + deleteValue, + replaceWith, + Selector, + SelectorMut }; \ No newline at end of file diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index cb5b494..befb227 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -31,6 +31,58 @@ fn select_str(mut ctx: FunctionContext) -> JsResult { } } +fn delete(mut ctx: FunctionContext) -> JsResult { + let json_val = ctx.argument::(0)?.value(); + let json: Value = match serde_json::from_str(&json_val) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }; + let path = ctx.argument::(1)?.value(); + match jsonpath::delete(json, &path) { + Ok(value) => Ok(JsString::new(&mut ctx, match serde_json::to_string(&value) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }).upcast()), + Err(e) => panic!("{:?}", e) + } +} + +fn replace_with(mut ctx: FunctionContext) -> JsResult { + let json_val = ctx.argument::(0)?.value(); + let json: Value = match serde_json::from_str(&json_val) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }; + let path = ctx.argument::(1)?.value(); + let fun = ctx.argument::(2)?; + match jsonpath::replace_with(json, &path, &mut |v| { + let json_str = JsString::new(&mut ctx, match serde_json::to_string(v) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }); + + let null = ctx.null(); + let args = vec![ctx.string(json_str.value())]; + let result = match fun.call(&mut ctx, null, args) { + Ok(result) => result, + Err(e) => panic!("{:?}", e) + }; + let json_str = match result.downcast::() { + Ok(v) => v.value(), + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }; + match serde_json::from_str(&json_str) { + Ok(v) => v, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + } + }) { + Ok(value) => Ok(JsString::new(&mut ctx, match serde_json::to_string(&value) { + Ok(value) => value, + Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string())) + }).upcast()), + Err(e) => panic!("{:?}", e) + } +} pub struct SelectorCls { node: Option, @@ -77,6 +129,8 @@ impl SelectorCls { } } +pub struct SelectorMutCls {} + declare_types! { pub class JsCompileFn for SelectorCls { init(mut ctx) { @@ -187,12 +241,29 @@ declare_types! { Ok(JsString::new(&mut ctx, &result_str).upcast()) } } + + pub class JsSelectorMut for SelectorMutCls { + init(mut _ctx) { + Ok(SelectorMutCls {}) + } + + method emptyPathError(mut _ctx) { + panic!("{:?}", JsonPathError::EmptyPath); + } + + method emptyValueError(mut _ctx) { + panic!("{:?}", JsonPathError::EmptyValue); + } + } } register_module!(mut m, { m.export_class::("CompileFn").expect("CompileFn class error"); m.export_class::("SelectorFn").expect("SelectorFn class error"); m.export_class::("Selector").expect("Selector class error"); + m.export_class::("SelectorMut").expect("SelectorMut class error"); m.export_function("select", select)?; + m.export_function("deleteValue", delete)?; + m.export_function("replaceWith", replace_with)?; m.export_function("selectStr", select_str)?; Ok(()) }); \ No newline at end of file diff --git a/nodejs/test/index.spec.js b/nodejs/test/index.spec.js index e4d50ba..7e5fa61 100644 --- a/nodejs/test/index.spec.js +++ b/nodejs/test/index.spec.js @@ -400,6 +400,100 @@ describe('filter test', () => { } }); +describe('SelectorMut test', () => { + it('delete', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let result = jsonpath.deleteValue(jsonObjNew, '$.store.book'); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': null, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); + + it('replaceWith', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let result = jsonpath.replaceWith(jsonObjNew, '$.store.book', (v) => { + let ret = v[0]; + ret.price = 9; + return ret; + }); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': { + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 9, + }, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); + + it('SeletorMut delete', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let selector = new jsonpath.SelectorMut(); + selector.path('$.store.book').value(jsonObjNew).deleteValue(); + + let result = selector.take(); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': null, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); + + it('SeletorMut replaceWith', (done) => { + let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); + let selector = new jsonpath.SelectorMut(); + selector.path('$.store.book').value(jsonObjNew).replaceWith((v) => { + let ret = v[0]; + ret.price = 9; + return ret; + }); + + let result = selector.take(); + if (JSON.stringify(result) === JSON.stringify({ + 'store': { + 'book': { + 'category': 'reference', + 'author': 'Nigel Rees', + 'title': 'Sayings of the Century', + 'price': 9, + }, + 'bicycle': { + 'color': 'red', + 'price': 19.95, + }, + }, + 'expensive': 10, + })) { + done(); + } + }); +}); + describe('Selector test', () => { it('select', (done) => { let selector = new jsonpath.Selector().value(jsonObj); From fbb2b49ba0d75e737d58596b227126a0040777ee Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 12:14:12 +0900 Subject: [PATCH 12/15] update READEME.md --- README.md | 249 +++++++++++++++++++++++++++------- nodejs/lib/index.js | 20 +-- nodejs/native/Cargo.toml | 3 +- nodejs/test/index.spec.js | 118 ++++++++++++++++ tests/mutable.rs | 25 ++++ wasm/tests/test/index.spec.js | 123 ++++++++++++++++- 6 files changed, 476 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 8aaa4fd..8855383 100644 --- a/README.md +++ b/README.md @@ -15,42 +15,17 @@ It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine writte ## Rust API -- [jsonpath_lib crate](#jsonpath_lib-crate) -- [Rust - jsonpath::Selector struct](#rust---jsonpathselector-struct) -- [Rust - jsonpath::SelectorMut struct](#rust---jsonpathselectormut-struct) -- [Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str) -- [Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str) -- [Rust - jsonpath::select_as\(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str) -- [Rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str) -- [Rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue) -- [Rust - jsonpath::selector_as\(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue) -- [Rust - jsonpath::delete(value: &Value, path: &str)](#rust---jsonpathdeletevalue-value-path-str) -- [Rust - jsonpath::replace_with\ Value`\>(value: &Value, path: &str, fun: &mut F)](#rust---jsonpathreplace_withf-fnmutvalue---valuevalue-value-path-str-fun-mut-f) -- [Rust - Other Examples](https://github.com/freestrings/jsonpath/wiki/rust-examples) +
jsonpath_lib crate -## Javascript API - -- [npm package](#npm-package) -- [Javascript - jsonpath.Selector class](#javascript---selector-class) -- [Javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string) -- [Javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string) -- [Javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject) -- [Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples) - ---- - -### Rust API - -#### jsonpath_lib crate -[Go to creates.io](https://crates.io/crates/jsonpath_lib) +Go to [`jsonpath_lib` creates.io](https://crates.io/crates/jsonpath_lib) ```rust extern crate jsonpath_lib as jsonpath; -#[macro_use] -extern crate serde_json; ``` -#### Rust - jsonpath::Selector struct +
+ +
Rust - jsonpath::Selector struct ```rust #[derive(Deserialize, PartialEq, Debug)] @@ -87,7 +62,9 @@ let result = selector.select_as::().unwrap(); assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); ``` -#### Rust - jsonpath::SelectorMut struct +
+ +
Rust - jsonpath::SelectorMut struct ```rust let json_obj = json!({ @@ -131,7 +108,9 @@ assert_eq!(result, json!({ ]})); ``` -#### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str) +
+ +
Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str) ```rust let json_obj = json!({ @@ -154,7 +133,10 @@ assert_eq!(json, vec![ ]); ``` -#### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str) +
+ + +
Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str) ```rust let ret = jsonpath::select_as_str(r#" @@ -175,7 +157,9 @@ let ret = jsonpath::select_as_str(r#" assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#); ``` -#### Rust - jsonpath::select_as\(json: &str, jsonpath: &str) +
+ +
Rust - jsonpath::select_as<T: `serde::de::DeserializeOwned`>(json_str: &str, jsonpath: &str) ```rust #[derive(Deserialize, PartialEq, Debug)] @@ -208,7 +192,9 @@ let person = Person { assert_eq!(ret[0], person); ``` -#### Rust - jsonpath::compile(jsonpath: &str) +
+ +
Rust - jsonpath::compile(jsonpath: &str) ```rust let mut template = jsonpath::compile("$..friends[0]"); @@ -233,7 +219,9 @@ assert_eq!(json, vec![ ]); ``` -#### Rust - jsonpath::selector(json: &serde_json::value::Value) +
+ +
Rust - jsonpath::selector(json: &serde_json::value::Value) ```rust let json_obj = json!({ @@ -265,7 +253,9 @@ assert_eq!(json, vec![ ]); ``` -#### Rust - jsonpath::selector_as\(json: &serde_json::value::Value) +
+ +
Rust - jsonpath::selector_as<T: serde::de::DeserializeOwned>(json: &serde_json::value::Value) ```rust let json_obj = json!({ @@ -306,7 +296,9 @@ let ret = vec!( assert_eq!(json, ret); ``` -#### Rust - jsonpath::delete(value: &Value, path: &str) +
+ +
Rust - jsonpath::delete(value: &Value, path: &str) ```rust let json_obj = json!({ @@ -336,7 +328,9 @@ assert_eq!(ret, json!({ ]})); ``` -#### Rust - jsonpath::replace_with\ Value`\>(value: &Value, path: &str, fun: &mut F) +
+ +
Rust - jsonpath::replace_with<F: FnMut(&Value) -> Value>(value: &Value, path: &str, fun: &mut F) ```rust let json_obj = json!({ @@ -373,14 +367,19 @@ assert_eq!(ret, json!({ {"name": "친구4"} ]})); ``` ---- -### Javascript API +
-#### npm package +[Rust - Other Examples](https://github.com/freestrings/jsonpath/wiki/rust-examples) + +## Javascript API + +
npm package ##### jsonpath-wasm +Goto [`jsonpath-wasm` npmjs.org](https://www.npmjs.com/package/jsonpath-wasm) + ```javascript // browser import * as jsonpath from "jsonpath-wasm"; @@ -390,13 +389,15 @@ const jsonpath = require('jsonpath-wasm'); ##### jsonpath-rs (NodeJS only) -[Goto npmjs.org](https://www.npmjs.com/package/jsonpath-rs) +Goto [`jsonpath-rs` npmjs.org](https://www.npmjs.com/package/jsonpath-rs) ```javascript const jsonpath = require('jsonpath-rs'); ``` -#### javascript - Selector class +
+ +
Javascript - jsonpath.Selector class ##### jsonpath-wasm `wasm-bindgen` 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다. @@ -465,7 +466,75 @@ console.log(JSON.stringify(ret) == JSON.stringify(retObj)); // => true ``` -#### Javascript - jsonpath.select(json: string|object, jsonpath: string) +
+ +
Javascript - jsonpath.SelectorMut class + +`since 0.2.0` + +빌더 패턴 제약은 `Selector class`와 동일하다. + +```javascript +let jsonObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], +}; + +let selector = new jsonpath.SelectorMut(); +selector.path('$..[?(@.age == 20)]'); + +{ + selector.value(jsonObj); + selector.deleteValue(); + + let resultObj = { + 'school': {'friends': [null, null]}, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj)); + + // => true +} + +{ + selector.value(jsonObj); + selector.replaceWith((v) => { + v.age = v.age * 2; + return v; + }); + + let resultObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 40}, + {'name': '친구2', 'age': 40}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj)); + + // => true +} +``` + +
+ +
Javascript - jsonpath.select(json: string|object, jsonpath: string) ```javascript let jsonObj = { @@ -498,7 +567,9 @@ console.log( // => true, true ``` -#### Javascript - jsonpath.compile(jsonpath: string) +
+ +
Javascript - jsonpath.compile(jsonpath: string) ```javascript let template = jsonpath.compile('$..friends[0]'); @@ -557,8 +628,10 @@ console.log( // => true, true ``` -#### Javascript - jsonpath.selector(json: string|object) - +
+ +
Javascript - jsonpath.selector(json: string|object) + ```javascript let jsonObj = { "school": { @@ -596,4 +669,82 @@ console.log( ); // => true, true -``` \ No newline at end of file +``` + +
+ +
Javascript - jsonpath.deleteValue(json: string|object, path: string) + +`since 0.2.0` + +```javascript +let jsonObj = { + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ] +}; + +let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]'); +let result = jsonpath.deleteValue(_1, '$..friends[1]'); + +console.log(JSON.stringify(result) !== JSON.stringify({ + "school": { "friends": [null, null]}, + "friends": [null, null] +})); + +// => true + +``` + +
+ +
Javascript - jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object + +`since 0.2.0` + +```javascript +let jsonObj = { + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ] +}; + +let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => { + v.age = v.age * 2; + return v; +}); + +console.log(JSON.stringify(result) === JSON.stringify({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 60}, + {"name": "친구4"} + ] +})); + +// => true + +``` + +
+ +[Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples) \ No newline at end of file diff --git a/nodejs/lib/index.js b/nodejs/lib/index.js index 5a6eb82..bf962f7 100644 --- a/nodejs/lib/index.js +++ b/nodejs/lib/index.js @@ -89,7 +89,7 @@ class SelectorMut { } path(path) { - this.path = path; + this._path = path; return this; } @@ -97,43 +97,43 @@ class SelectorMut { if(typeof json != 'string') { json = JSON.stringify(json) } - this.json = json; + this._json = json; return this; } deleteValue() { let selector = new _SelectorMut(); - if(!this.path) { + if(!this._path) { selector.emptyPathError(); return; } - if(!this.json) { + if(!this._json) { selector.emptyValueError(); return; } - this.json = deleteValue(this.json, this.path); + this._json = deleteValue(this._json, this._path); return this; } replaceWith(fun) { let selector = new _SelectorMut(); - if(!this.path) { + if(!this._path) { selector.emptyPathError(); return; } - if(!this.json) { + if(!this._json) { selector.emptyValueError(); return; } - this.json = replaceWith(this.json, this.path, fun); + this._json = replaceWith(this._json, this._path, fun); return this; } take() { - let json = this.json; - delete this.json; + let json = this._json; + delete this._json; return json; } } diff --git a/nodejs/native/Cargo.toml b/nodejs/native/Cargo.toml index 9b0f1ce..071e68d 100644 --- a/nodejs/native/Cargo.toml +++ b/nodejs/native/Cargo.toml @@ -14,7 +14,8 @@ exclude = ["artifacts.json", "index.node"] neon-build = "0.2.0" [dependencies] -jsonpath_lib = "0.2.0" +#jsonpath_lib = "0.2.0" +jsonpath_lib = {path="../../"} neon = "0.2.0" neon-serde = "0.1.1" serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/nodejs/test/index.spec.js b/nodejs/test/index.spec.js index 7e5fa61..c948aae 100644 --- a/nodejs/test/index.spec.js +++ b/nodejs/test/index.spec.js @@ -550,6 +550,64 @@ describe('README test', () => { done(); }); + it('jsonpath.SelectorMut', (done) => { + let jsonObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + + let selector = new jsonpath.SelectorMut(); + selector.path('$..[?(@.age == 20)]'); + + { + selector.value(jsonObj).deleteValue(); + + let resultObj = { + 'school': {'friends': [null, null]}, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) { + throw 'jsonpath.SelectorMut.deleteValue'; + } + } + + { + selector.value(jsonObj).replaceWith((v) => { + v.age = v.age * 2; + return v; + }); + + let resultObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 40}, + {'name': '친구2', 'age': 40}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) { + throw 'jsonpath.SelectorMut.replaceWith'; + } + } + + done(); + }); + it('jsonpath.select(json: string|object, jsonpath: string)', (done) => { let jsonObj = { "school": { @@ -679,4 +737,64 @@ describe('README test', () => { done(); }); + + it('jsonpath.deleteValue(json: string|object, path: string)', (done) => { + let jsonObj = { + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ] + }; + + let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]'); + let result = jsonpath.deleteValue(_1, '$..friends[1]'); + + if(JSON.stringify(result) === JSON.stringify({ + "school": { "friends": [null, null]}, + "friends": [null, null] + })) { + done(); + } + }); + + it('jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object', (done) => { + let jsonObj = { + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ] + }; + + let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => { + v.age = v.age * 2; + return v; + }); + + if(JSON.stringify(result) === JSON.stringify({ + "school": { + "friends": [ + {"name": "친구1", "age": 40}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 60}, + {"name": "친구4"} + ] + })) { + done(); + } + }); }); \ No newline at end of file diff --git a/tests/mutable.rs b/tests/mutable.rs index b61fa07..d67e424 100644 --- a/tests/mutable.rs +++ b/tests/mutable.rs @@ -37,4 +37,29 @@ fn selector_mut() { .select().unwrap(); assert_eq!(vec![&json!("a"), &json!("a"), &json!("a"), &json!("a"), &json!("a")], result); +} + +#[test] +fn selector_mut_delete_array() { + setup(); + + let json = serde_json::from_str(r#"{ + "school": { + "friends": [ + {"name": "친구1", "age": 20}, + {"name": "친구2", "age": 20} + ] + }, + "friends": [ + {"name": "친구3", "age": 30}, + {"name": "친구4"} + ] + }"#).unwrap(); + + let json1 = jsonpath::delete(json, "$..friends[0]").unwrap(); + + println!("{:?}", json1); + + let mut json2 = jsonpath::delete(json1, "$..friends[1]").unwrap(); + } \ No newline at end of file diff --git a/wasm/tests/test/index.spec.js b/wasm/tests/test/index.spec.js index c17bcbd..97d7dc7 100644 --- a/wasm/tests/test/index.spec.js +++ b/wasm/tests/test/index.spec.js @@ -478,7 +478,7 @@ describe('SelectorMut test', () => { })) { done(); } - }) + }); it('SeletorMut replaceWith', (done) => { let jsonObjNew = JSON.parse(JSON.stringify(jsonObj)); @@ -509,7 +509,7 @@ describe('SelectorMut test', () => { })) { done(); } - }) + }); }); describe('Selector test', () => { @@ -574,6 +574,65 @@ describe('README test', () => { done(); }); + it('jsonpath.SelectorMut', (done) => { + let jsonObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + + let selector = new jsonpath.SelectorMut(); + selector.path('$..[?(@.age == 20)]'); + { + selector.value(jsonObj); + selector.deleteValue(); + + let resultObj = { + 'school': {'friends': [null, null]}, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) { + throw 'jsonpath.SelectorMut.deleteValue'; + } + } + + { + selector.value(jsonObj); + selector.replaceWith((v) => { + v.age = v.age * 2; + return v; + }); + + let resultObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 40}, + {'name': '친구2', 'age': 40}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) { + throw 'jsonpath.SelectorMut.replaceWith'; + } + } + + done(); + }); + it('jsonpath.select(json: string|object, jsonpath: string)', (done) => { let jsonObj = { 'school': { @@ -702,4 +761,64 @@ describe('README test', () => { done(); }); + + it('jsonpath.deleteValue(json: string|object, path: string)', (done) => { + let jsonObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + + let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]'); + let result = jsonpath.deleteValue(_1, '$..friends[1]'); + + if (JSON.stringify(result) === JSON.stringify({ + 'school': {'friends': [null, null]}, + 'friends': [null, null], + })) { + done(); + } + }); + + it('jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object', (done) => { + let jsonObj = { + 'school': { + 'friends': [ + {'name': '친구1', 'age': 20}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 30}, + {'name': '친구4'}, + ], + }; + + let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => { + v.age = v.age * 2; + return v; + }); + + if (JSON.stringify(result) === JSON.stringify({ + 'school': { + 'friends': [ + {'name': '친구1', 'age': 40}, + {'name': '친구2', 'age': 20}, + ], + }, + 'friends': [ + {'name': '친구3', 'age': 60}, + {'name': '친구4'}, + ], + })) { + done(); + } + }); }); \ No newline at end of file From 2e9e0ac6fcc90f95f9a821dcbdfe6fde84926aca Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 16:12:40 +0900 Subject: [PATCH 13/15] =?UTF-8?q?compiled=5Fpath=20=EC=9D=B8=EC=9E=90=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD,=20compute=5Fpath=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benches/bench.rs | 7 +-- nodejs/native/Cargo.toml | 4 +- nodejs/native/src/lib.rs | 4 +- src/lib.rs | 7 +-- src/select/mod.rs | 101 +++++++++++++++++++++++++-------------- tests/mutable.rs | 25 ---------- wasm/src/lib.rs | 4 +- 7 files changed, 78 insertions(+), 74 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 3cc6b1c..27b1a37 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -125,12 +125,13 @@ fn bench_select_to_compare_with_delete(b: &mut Bencher) { let mut selector = Selector::new(); let _ = selector.str_path(get_path()); - let _ = selector.value(json); b.iter(move || { for _ in 1..100 { - let _ = json.clone(); - let _ = selector.reset_value().select(); + let json = json.clone(); + let mut s = Selector::new(); + let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json); + let _ = s.select(); } }); } \ No newline at end of file diff --git a/nodejs/native/Cargo.toml b/nodejs/native/Cargo.toml index 071e68d..2c52d00 100644 --- a/nodejs/native/Cargo.toml +++ b/nodejs/native/Cargo.toml @@ -14,8 +14,8 @@ exclude = ["artifacts.json", "index.node"] neon-build = "0.2.0" [dependencies] -#jsonpath_lib = "0.2.0" -jsonpath_lib = {path="../../"} +jsonpath_lib = "0.2.0" +#jsonpath_lib = { path = "../../" } neon = "0.2.0" neon-serde = "0.1.1" serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index befb227..eb77863 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -110,7 +110,7 @@ impl SelectorCls { fn select(&self) -> String { let node = match &self.node { - Some(node) => node.clone(), + Some(node) => node, None => panic!("{:?}", JsonPathError::EmptyPath) }; @@ -120,7 +120,7 @@ impl SelectorCls { }; let mut selector = Selector::new(); - selector.compiled_path(node.clone()); + selector.compiled_path(node); selector.value(&value); match selector.select_as_str() { Ok(ret) => ret, diff --git a/src/lib.rs b/src/lib.rs index cc9c12d..7b5c5b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,12 +175,9 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPath match &node { Ok(node) => { let mut selector = Selector::new(); - // - // TODO remove node.clone() - // - selector.compiled_path(node.clone()).value(json).select() + selector.compiled_path(node).value(json).select() } - Err(e) => Err(JsonPathError::Path(e.clone())) + Err(e) => Err(JsonPathError::Path(e.to_string())) } } } diff --git a/src/select/mod.rs b/src/select/mod.rs index e1581bd..ab4ec93 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use array_tool::vec::{Intersect, Union}; -use indexmap::IndexSet; +use indexmap::IndexMap; use serde_json::{Number, Value}; use parser::parser::*; @@ -487,19 +487,21 @@ pub enum JsonPathError { } #[derive(Debug)] -pub struct Selector<'a> { +pub struct Selector<'a, 'b> { node: Option, + node_ref: Option<&'b Node>, value: Option<&'a Value>, tokens: Vec, terms: Vec>>, current: Option>, - selectors: Vec>, + selectors: Vec>, } -impl<'a> Selector<'a> { +impl<'a, 'b> Selector<'a, 'b> { pub fn new() -> Self { Selector { node: None, + node_ref: None, value: None, tokens: Vec::new(), terms: Vec::new(), @@ -510,12 +512,29 @@ impl<'a> Selector<'a> { pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { debug!("path : {}", path); + + if self.node_ref.is_some() { + self.node_ref.take(); + } + self.node = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?); Ok(self) } - pub fn compiled_path(&mut self, node: Node) -> &mut Self { - self.node = Some(node); + pub fn node_ref(&self) -> Option<&Node> { + if let Some(node) = &self.node { + Some(node) + } else { + None + } + } + + pub fn compiled_path(&mut self, node: &'b Node) -> &mut Self { + if self.node.is_some() { + self.node.take(); + } + + self.node_ref = Some(node); self } @@ -530,14 +549,21 @@ impl<'a> Selector<'a> { } fn _select(&mut self) -> Result<(), JsonPathError> { - match self.node.take() { - Some(node) => { - self.visit(&node); - self.node = Some(node); - Ok(()) - } - _ => Err(JsonPathError::EmptyPath) + if self.node_ref.is_some() { + let node_ref = self.node_ref.take().unwrap(); + self.visit(node_ref); + return Ok(()); } + + if self.node.is_none() { + return Err(JsonPathError::EmptyPath); + } + + let node = self.node.take().unwrap(); + self.visit(&node); + self.node = Some(node); + + Ok(()) } pub fn select_as(&mut self) -> Result, JsonPathError> { @@ -743,7 +769,7 @@ impl<'a> Selector<'a> { } } -impl<'a> NodeVisitor for Selector<'a> { +impl<'a, 'b> NodeVisitor for Selector<'a, 'b> { fn visit_token(&mut self, token: &ParseToken) { debug!("token: {:?}, stack: {:?}", token, self.tokens); @@ -1002,17 +1028,23 @@ impl SelectorMut { self.value.take() } - fn compute_paths(&self, result: &Vec<&Value>) -> Vec> { - fn _walk(origin: &Value, target: &Value, tokens: &mut Vec, visited: &mut IndexSet>) -> bool { - if visited.contains(tokens) { - return false; - } + fn compute_paths(&self, mut result: Vec<&Value>) -> Vec> { + fn _walk(origin: &Value, target: &mut Vec<&Value>, tokens: &mut Vec, visited: &mut IndexMap<*const Value, Vec>) -> bool { + trace!("{:?}, {:?}", target, tokens); - if std::ptr::eq(origin, target) { - debug!("tokens: {:?}", tokens); + if target.is_empty() { return true; } + target.retain(|t| { + if std::ptr::eq(origin, *t) { + visited.insert(*t, tokens.to_vec()); + false + } else { + true + } + }); + match origin { Value::Array(vec) => for (i, v) in vec.iter().enumerate() { tokens.push(i.to_string()); @@ -1034,18 +1066,14 @@ impl SelectorMut { return false; } - let mut visited = IndexSet::new(); + let mut visited = IndexMap::new(); if let Some(origin) = &self.value { - for v in result { - let mut tokens = Vec::new(); - if _walk(origin, v, &mut tokens, &mut visited) { - visited.insert(tokens); - } - } + let mut tokens = Vec::new(); + _walk(origin, &mut result, &mut tokens, &mut visited); } - visited.iter().map(|v| v.to_vec()).collect() + visited.iter().map(|(_, v)| v.to_vec()).collect() } pub fn delete(&mut self) -> Result<&mut Self, JsonPathError> { @@ -1053,21 +1081,24 @@ impl SelectorMut { } pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { - let mut selector = Selector::new(); - - if let Some(path) = self.path.take() { - selector.compiled_path(path); + if self.path.is_none() { + return Err(JsonPathError::EmptyPath); } + let node = self.path.take().unwrap(); + + let mut selector = Selector::new(); + selector.compiled_path(&node); + if let Some(value) = &self.value { selector.value(value); } let result = selector.select(); - self.path = Some(selector.node.unwrap()); + self.path = Some(node); - let paths = self.compute_paths(&result?); + let paths = self.compute_paths(result?); if let Some(mut value) = self.value.take() { for tokens in paths { diff --git a/tests/mutable.rs b/tests/mutable.rs index d67e424..b61fa07 100644 --- a/tests/mutable.rs +++ b/tests/mutable.rs @@ -37,29 +37,4 @@ fn selector_mut() { .select().unwrap(); assert_eq!(vec![&json!("a"), &json!("a"), &json!("a"), &json!("a"), &json!("a")], result); -} - -#[test] -fn selector_mut_delete_array() { - setup(); - - let json = serde_json::from_str(r#"{ - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] - }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] - }"#).unwrap(); - - let json1 = jsonpath::delete(json, "$..friends[0]").unwrap(); - - println!("{:?}", json1); - - let mut json2 = jsonpath::delete(json1, "$..friends[1]").unwrap(); - } \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 530827e..f21c7ea 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -88,7 +88,7 @@ pub fn compile(path: &str) -> JsValue { let cb = Closure::wrap(Box::new(move |js_value: JsValue| { let mut selector = _Selector::new(); match &node { - Ok(node) => selector.compiled_path(node.clone()), + Ok(node) => selector.compiled_path(node), Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) }; let json = match into_serde_json(&js_value) { @@ -120,7 +120,7 @@ pub fn selector(js_value: JsValue) -> JsValue { match Parser::compile(path.as_str()) { Ok(node) => { let mut selector = _Selector::new(); - let _ = selector.compiled_path(node); + let _ = selector.compiled_path(&node); match selector.value(&json).select() { Ok(ret) => match JsValue::from_serde(&ret) { Ok(ret) => ret, From 766be8cab2edebde48e821344710e383f7dd1319 Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 18:40:18 +0900 Subject: [PATCH 14/15] =?UTF-8?q?Stable=20=EB=B2=84=EC=A0=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=BB=B4=ED=8C=8C=EC=9D=BC=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benches/bench_example.rs | 1 - src/parser/parser.rs | 66 +++++++++++-------- src/parser/tokenizer.rs | 57 +++++++++------- src/select/mod.rs | 137 +++++++++++++++++++-------------------- wasm/src/lib.rs | 13 ++-- 5 files changed, 146 insertions(+), 128 deletions(-) diff --git a/benches/bench_example.rs b/benches/bench_example.rs index 1d00866..dd77bca 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -1,5 +1,4 @@ #![feature(test)] - extern crate bencher; extern crate jsonpath_lib as jsonpath; extern crate serde; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 253252f..4c76103 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -76,7 +76,6 @@ pub struct Node { pub struct Parser; impl Parser { - pub fn compile(input: &str) -> ParseResult { let mut tokenizer = TokenReader::new(input); Ok(Self::json_path(&mut tokenizer)?) @@ -531,43 +530,54 @@ impl Parser { } } + fn peek_key(tokenizer: &mut TokenReader) -> Option { + if let Ok(Token::Key(_, k)) = tokenizer.peek_token() { + Some(k.clone()) + } else { + None + } + } + fn term(tokenizer: &mut TokenReader) -> ParseResult { debug!("#term"); - match tokenizer.peek_token() { - Ok(Token::At(_)) => { - Self::eat_token(tokenizer); - let node = Self::node(ParseToken::Relative); - match tokenizer.peek_token() { - Ok(Token::Whitespace(_, _)) => { - Self::eat_whitespace(tokenizer); - Ok(node) - } - _ => { - Self::paths(node, tokenizer) - } + if tokenizer.peek_is(AT) { + Self::eat_token(tokenizer); + let node = Self::node(ParseToken::Relative); + + return match tokenizer.peek_token() { + Ok(Token::Whitespace(_, _)) => { + Self::eat_whitespace(tokenizer); + Ok(node) } - } - Ok(Token::Absolute(_)) => { - Self::json_path(tokenizer) - } - Ok(Token::DoubleQuoted(_, _)) - | Ok(Token::SingleQuoted(_, _)) => { - Self::array_quota_value(tokenizer) - } - Ok(Token::Key(_, k)) => { - match k.chars().next() { + _ => { + Self::paths(node, tokenizer) + } + }; + } + + if tokenizer.peek_is(ABSOLUTE) { + return Self::json_path(tokenizer); + } + + if tokenizer.peek_is(DOUBLE_QUOTA) || tokenizer.peek_is(SINGLE_QUOTA) { + return Self::array_quota_value(tokenizer); + } + + if tokenizer.peek_is(KEY) { + return match Self::peek_key(tokenizer) { + Some(key) => match key.chars().next() { Some(ch) => match ch { '-' | '0'...'9' => Self::term_num(tokenizer), _ => Self::boolean(tokenizer) } _ => Err(tokenizer.err_msg()) - } - } - _ => { - Err(tokenizer.err_msg()) - } + }, + _ => Err(tokenizer.err_msg()) + }; } + + return Err(tokenizer.err_msg()); } fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { diff --git a/src/parser/tokenizer.rs b/src/parser/tokenizer.rs index 4a777f2..23a3ac7 100644 --- a/src/parser/tokenizer.rs +++ b/src/parser/tokenizer.rs @@ -3,29 +3,29 @@ use std::result::Result; use super::path_reader::{PathReader, ReaderError}; -const ABSOLUTE: &'static str = "$"; -const DOT: &'static str = "."; -const AT: &'static str = "@"; -const OPEN_ARRAY: &'static str = "["; -const CLOSE_ARRAY: &'static str = "]"; -const ASTERISK: &'static str = "*"; -const QUESTION: &'static str = "?"; -const COMMA: &'static str = ","; -const SPLIT: &'static str = ":"; -const OPEN_PARENTHESIS: &'static str = "("; -const CLOSE_PARENTHESIS: &'static str = ")"; -const KEY: &'static str = "Key"; -const DOUBLE_QUOTA: &'static str = "\""; -const SINGLE_QUOTA: &'static str = "'"; -const EQUAL: &'static str = "=="; -const GREATER_OR_EQUAL: &'static str = ">="; -const GREATER: &'static str = ">"; -const LITTLE: &'static str = "<"; -const LITTLE_OR_EQUAL: &'static str = "<="; -const NOT_EQUAL: &'static str = "!="; -const AND: &'static str = "&&"; -const OR: &'static str = "||"; -const WHITESPACE: &'static str = " "; +pub const ABSOLUTE: &'static str = "$"; +pub const DOT: &'static str = "."; +pub const AT: &'static str = "@"; +pub const OPEN_ARRAY: &'static str = "["; +pub const CLOSE_ARRAY: &'static str = "]"; +pub const ASTERISK: &'static str = "*"; +pub const QUESTION: &'static str = "?"; +pub const COMMA: &'static str = ","; +pub const SPLIT: &'static str = ":"; +pub const OPEN_PARENTHESIS: &'static str = "("; +pub const CLOSE_PARENTHESIS: &'static str = ")"; +pub const KEY: &'static str = "Key"; +pub const DOUBLE_QUOTA: &'static str = "\""; +pub const SINGLE_QUOTA: &'static str = "'"; +pub const EQUAL: &'static str = "=="; +pub const GREATER_OR_EQUAL: &'static str = ">="; +pub const GREATER: &'static str = ">"; +pub const LITTLE: &'static str = "<"; +pub const LITTLE_OR_EQUAL: &'static str = "<="; +pub const NOT_EQUAL: &'static str = "!="; +pub const AND: &'static str = "&&"; +pub const OR: &'static str = "||"; +pub const WHITESPACE: &'static str = " "; const CH_DOLLA: char = '$'; const CH_DOT: char = '.'; @@ -91,6 +91,10 @@ impl Token { self.to_simple() == other.to_simple() } + pub fn simple_eq(&self, str_token: &str) -> bool { + self.to_simple() == str_token + } + fn to_simple(&self) -> &'static str { match self { Token::Absolute(_) => ABSOLUTE, @@ -305,6 +309,13 @@ impl<'a> TokenReader<'a> { } } + pub fn peek_is(&self, simple_token: &str) -> bool { + match self.peek_token() { + Ok(t) => t.simple_eq(simple_token), + _ => false + } + } + pub fn peek_token(&self) -> Result<&Token, TokenError> { match self.tokens.last() { Some((_, t)) => { diff --git a/src/select/mod.rs b/src/select/mod.rs index ab4ec93..f2b19ea 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1004,6 +1004,49 @@ pub struct SelectorMut { value: Option, } +fn replace_value Value>(tokens: Vec, value: &mut Value, fun: &mut F) { + let mut target = value; + + for (i, token) in tokens.iter().enumerate() { + let target_once = target; + let is_last = i == tokens.len() - 1; + let target_opt = match *target_once { + Value::Object(ref mut map) => { + if is_last { + let v = if let Some(v) = map.get(token) { + fun(v) + } else { + return; + }; + + map.insert(token.clone(), v); + return; + } + map.get_mut(token) + } + Value::Array(ref mut vec) => { + if let Ok(x) = token.parse::() { + if is_last { + let v = { fun(&vec[x]) }; + vec[x] = v; + return; + } + vec.get_mut(x) + } else { + None + } + } + _ => None, + }; + + if let Some(t) = target_opt { + target = t; + } else { + break; + } + } +} + impl SelectorMut { pub fn new() -> Self { SelectorMut { path: None, value: None } @@ -1014,11 +1057,6 @@ impl SelectorMut { Ok(self) } - pub fn compiled_path(&mut self, node: Node) -> &mut Self { - self.path = Some(node); - self - } - pub fn value(&mut self, value: Value) -> &mut Self { self.value = Some(value); self @@ -1080,76 +1118,33 @@ impl SelectorMut { self.replace_with(&mut |_| Value::Null) } - pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { - if self.path.is_none() { - return Err(JsonPathError::EmptyPath); - } + fn select(&self) -> Result, JsonPathError> { + if let Some(node) = &self.path { + let mut selector = Selector::new(); + selector.compiled_path(&node); - let node = self.path.take().unwrap(); - - let mut selector = Selector::new(); - selector.compiled_path(&node); - - if let Some(value) = &self.value { - selector.value(value); - } - - let result = selector.select(); - - self.path = Some(node); - - let paths = self.compute_paths(result?); - - if let Some(mut value) = self.value.take() { - for tokens in paths { - self.replace_value(tokens, &mut value, fun); + if let Some(value) = &self.value { + selector.value(value); + } + + Ok(selector.select()?) + } else { + Err(JsonPathError::EmptyPath) + } + } + + pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { + let paths = { + let result = self.select()?; + self.compute_paths(result) + }; + + if let Some(ref mut value) = &mut self.value { + for tokens in paths { + replace_value(tokens, value, fun); } - self.value = Some(value); } Ok(self) } - - fn replace_value Value>(&mut self, tokens: Vec, value: &mut Value, fun: &mut F) { - let mut target = value; - - for (i, token) in tokens.iter().enumerate() { - let target_once = target; - let is_last = i == tokens.len() - 1; - let target_opt = match *target_once { - Value::Object(ref mut map) => { - if is_last { - let v = if let Some(v) = map.get(token) { - fun(v) - } else { - return; - }; - - map.insert(token.clone(), v); - return; - } - map.get_mut(token) - } - Value::Array(ref mut vec) => { - if let Ok(x) = token.parse::() { - if is_last { - let v = &vec[x]; - vec[x] = fun(v); - return; - } - vec.get_mut(x) - } else { - None - } - } - _ => None, - }; - - if let Some(t) = target_opt { - target = t; - } else { - break; - } - } - } } \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index f21c7ea..25abf1c 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -86,15 +86,18 @@ pub fn compile(path: &str) -> JsValue { let node = Parser::compile(path); let cb = Closure::wrap(Box::new(move |js_value: JsValue| { - let mut selector = _Selector::new(); - match &node { - Ok(node) => selector.compiled_path(node), - Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) - }; let json = match into_serde_json(&js_value) { Ok(json) => json, Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) }; + + let mut selector = _Selector::new(); + + match &node { + Ok(node) => selector.compiled_path(node), + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) + }; + match selector.value(&json).select() { Ok(ret) => match JsValue::from_serde(&ret) { Ok(ret) => ret, From 4af31947f5d0dcd36e5b107872088f7bf9eca2ef Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 18:47:26 +0900 Subject: [PATCH 15/15] =?UTF-8?q?0.2.0=20=EB=B0=B0=ED=8F=AC=20=EC=A0=84?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20nodejs=20=EB=B9=8C=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 76 ++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7234633..d1724f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,41 +36,41 @@ matrix: script: - cargo build --verbose --all - cargo test --verbose --all - - language: node_js - os: linux - node_js: - - '11' - - '10' - - '9' - - '8' - before_install: - - curl https://sh.rustup.rs -sSf > /tmp/rustup.sh - - sh /tmp/rustup.sh -y - - export PATH="$HOME/.cargo/bin:$PATH" - - source "$HOME/.cargo/env" - - npm install -g neon-cli - - cd nodejs - - node -v - - npm -v - - npm install - script: - - npm test - - language: node_js - os: osx - node_js: - - '11' - - '10' - - '9' - - '8' - before_install: - - curl https://sh.rustup.rs -sSf > /tmp/rustup.sh - - sh /tmp/rustup.sh -y - - export PATH="$HOME/.cargo/bin:$PATH" - - source "$HOME/.cargo/env" - - npm install -g neon-cli - - cd nodejs - - node -v - - npm -v - - npm install - script: - - npm test \ No newline at end of file +# - language: node_js +# os: linux +# node_js: +# - '11' +# - '10' +# - '9' +# - '8' +# before_install: +# - curl https://sh.rustup.rs -sSf > /tmp/rustup.sh +# - sh /tmp/rustup.sh -y +# - export PATH="$HOME/.cargo/bin:$PATH" +# - source "$HOME/.cargo/env" +# - npm install -g neon-cli +# - cd nodejs +# - node -v +# - npm -v +# - npm install +# script: +# - npm test +# - language: node_js +# os: osx +# node_js: +# - '11' +# - '10' +# - '9' +# - '8' +# before_install: +# - curl https://sh.rustup.rs -sSf > /tmp/rustup.sh +# - sh /tmp/rustup.sh -y +# - export PATH="$HOME/.cargo/bin:$PATH" +# - source "$HOME/.cargo/env" +# - npm install -g neon-cli +# - cd nodejs +# - node -v +# - npm -v +# - npm install +# script: +# - npm test \ No newline at end of file