From e096e62dbf84efddc9192db040924a6bd8dc90e3 Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 00:02:05 +0900 Subject: [PATCH] =?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);