fix nodejs

This commit is contained in:
freestrings 2019-06-03 13:50:44 +09:00
parent 56a22674bf
commit 498f2ce4f4
6 changed files with 129 additions and 259 deletions

101
README.md
View File

@ -50,7 +50,7 @@ extern crate serde_json;
#### Rust - jsonpath::Selector struct #### Rust - jsonpath::Selector struct
```rust ```rust
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Deserialize, PartialEq, Debug)]
struct Friend { struct Friend {
name: String, name: String,
age: Option<u8>, age: Option<u8>,
@ -72,43 +72,16 @@ let mut selector = Selector::new();
let result = selector let result = selector
.path("$..[?(@.age >= 30)]").unwrap() .path("$..[?(@.age >= 30)]").unwrap()
// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap() .value(&json_obj)
// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap() .select().unwrap();
.value(&json_obj /*serde_json::value::Value*/).unwrap()
.select_as_value().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(); let result = selector.select_as_str().unwrap();
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result); assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
let result = selector.select_as::<Vec<Friend>>().unwrap(); let result = selector.select_as::<Friend>().unwrap();
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result); 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<Friend>| {
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::<Vec<Friend>>().unwrap());
``` ```
#### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str) #### 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 json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
let ret = json!([ assert_eq!(json, vec![
{"name": "친구3", "age": 30}, &json!({"name": "친구3", "age": 30}),
{"name": "친구1", "age": 20} &json!({"name": "친구1", "age": 20})
]); ]);
assert_eq!(json, ret);
``` ```
#### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str) #### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str)
@ -166,7 +138,7 @@ struct Person {
phones: Vec<String>, phones: Vec<String>,
} }
let ret: Person = jsonpath::select_as(r#" let ret: Vec<Person> = jsonpath::select_as(r#"
{ {
"person": "person":
{ {
@ -186,7 +158,7 @@ let person = Person {
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()], phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
}; };
assert_eq!(person, ret); assert_eq!(ret[0], person);
``` ```
#### Rust - jsonpath::compile(jsonpath: &str) #### Rust - jsonpath::compile(jsonpath: &str)
@ -208,12 +180,10 @@ let json_obj = json!({
let json = template(&json_obj).unwrap(); let json = template(&json_obj).unwrap();
let ret = json!([ assert_eq!(json, vec![
{"name": "친구3", "age": 30}, &json!({"name": "친구3", "age": 30}),
{"name": "친구1", "age": 20} &json!({"name": "친구1", "age": 20})
]); ]);
assert_eq!(json, ret);
``` ```
#### Rust - jsonpath::selector(json: &serde_json::value::Value) #### 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 json = selector("$..friends[0]").unwrap();
let ret = json!([ assert_eq!(json, vec![
{"name": "친구3", "age": 30}, &json!({"name": "친구3", "age": 30}),
{"name": "친구1", "age": 20} &json!({"name": "친구1", "age": 20})
]); ]);
assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap(); let json = selector("$..friends[1]").unwrap();
let ret = json!([ assert_eq!(json, vec![
{"name": "친구4"}, &json!({"name": "친구4"}),
{"name": "친구2", "age": 20} &json!({"name": "친구2", "age": 20})
]); ]);
assert_eq!(json, ret);
``` ```
#### Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value) #### Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)
@ -267,13 +233,13 @@ let json_obj = json!({
{"name": "친구4"} {"name": "친구4"}
]}); ]});
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Deserialize, PartialEq, Debug)]
struct Friend { struct Friend {
name: String, name: String,
age: Option<u8>, age: Option<u8>,
} }
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj); let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
let json = selector("$..friends[0]").unwrap(); let json = selector("$..friends[0]").unwrap();
@ -346,21 +312,10 @@ let selector = new jsonpath.Selector();
selector.path('$..friends[0]'); selector.path('$..friends[0]');
selector.value(jsonObj); selector.value(jsonObj);
let selectAsObj = selector.selectAs(); let retObj = selector.select();
let selectAsString = selector.selectAsStr();
console.log( console.log(JSON.stringify(ret) == JSON.stringify(retObj));
JSON.stringify(ret) == JSON.stringify(selectAsObj),
JSON.stringify(ret) == selectAsString
);
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 // => true
``` ```
@ -389,15 +344,11 @@ let selector = new jsonpath.Selector()
.path('$..friends[0]') .path('$..friends[0]')
.value(jsonObj); .value(jsonObj);
let selectAsObj = selector.selectAs(); let retObj = selector.select();
let selectAsString = selector.selectAsStr();
console.log( console.log(JSON.stringify(ret) == JSON.stringify(retObj));
JSON.stringify(ret) == JSON.stringify(selectAsObj),
JSON.stringify(ret) == selectAsString
);
// => true, true // => true
``` ```
#### Javascript - jsonpath.select(json: string|object, jsonpath: string) #### Javascript - jsonpath.select(json: string|object, jsonpath: string)

View File

@ -42,39 +42,12 @@ class Selector {
if(typeof json != 'string') { if(typeof json != 'string') {
json = JSON.stringify(json) json = JSON.stringify(json)
} }
this._selector.valueFromStr(json); this._selector.value(json);
return this; return this;
} }
selectToStr() { select() {
return this.selectAsStr(); return JSON.parse(this._selector.select());
}
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());
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "jsonpath4nodejs" name = "jsonpath4nodejs"
version = "0.1.3" version = "0.2.0"
authors = ["Changseok Han <freestrings@gmail.com>"] authors = ["Changseok Han <freestrings@gmail.com>"]
description = "jsonpath_lib bindings for nodejs" description = "jsonpath_lib bindings for nodejs"
keywords = ["library", "jsonpath", "json", "nodejs"] keywords = ["library", "jsonpath", "json", "nodejs"]
@ -14,7 +14,7 @@ exclude = ["artifacts.json", "index.node"]
neon-build = "0.2.0" neon-build = "0.2.0"
[dependencies] [dependencies]
jsonpath_lib = "0.1.13" jsonpath_lib = "0.2.0"
neon = "0.2.0" neon = "0.2.0"
neon-serde = "0.1.1" neon-serde = "0.1.1"
serde_json = { version = "1.0", features = ["preserve_order"] } serde_json = { version = "1.0", features = ["preserve_order"] }

View File

@ -4,13 +4,9 @@ extern crate neon;
extern crate neon_serde; extern crate neon_serde;
extern crate serde_json; extern crate serde_json;
use jsonpath::filter::value_filter::JsonValueFilter; use jsonpath::{JsonPathError, Node, Parser, Selector};
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
use jsonpath::Selector;
use neon::prelude::*; use neon::prelude::*;
use serde_json::Value; use serde_json::Value;
use std::ops::Deref;
/// ///
/// `neon_serde::from_value` has very poor performance. /// `neon_serde::from_value` has very poor performance.
@ -35,96 +31,124 @@ fn select_str(mut ctx: FunctionContext) -> JsResult<JsValue> {
} }
} }
pub struct CompileFn {
node: Node
}
pub struct SelectorFn {
json: RefValueWrapper
}
pub struct SelectorCls { pub struct SelectorCls {
selector: Selector node: Option<Node>,
value: Option<Value>,
}
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! { declare_types! {
pub class JsCompileFn for CompileFn { pub class JsCompileFn for SelectorCls {
init(mut ctx) { init(mut ctx) {
let path = ctx.argument::<JsString>(0)?.value(); let path = ctx.argument::<JsString>(0)?.value();
let mut parser = Parser::new(path.as_str()); let mut parser = Parser::new(path.as_str());
let node = match parser.compile() { let node = match parser.compile() {
Ok(node) => node, Ok(node) => node,
Err(e) => panic!("{:?}", e) Err(e) => panic!("{:?}", e)
}; };
Ok(CompileFn { node }) Ok(SelectorCls { node: Some(node), value: None })
} }
method template(mut ctx) { method template(mut ctx) {
let this = ctx.this(); let mut this = ctx.this();
let node = {
let guard = ctx.lock();
let this = this.borrow(&guard);
this.node.clone()
};
let json_str = ctx.argument::<JsString>(0)?.value(); let json_str = ctx.argument::<JsString>(0)?.value();
let ref_value: RefValue = match serde_json::from_str(&json_str) { {
Ok(ref_value) => ref_value, let guard = ctx.lock();
Err(e) => panic!("{:?}", e) 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()); let result_str = {
jf.visit(node); let guard = ctx.lock();
match serde_json::to_string(&jf.take_value().deref()) { let this = this.borrow(&guard);
Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()), this.select()
Err(e) => panic!("{:?}", e) };
}
Ok(JsString::new(&mut ctx, &result_str).upcast())
} }
} }
pub class JsSelectorFn for SelectorFn { pub class JsSelectorFn for SelectorCls {
init(mut ctx) { init(mut ctx) {
let json_str = ctx.argument::<JsString>(0)?.value(); let json_str = ctx.argument::<JsString>(0)?.value();
let ref_value: RefValue = match serde_json::from_str(&json_str) { let value: Value = match serde_json::from_str(&json_str) {
Ok(ref_value) => ref_value, Ok(value) => value,
Err(e) => panic!("{:?}", e) 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) { method select(mut ctx) {
let this = ctx.this(); let mut this = ctx.this();
let json = {
let guard = ctx.lock();
let this = this.borrow(&guard);
this.json.clone()
};
let path = ctx.argument::<JsString>(0)?.value(); let path = ctx.argument::<JsString>(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() { let result_str = {
Ok(node) => node, let guard = ctx.lock();
Err(e) => panic!("{:?}", e) let this = this.borrow(&guard);
this.select()
}; };
let mut jf = JsonValueFilter::new_from_value(json); Ok(JsString::new(&mut ctx, &result_str).upcast())
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)
}
} }
} }
pub class JsSelector for SelectorCls { pub class JsSelector for SelectorCls {
init(mut _ctx) { init(mut _ctx) {
Ok(SelectorCls { selector: Selector::new() }) Ok(SelectorCls { node: None, value: None })
} }
method path(mut ctx) { method path(mut ctx) {
@ -134,80 +158,35 @@ declare_types! {
{ {
let guard = ctx.lock(); let guard = ctx.lock();
let mut this = this.borrow_mut(&guard); let mut this = this.borrow_mut(&guard);
let _ = this.selector.path(&path); let _ = this.path(&path);
} }
Ok(JsUndefined::new().upcast()) Ok(JsUndefined::new().upcast())
} }
method valueFromStr(mut ctx) { method value(mut ctx) {
let mut this = ctx.this(); let mut this = ctx.this();
let json_str = ctx.argument::<JsString>(0)?.value(); let json_str = ctx.argument::<JsString>(0)?.value();
{ {
let guard = ctx.lock(); let guard = ctx.lock();
let mut this = this.borrow_mut(&guard); let mut this = this.borrow_mut(&guard);
let _ = this.selector.value_from_str(&json_str); let _ = this.value(&json_str);
} }
Ok(JsUndefined::new().upcast()) Ok(JsUndefined::new().upcast())
} }
method selectAsStr(mut ctx) { method select(mut ctx) {
let mut this = ctx.this(); let this = ctx.this();
let result = { let result_str = {
let guard = ctx.lock(); let guard = ctx.lock();
let this = this.borrow_mut(&guard); let this = this.borrow(&guard);
this.selector.select_as_str() this.select()
}; };
match result { Ok(JsString::new(&mut ctx, &result_str).upcast())
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::<JsFunction>(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::<JsString>()
.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())
} }
} }
} }

View File

@ -359,7 +359,7 @@ describe('compile test', () => {
it('basic', (done) => { it('basic', (done) => {
let template = jsonpath.compile('$.a'); let template = jsonpath.compile('$.a');
let result = template({'a': 1}); let result = template({'a': 1});
if (result === 1) { if (result[0] === 1) {
done(); done();
} }
}); });
@ -369,7 +369,7 @@ describe('selector test', () => {
it('basic', (done) => { it('basic', (done) => {
let selector = jsonpath.selector({'a': 1}); let selector = jsonpath.selector({'a': 1});
let result = selector('$.a'); let result = selector('$.a');
if (result === 1) { if (result[0] === 1) {
done(); done();
} }
}); });
@ -378,7 +378,7 @@ describe('selector test', () => {
describe('select test', () => { describe('select test', () => {
it('basic', (done) => { it('basic', (done) => {
let result = jsonpath.select({'a': 1}, '$.a'); let result = jsonpath.select({'a': 1}, '$.a');
if (result === 1) { if (result[0] === 1) {
done(); done();
} }
}); });
@ -401,24 +401,10 @@ describe('filter test', () => {
}); });
describe('Selector 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) => { it('select', (done) => {
let selector = new jsonpath.Selector().value(jsonObj); let selector = new jsonpath.Selector().value(jsonObj);
for(var i in list) { 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}`; throw `fail: ${i}`;
} }
} }
@ -444,7 +430,7 @@ describe('README test', () => {
let selector = new jsonpath.Selector().value(jsonObj); 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}]; let resultObj = [{"name": "친구3", "age": 30}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: $..[?(@.age >= 30)]'; 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}]; let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: $..[?(@.age >= 20)]'; 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}]; let resultObj = [{"name": "친구5", "age": 20}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) { if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: change value'; 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(); done();
}); });

View File

@ -140,7 +140,7 @@ mod select;
pub use select::Selector; pub use select::Selector;
pub use select::JsonPathError; 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. /// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
/// ///