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. ///