diff --git a/.idea/runConfigurations/all.xml b/.idea/runConfigurations/all.xml
index cb9472d..e050ac1 100644
--- a/.idea/runConfigurations/all.xml
+++ b/.idea/runConfigurations/all.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/.idea/runConfigurations/selector.xml b/.idea/runConfigurations/selector.xml
new file mode 100644
index 0000000..8192ccf
--- /dev/null
+++ b/.idea/runConfigurations/selector.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/serde.xml b/.idea/runConfigurations/serde.xml
index 83f09b6..526684d 100644
--- a/.idea/runConfigurations/serde.xml
+++ b/.idea/runConfigurations/serde.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/README.md b/README.md
index 30273d6..e25dea9 100644
--- a/README.md
+++ b/README.md
@@ -39,8 +39,6 @@ To enjoy Rust!
- [rust - jsonpath::selector_as\(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue)
- [rust - examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
-[With AWS API Gateway](#)
-
[Simple time check - webassembly](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck---jsonpath-wasm)
[Simple time check - native addon for NodeJs](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
diff --git a/benches/bench.rs b/benches/bench.rs
index 4b2b0cd..33c5cbf 100644
--- a/benches/bench.rs
+++ b/benches/bench.rs
@@ -3,6 +3,7 @@ extern crate jsonpath_lib as jsonpath;
extern crate serde;
extern crate serde_json;
extern crate test;
+extern crate bencher;
use std::io::Read;
@@ -10,6 +11,8 @@ use serde::Deserialize;
use serde_json::Value;
use self::test::Bencher;
+use jsonpath::ref_value::model::RefValue;
+use serde::ser::Serialize;
fn read_json(path: &str) -> String {
let mut f = std::fs::File::open(path).unwrap();
@@ -101,4 +104,25 @@ fn bench_select_as(b: &mut Bencher) {
let _: Book = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap();
}
});
+}
+
+#[bench]
+fn bench_serde_ser(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();
+ }
+ });
+}
+
+#[bench]
+fn bench_serde_de(b: &mut Bencher) {
+ let json_string = get_string();
+ let json_str = json_string.as_str();
+
+ b.iter(move || for _ in 1..100 {
+ let _: RefValue = serde_json::from_str(json_str).unwrap();
+ });
}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 6410469..e27562e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -158,6 +158,7 @@
//! assert_eq!(ret, json);
//! ```
+extern crate core;
extern crate env_logger;
extern crate indexmap;
#[macro_use]
@@ -166,36 +167,21 @@ extern crate log;
extern crate serde;
extern crate serde_json;
-use std::error::Error;
-use std::ops::Deref;
+use core::borrow::BorrowMut;
use std::result;
use serde_json::Value;
-use filter::value_filter::JsonValueFilter;
-use parser::parser::{NodeVisitor, Parser};
-use ref_value::model::RefValueWrapper;
-
#[doc(hidden)]
pub mod parser;
#[doc(hidden)]
pub mod filter;
#[doc(hidden)]
pub mod ref_value;
+#[doc(hidden)]
+pub mod select;
-fn query_from_str(json: &str, path: &str) -> result::Result {
- let mut jf = JsonValueFilter::new(json)?;
- let mut parser = Parser::new(path);
- parser.parse(&mut jf)?;
- Ok(jf)
-}
-
-fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result::Result {
- let mut jf = JsonValueFilter::new_from_value(json_wrapper);
- let mut parser = Parser::new(path);
- parser.parse(&mut jf)?;
- Ok(jf)
-}
+pub use select::Selector;
/// It is a highorder function that compile a JsonPath then returns a function.
///
@@ -227,17 +213,13 @@ fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result:
/// assert_eq!(json, ret);
/// ```
pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result + 'a {
- let mut parser = Parser::new(path);
- let node = parser.compile();
+ let mut selector = select::Selector::new();
+ let _ = selector.path(path);
+ let mut selector = Box::new(selector);
move |json| {
- match &node {
- Ok(n) => {
- let mut jf = JsonValueFilter::new_from_value(json.into());
- jf.visit(n.clone());
- Ok((&jf.take_value()).into())
- }
- Err(e) => Err(e.clone())
- }
+ let s: &mut select::Selector = selector.borrow_mut();
+ let _ = s.value(json.into());
+ s.select_to_value()
}
}
@@ -277,11 +259,13 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result impl FnMut(&str) -> result::Result {
- let wrapper: RefValueWrapper = json.into();
- move |path: &str| {
- let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
- Ok((&jf.take_value()).into())
+pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result {
+ let mut selector = select::Selector::new();
+ let _ = selector.value(json.into());
+ let mut selector = Box::new(selector);
+ move |path: &'a str| {
+ let s: &mut select::Selector = selector.borrow_mut();
+ s.path(path)?.select_to_value()
}
}
@@ -331,15 +315,15 @@ pub fn selector(json: &Value) -> impl FnMut(&str) -> result::Result(json: &Value) -> impl FnMut(&str) -> result::Result {
- let wrapper: RefValueWrapper = json.into();
+ let mut selector = select::Selector::new();
+ let _ = selector.value(json.into());
move |path: &str| {
- let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
- T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
+ selector.path(path)?.select_to()
}
}
#[deprecated(since = "0.1.4", note = "Please use the selector function instead")]
-pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result {
+pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result {
selector(json)
}
@@ -370,8 +354,8 @@ pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result
/// assert_eq!(json, ret);
/// ```
pub fn select(json: &Value, path: &str) -> result::Result {
- let mut jf = query_from_json_wrapper(json.into(), path)?;
- Ok((&jf.take_value()).into())
+ let mut selector = select::Selector::new();
+ selector.path(path)?.value(json.into())?.select_to_value()
}
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
@@ -408,8 +392,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 {
- let mut jf = query_from_str(json, path)?;
- serde_json::to_string(&jf.take_value().deref()).map_err(|e| e.description().to_string())
+ select::Selector::new()
+ .path(path)?
+ .value_from_str(json)?
+ .select_to_str()
}
/// Select a JsonObject. it return a deserialized instance of type `T`
@@ -451,6 +437,8 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result {
/// assert_eq!(person, ret);
/// ```
pub fn select_as(json: &str, path: &str) -> result::Result {
- let mut jf = query_from_str(json, path)?;
- T::deserialize(jf.take_value().deref()).map_err(|e| e.description().to_string())
+ select::Selector::new()
+ .path(path)?
+ .value_from_str(json)?
+ .select_to()
}
\ No newline at end of file
diff --git a/src/ref_value/model.rs b/src/ref_value/model.rs
index 48a7852..bb259b2 100644
--- a/src/ref_value/model.rs
+++ b/src/ref_value/model.rs
@@ -245,6 +245,15 @@ impl Into for RefValue {
}
}
+impl Into for &Value {
+ fn into(self) -> RefValue {
+ match self.serialize(super::ser::Serializer) {
+ Ok(v) => v,
+ Err(e) => panic!("Error Value into RefValue: {:?}", e)
+ }
+ }
+}
+
impl Into for &Value {
fn into(self) -> RefValueWrapper {
match self.serialize(super::ser::Serializer) {
diff --git a/src/select/mod.rs b/src/select/mod.rs
new file mode 100644
index 0000000..e65416b
--- /dev/null
+++ b/src/select/mod.rs
@@ -0,0 +1,122 @@
+use std::ops::Deref;
+use std::result;
+
+use serde_json::Value;
+
+use super::filter::value_filter::*;
+use super::parser::parser::*;
+use super::ref_value::model::*;
+
+/// Utility structure. Functions like jsonpath :: selector or jsonpath :: compile are also implemented using this structure.
+///
+/// ```rust
+/// extern crate jsonpath_lib as jsonpath;
+/// extern crate serde;
+/// #[macro_use] extern crate serde_json;
+///
+/// use serde::{Deserialize, Serialize};
+///
+/// #[derive(Deserialize, PartialEq, Debug)]
+/// struct Person {
+/// name: String,
+/// age: u8,
+/// phones: Vec,
+/// }
+///
+/// let ret: Person = jsonpath::select_as(r#"
+/// {
+/// "person":
+/// {
+/// "name": "Doe John",
+/// "age": 44,
+/// "phones": [
+/// "+44 1234567",
+/// "+44 2345678"
+/// ]
+/// }
+/// }
+/// "#, "$.person").unwrap();
+///
+/// let person = Person {
+/// name: "Doe John".to_owned(),
+/// age: 44,
+/// phones: vec!["+44 1234567".to_owned(), "+44 2345678".to_owned()],
+/// };
+///
+/// assert_eq!(person, ret);
+/// ```
+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, ref_value: RefValue) -> result::Result<&mut Self, String> {
+ self.value = Some(ref_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| format!("{:?}", e))?;
+ self.value(ref_value)
+ }
+
+ pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
+ let ref_value: RefValue = serde_json::from_str(json_str)
+ .map_err(|e| format!("{:?}", e))?;
+ self.value(ref_value)
+ }
+
+ fn jf(&mut self) -> result::Result {
+ match &self.value {
+ Some(v) => Ok(JsonValueFilter::new_from_value(v.clone())),
+ _ => return Err("Value is empty".to_owned())
+ }
+ }
+
+ pub fn select_to_str(&mut self) -> result::Result {
+ let mut jf = self.jf()?;
+
+ match &mut self.node {
+ Some(node) => {
+ jf.visit(node.clone());
+ return serde_json::to_string(jf.take_value().deref()).map_err(|e| format!("{:?}", e));
+ }
+ _ => return Err("Path is empty".to_owned())
+ };
+ }
+
+ pub fn select_to_value(&mut self) -> result::Result {
+ let mut jf = self.jf()?;
+ match &mut self.node {
+ Some(node) => {
+ jf.visit(node.clone());
+ Ok((&jf.take_value()).into())
+ }
+ _ => Err("Path is empty".to_owned())
+ }
+ }
+
+ pub fn select_to(&mut self) -> result::Result {
+ let mut jf = self.jf()?;
+ match &mut self.node {
+ Some(node) => {
+ jf.visit(node.clone());
+ T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
+ }
+ _ => Err("Path is empty".to_owned())
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/selector.rs b/tests/selector.rs
new file mode 100644
index 0000000..769a9c3
--- /dev/null
+++ b/tests/selector.rs
@@ -0,0 +1,92 @@
+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: u8,
+ 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()
+}
+#[test]
+fn selector_value_from() {
+ let result = Selector::new()
+ .path("$..[?(@.age > 40)]").unwrap()
+ .value_from(&input_person()).unwrap()
+ .select_to::>().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_to_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_to_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_to_value().unwrap();
+ assert_eq!(input_json()[1], result[0]);
+
+ let result = selector.select_to_str().unwrap();
+ assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
+
+ let result = selector.select_to::>().unwrap();
+ assert_eq!(input_person()[1], result[0]);
+
+ let _ = selector.path("$..[?(@.age == 40)]");
+
+ let result = selector.select_to_value().unwrap();
+ assert_eq!(input_json()[0], result[0]);
+
+ let result = selector.select_to_str().unwrap();
+ assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
+
+ let result = selector.select_to::>().unwrap();
+ assert_eq!(input_person()[0], result[0]);
+}
\ No newline at end of file
diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs
index 79d7ec5..5447ee3 100644
--- a/wasm/src/lib.rs
+++ b/wasm/src/lib.rs
@@ -120,14 +120,6 @@ pub fn compile(path: &str) -> JsValue {
ret
}
-///
-/// deprecated. use selector
-///
-#[wasm_bindgen]
-pub fn reader(js_value: JsValue) -> JsValue {
- selector(js_value)
-}
-
#[wasm_bindgen]
pub fn selector(js_value: JsValue) -> JsValue {
let json = match js_value.as_f64() {
@@ -167,13 +159,5 @@ pub fn select(js_value: JsValue, path: &str) -> JsValue {
}
}
-///
-/// deprecated. use select
-///
-#[wasm_bindgen]
-pub fn read(js_value: JsValue, path: &str) -> JsValue {
- select(js_value, path)
-}
-
#[wasm_bindgen]
pub fn testa() {}
\ No newline at end of file
diff --git a/wasm/www/index.js b/wasm/www/index.js
index 9d3d406..4a06a31 100644
--- a/wasm/www/index.js
+++ b/wasm/www/index.js
@@ -36,7 +36,7 @@ function initEvent() {
}
function read() {
- let ret = jsonpath.read(getTextarea().value, getJsonpathInput().value);
+ let ret = jsonpath.select(getTextarea().value, getJsonpathInput().value);
if(typeof ret === 'string') {
getReadResult().innerText = ret;
} else {