diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 43e19d9..fa4bd9d 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonpath-wasm" -version = "0.1.2" +version = "0.1.3" 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"] @@ -24,12 +24,12 @@ serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } lazy_static = "1.3.0" web-sys = { version = "0.3", features = ['console'] } +js-sys = "0.3" [dev-dependencies] wasm-bindgen-test = "0.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -js-sys = "0.3" [profile.release] opt-level = "s" diff --git a/wasm/README.md b/wasm/README.md index e5b684c..d43f20c 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -14,9 +14,11 @@ It is Webassembly version of [jsonpath_lib](https://github.com/freestrings/jsonp ### jsonpath.Selector -> Selector's selectTo function is deprecated since 0.1.3 +> Selector's selectTo function is deprecated. since 0.1.3 ```javascript +let jsonpath = require('jsonpath-wasm'); + let jsonObj = { "school": { "friends": [ @@ -30,25 +32,45 @@ let jsonObj = { ] }; -let selector = new jsonpath.Selector().value(jsonObj); +let selector = new jsonpath.Selector(); +selector.value(jsonObj); { - let jsonObj = selector.path('$..[?(@.age >= 30)]').selectAs(); + selector.path('$..[?(@.age >= 30)]'); + let jsonObj = selector.selectAs(); let resultObj = [{"name": "친구3", "age": 30}]; console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj)); } { - let jsonObj = selector.path('$..[?(@.age == 20)]').selectAs(); + selector.path('$..[?(@.age == 20)]'); + let jsonObj = selector.selectAs(); let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}]; console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj)); } { - let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectAs(); + selector.value({"friends": [ {"name": "친구5", "age": 20} ]}); + let jsonObj = selector.selectAs(); let resultObj = [{"name": "친구5", "age": 20}]; console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj)); } + +{ + selector.value(jsonObj); + selector.map(function(v) { + let f1 = v[0]; + f1.age = 30; + return v; + }); + let resultObj1 = [{"name": "친구1", "age": 30}, {"name": "친구2", "age": 20}]; + console.log(JSON.stringify(selector.get()) === JSON.stringify(resultObj1)); + + selector.path('$..[?(@.age == 20)]'); + let jsonObj1 = selector.selectAs(); + let resultObj2 = [{"name": "친구2", "age": 20}]; + console.log(JSON.stringify(jsonObj1) === JSON.stringify(resultObj2)); +} ``` ### jsonpath.select(json: string|object, jsonpath: string) diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 9c7750b..6b7522b 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,4 +1,5 @@ extern crate cfg_if; +extern crate js_sys; extern crate jsonpath_lib as jsonpath; #[macro_use] extern crate lazy_static; @@ -18,6 +19,8 @@ use jsonpath::filter::value_filter::JsonValueFilter; use jsonpath::parser::parser::{Node, NodeVisitor, Parser}; use jsonpath::ref_value::model::{RefValue, RefValueWrapper}; use jsonpath::Selector as _Selector; +use serde_json::Value; +use wasm_bindgen::*; use wasm_bindgen::prelude::*; use web_sys::console; @@ -106,7 +109,7 @@ pub extern fn alloc_json(js_value: JsValue) -> usize { *idx } Err(e) => { - console::log_1(&e.into()); + console::error_1(&e.into()); 0 } } @@ -222,7 +225,49 @@ impl Selector { 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(&format!("{:?}", e)))?) + .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")); + } + + let cb: &js_sys::Function = JsCast::unchecked_ref(func.as_ref()); + + 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 { + JsValue::from_serde(&self.selector.get()).map_err(|e| JsValue::from_str(&e.to_string())) } } diff --git a/wasm/tests/web.rs b/wasm/tests/web.rs index 349afbf..0dac354 100644 --- a/wasm/tests/web.rs +++ b/wasm/tests/web.rs @@ -10,6 +10,7 @@ extern crate wasm_bindgen_test; use serde_json::Value; use wasm_bindgen::*; +use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); @@ -113,6 +114,27 @@ fn selector_struct() { let mut selector = jsonpath::Selector::new(); selector.path("$..book[2]").unwrap(); selector.value(JsValue::from_str(json_str())).unwrap(); + let json: Value = selector.select_as().unwrap().into_serde().unwrap(); assert_eq!(json, target_json()); + + let cb = Closure::wrap(Box::new(|js_value: JsValue| { + match js_value.into_serde().unwrap() { + Value::Array(mut vec) => { + match vec.pop().unwrap() { + Value::Object(mut map) => { + map.clear(); + map.insert("key".to_string(), Value::String("value".to_string())); + JsValue::from_serde(&Value::Object(map)).unwrap() + } + _ => return JsValue::NULL + } + } + _ => return JsValue::NULL + } + }) as Box JsValue>); + + selector.map(cb.as_ref().clone()).unwrap(); + let js_value = selector.get().unwrap(); + assert_eq!(js_value.into_serde::().unwrap(), json!({ "key": "value" })); } \ No newline at end of file