mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 09:22:19 +00:00
serde_json::Value clone 제거
This commit is contained in:
parent
ba57ae0ea5
commit
1a3104c5db
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "jsonpath_lib"
|
name = "jsonpath_lib"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||||
|
|
||||||
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
||||||
@ -27,4 +27,8 @@ bencher = "0.1.5"
|
|||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "jsonpath_lib"
|
name = "jsonpath_lib"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
lto = false
|
||||||
|
183
README.md
183
README.md
@ -1,7 +1,7 @@
|
|||||||
# jsonpath-lib
|
# jsonpath-lib
|
||||||
|
|
||||||
[](https://travis-ci.org/freestrings/jsonpath)
|
[](https://travis-ci.org/freestrings/jsonpath)
|
||||||
[](https://crates.io/crates/jsonpath_lib)
|

|
||||||
|
|
||||||
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. Rust 구현과 동일한 기능을 `Webassembly` 로 제공하는 것도 목표.
|
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. Rust 구현과 동일한 기능을 `Webassembly` 로 제공하는 것도 목표.
|
||||||
|
|
||||||
@ -16,17 +16,18 @@ To enjoy Rust!
|
|||||||
[With Javascript (Webassembly)](#with-javascript-webassembly)
|
[With Javascript (Webassembly)](#with-javascript-webassembly)
|
||||||
|
|
||||||
- [jsonpath-wasm library](#jsonpath-wasm-library)
|
- [jsonpath-wasm library](#jsonpath-wasm-library)
|
||||||
- [javascript - jsonpath.read(json: string|object, jsonpath: string)](#javascript---jsonpathreadjson-stringobject-jsonpath-string)
|
- [javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
|
||||||
- [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
|
- [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
|
||||||
- [javascript - jsonpath.reader(json: string|object)](#javascript---jsonpathreaderjson-stringobject)
|
- [javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
|
||||||
|
- [javascript - alloc_json, dealloc_json](#javascript---alloc_json-dealloc_json)
|
||||||
- [javascript - examples](#javascript---examples)
|
- [javascript - examples](#javascript---examples)
|
||||||
|
|
||||||
[With Rust (as library)](#with-rust-as-library)
|
[With Rust (as library)](#with-rust-as-library)
|
||||||
|
|
||||||
- [jsonpath_lib library](#jsonpath_lib-library)
|
- [jsonpath_lib library](#jsonpath_lib-library)
|
||||||
- [rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str)](#rust---jsonpathreadjson-serde_jsonvaluevalue-jsonpath-str)
|
- [rust - jsonpath::select(json: serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
|
||||||
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
|
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
|
||||||
- [rust - jsonpath::reader(json: serde_json::value::Value)](#rust---jsonpathreaderjson-serde_jsonvaluevalue)
|
- [rust - jsonpath::selector(json: serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
|
||||||
- [rust - examples](#rust---examples)
|
- [rust - examples](#rust---examples)
|
||||||
|
|
||||||
[With AWS API Gateway](#with-aws-api-gateway)
|
[With AWS API Gateway](#with-aws-api-gateway)
|
||||||
@ -45,7 +46,7 @@ import * as jsonpath from "jsonpath-wasm";
|
|||||||
let jsonpath = require('jsonpath-wasm');
|
let jsonpath = require('jsonpath-wasm');
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - jsonpath.read(json: string|object, jsonpath: string)
|
### javascript - jsonpath.select(json: string|object, jsonpath: string)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let jsonObj = {
|
let jsonObj = {
|
||||||
@ -56,8 +57,8 @@ let jsonObj = {
|
|||||||
};
|
};
|
||||||
let ret = [{"id": 0}, {"id": 0}];
|
let ret = [{"id": 0}, {"id": 0}];
|
||||||
|
|
||||||
let a = jsonpath.read(JSON.stringify(jsonObj), "$..friends[0]");
|
let a = jsonpath.select(JSON.stringify(jsonObj), "$..friends[0]");
|
||||||
let b = jsonpath.read(jsonObj, "$..friends[0]");
|
let b = jsonpath.select(jsonObj, "$..friends[0]");
|
||||||
console.log(
|
console.log(
|
||||||
JSON.stringify(ret) == JSON.stringify(a),
|
JSON.stringify(ret) == JSON.stringify(a),
|
||||||
JSON.stringify(a) == JSON.stringify(b)
|
JSON.stringify(a) == JSON.stringify(b)
|
||||||
@ -101,7 +102,7 @@ console.log(JSON.stringify(template(jsonObj2)) == ret2);
|
|||||||
console.log(JSON.stringify(template(JSON.stringify(jsonObj2))) == ret2);
|
console.log(JSON.stringify(template(JSON.stringify(jsonObj2))) == ret2);
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - jsonpath.reader(json: string|object)
|
### javascript - jsonpath.selector(json: string|object)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let jsonObj = {
|
let jsonObj = {
|
||||||
@ -115,14 +116,55 @@ let ret1 = JSON.stringify([ {"id": 0}, {"id": 0} ]);
|
|||||||
let ret2 = JSON.stringify([ {"id": 1}, {"id": 1} ]);
|
let ret2 = JSON.stringify([ {"id": 1}, {"id": 1} ]);
|
||||||
|
|
||||||
// 1. read as json object
|
// 1. read as json object
|
||||||
let reader = jsonpath.reader(jsonObj);
|
let selector = jsonpath.selector(jsonObj);
|
||||||
console.log(JSON.stringify(reader("$..friends[0]")) == ret1);
|
console.log(JSON.stringify(selector("$..friends[0]")) == ret1);
|
||||||
console.log(JSON.stringify(reader("$..friends[1]")) == ret2);
|
console.log(JSON.stringify(selector("$..friends[1]")) == ret2);
|
||||||
|
|
||||||
// 2. read as json string
|
// 2. read as json string
|
||||||
let reader2 = jsonpath.reader(JSON.stringify(jsonObj));
|
let selector = jsonpath.selector(JSON.stringify(jsonObj));
|
||||||
console.log(JSON.stringify(reader2("$..friends[0]")) == ret1);
|
console.log(JSON.stringify(selector("$..friends[0]")) == ret1);
|
||||||
console.log(JSON.stringify(reader2("$..friends[1]")) == ret2);
|
console.log(JSON.stringify(selector("$..friends[1]")) == ret2);
|
||||||
|
```
|
||||||
|
|
||||||
|
### javascript - alloc_json, dealloc_json
|
||||||
|
|
||||||
|
wasm-bindgen은 Javascript와 Webassembly 간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체를 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
|
||||||
|
|
||||||
|
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, it is helpful to create repeated Json objects in Webassembly area.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [{"id": 0}, {"id": 1}]
|
||||||
|
},
|
||||||
|
"friends": [{"id": 0},{"id": 1}]
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = '$..friends[0]';
|
||||||
|
let template = jsonpath.compile(path);
|
||||||
|
let selector = jsonpath.selector(jsonObj);
|
||||||
|
|
||||||
|
let ptr = jsonpath.alloc_json(jsonObj);
|
||||||
|
if(ptr == 0) console.error('invalid ptr'); // `0` is invalid pointer
|
||||||
|
let selector2 = jsonpath.selector(ptr);
|
||||||
|
|
||||||
|
let ret1 = selector(path)
|
||||||
|
let ret2 = selector2(path)
|
||||||
|
let ret3 = template(jsonObj);
|
||||||
|
let ret4 = template(ptr);
|
||||||
|
let ret5 = jsonpath.select(jsonObj, path);
|
||||||
|
let ret6 = jsonpath.select(ptr, path);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(ret1) == JSON.stringify(ret2),// true
|
||||||
|
JSON.stringify(ret1) == JSON.stringify(ret3),// true
|
||||||
|
JSON.stringify(ret1) == JSON.stringify(ret4),// true
|
||||||
|
JSON.stringify(ret1) == JSON.stringify(ret5),// true
|
||||||
|
JSON.stringify(ret1) == JSON.stringify(ret6));// true
|
||||||
|
|
||||||
|
jsonpath.dealloc_json(ptr);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - examples
|
### javascript - examples
|
||||||
@ -201,7 +243,7 @@ extern crate jsonpath_lib as jsonpath;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
```
|
```
|
||||||
|
|
||||||
### rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str)
|
### rust - jsonpath::select(json: serde_json::value::Value, jsonpath: &str)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let json_obj = json!({
|
let json_obj = json!({
|
||||||
@ -210,7 +252,7 @@ let json_obj = json!({
|
|||||||
},
|
},
|
||||||
"friends": [{"id": 0}, {"id": 1}]
|
"friends": [{"id": 0}, {"id": 1}]
|
||||||
});
|
});
|
||||||
let json = jsonpath::read(json_obj, "$..friends[0]").unwrap();
|
let json = jsonpath::select(json_obj, "$..friends[0]").unwrap();
|
||||||
let ret = json!([ {"id": 0}, {"id": 0} ]);
|
let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||||
assert_eq!(json, ret)
|
assert_eq!(json, ret)
|
||||||
```
|
```
|
||||||
@ -243,7 +285,7 @@ let ret = json!([ {"id": 0}, {"name": "Millicent Norman"} ]);
|
|||||||
assert_eq!(json, ret);
|
assert_eq!(json, ret);
|
||||||
```
|
```
|
||||||
|
|
||||||
### rust - jsonpath::reader(json: serde_json::value::Value)
|
### rust - jsonpath::selector(json: serde_json::value::Value)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let json_obj = json!({
|
let json_obj = json!({
|
||||||
@ -253,13 +295,13 @@ let json_obj = json!({
|
|||||||
"friends": [{"id": 0},{"id": 1}]
|
"friends": [{"id": 0},{"id": 1}]
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut reader = jsonpath::reader(json_obj);
|
let mut selector = jsonpath::selector(json_obj);
|
||||||
|
|
||||||
let json = reader("$..friends[0]").unwrap();
|
let json = selector("$..friends[0]").unwrap();
|
||||||
let ret = json!([ {"id": 0}, {"id": 0} ]);
|
let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||||
assert_eq!(json, ret);
|
assert_eq!(json, ret);
|
||||||
|
|
||||||
let json = reader("$..friends[1]").unwrap();
|
let json = selector("$..friends[1]").unwrap();
|
||||||
let ret = json!([ {"id": 1}, {"id": 1} ]);
|
let ret = json!([ {"id": 1}, {"id": 1} ]);
|
||||||
assert_eq!(json, ret);
|
assert_eq!(json, ret);
|
||||||
```
|
```
|
||||||
@ -305,13 +347,13 @@ let json_obj = json!({
|
|||||||
"expensive": 10
|
"expensive": 10
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut reader = jsonpath::reader(json_obj);
|
let mut selector = jsonpath::selector(json_obj);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### $.store.book[*].author
|
#### $.store.book[*].author
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$.store.book[*].author").unwrap();
|
let json = selector("$.store.book[*].author").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
"Nigel Rees",
|
"Nigel Rees",
|
||||||
"Evelyn Waugh",
|
"Evelyn Waugh",
|
||||||
@ -323,7 +365,7 @@ assert_eq!(json, ret);
|
|||||||
|
|
||||||
#### $..author
|
#### $..author
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..author").unwrap();
|
let json = selector("$..author").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
"Nigel Rees",
|
"Nigel Rees",
|
||||||
"Evelyn Waugh",
|
"Evelyn Waugh",
|
||||||
@ -335,7 +377,7 @@ assert_eq!(json, ret);
|
|||||||
|
|
||||||
#### $.store.*
|
#### $.store.*
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$.store.*").unwrap();
|
let json = selector("$.store.*").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -375,14 +417,14 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $.store..price
|
#### $.store..price
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$.store..price").unwrap();
|
let json = selector("$.store..price").unwrap();
|
||||||
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||||
assert_eq!(ret, json);
|
assert_eq!(ret, json);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### $..book[2]
|
#### $..book[2]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[2]").unwrap();
|
let json = selector("$..book[2]").unwrap();
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
"author" : "Herman Melville",
|
"author" : "Herman Melville",
|
||||||
@ -395,7 +437,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[-2]
|
#### $..book[-2]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[-2]").unwrap();
|
let json = selector("$..book[-2]").unwrap();
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
"author" : "Herman Melville",
|
"author" : "Herman Melville",
|
||||||
@ -408,7 +450,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[0,1]
|
#### $..book[0,1]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[0,1]").unwrap();
|
let json = selector("$..book[0,1]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category": "reference",
|
"category": "reference",
|
||||||
@ -428,7 +470,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[:2]
|
#### $..book[:2]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[:2]").unwrap();
|
let json = selector("$..book[:2]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category": "reference",
|
"category": "reference",
|
||||||
@ -448,7 +490,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[2:]
|
#### $..book[2:]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[2:]").unwrap();
|
let json = selector("$..book[2:]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category": "fiction",
|
"category": "fiction",
|
||||||
@ -470,7 +512,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[?(@.isbn)]
|
#### $..book[?(@.isbn)]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$..book[?(@.isbn)]").unwrap();
|
let json = selector("$..book[?(@.isbn)]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category": "fiction",
|
"category": "fiction",
|
||||||
@ -492,7 +534,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $.store.book[?(@.price < 10)]
|
#### $.store.book[?(@.price < 10)]
|
||||||
```rust
|
```rust
|
||||||
let json = reader("$.store.book[?(@.price < 10)]").unwrap();
|
let json = selector("$.store.book[?(@.price < 10)]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{
|
{
|
||||||
"category": "reference",
|
"category": "reference",
|
||||||
@ -513,7 +555,7 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
#### $..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")]
|
#### $..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")]
|
||||||
```rust
|
```rust
|
||||||
let json = reader(r#"$..book[
|
let json = selector(r#"$..book[
|
||||||
?(
|
?(
|
||||||
(@.price == 12.99 || $.store.bicycle.price < @.price)
|
(@.price == 12.99 || $.store.bicycle.price < @.price)
|
||||||
|| @.category == "reference"
|
|| @.category == "reference"
|
||||||
@ -554,15 +596,21 @@ assert_eq!(ret, json);
|
|||||||
|
|
||||||
### Browser [Bench Demo](https://freestrings.github.io/jsonpath/bench)
|
### Browser [Bench Demo](https://freestrings.github.io/jsonpath/bench)
|
||||||
|
|
||||||
|
```
|
||||||
|
'$..book[?(@.price<30 && @.category=="fiction")]' (loop 2,000)
|
||||||
|
```
|
||||||
|
|
||||||
#### Chrome: 72.0
|
#### Chrome: 72.0
|
||||||
|
|
||||||
> Something to wrong in chrome
|
> Something to wrong in chrome
|
||||||
|
|
||||||
```
|
```
|
||||||
jsonpath, 134
|
jsonpath, 166
|
||||||
jsonpath-wasm- reader, 1409
|
jsonpath-wasm- selector, 256
|
||||||
jsonpath-wasm- compile, 3237
|
jsonpath-wasm- compile, 1168
|
||||||
jsonpath-wasm- read, 5302
|
jsonpath-wasm- compile-alloc, 645
|
||||||
|
jsonpath-wasm- select, 3224
|
||||||
|
jsonpath-wasm- select-alloc, 1427
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Firefox: 65.0
|
#### Firefox: 65.0
|
||||||
@ -570,40 +618,65 @@ jsonpath-wasm- read, 5302
|
|||||||
> jsonpath-wasm is faster than jsonpath
|
> jsonpath-wasm is faster than jsonpath
|
||||||
|
|
||||||
```
|
```
|
||||||
jsonpath, 301
|
jsonpath, 125
|
||||||
jsonpath-wasm- reader, 166
|
jsonpath-wasm- selector, 101
|
||||||
jsonpath-wasm- compile, 130
|
jsonpath-wasm- compile, 169
|
||||||
jsonpath-wasm- read, 144
|
jsonpath-wasm- compile-alloc, 78
|
||||||
|
jsonpath-wasm- select, 186
|
||||||
|
jsonpath-wasm- select-alloc, 93
|
||||||
```
|
```
|
||||||
|
|
||||||
### NodeJs
|
### NodeJs
|
||||||
|
|
||||||
* NodeJS: 11.0
|
* NodeJS: 11.0
|
||||||
* CPU: Intel Core i5-4460
|
|
||||||
* Memory: 16GB
|
|
||||||
|
|
||||||
> Rust > jsonpath > jsonpath-wasm
|
> Rust > jsonpath > jsonpath-wasm
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd benches && ./bench_node_vs_rust.sh
|
cd benches && ./bench_node_vs_rust.sh
|
||||||
|
|
||||||
$..book[?(@.price<30 && @.category==fiction)] (loop 100,000)
|
$..book[?(@.price<30 && @.category==fiction)] (loop 100,000)
|
||||||
|
|
||||||
Rust:
|
Rust:
|
||||||
|
|
||||||
real 0m1.141s
|
real 0m0.862s
|
||||||
user 0m1.137s
|
user 0m0.862s
|
||||||
sys 0m0.004s
|
sys 0m0.000s
|
||||||
|
|
||||||
NodeJs - jsonpath module:
|
NodeJs - jsonpath module:
|
||||||
|
|
||||||
real 0m3.718s
|
real 0m3.667s
|
||||||
user 0m4.175s
|
user 0m4.139s
|
||||||
sys 0m0.050s
|
sys 0m0.045s
|
||||||
|
|
||||||
NodeJs - jsonpath-wasm module:
|
NodeJs - jsonpath-wasm module - selector:
|
||||||
|
|
||||||
|
real 0m5.331s
|
||||||
|
user 0m5.494s
|
||||||
|
sys 0m0.093s
|
||||||
|
|
||||||
|
NodeJs - jsonpath-wasm module - compile:
|
||||||
|
|
||||||
|
real 0m8.665s
|
||||||
|
user 0m8.809s
|
||||||
|
sys 0m0.197s
|
||||||
|
|
||||||
|
NodeJs - jsonpath-wasm module - compile-alloc:
|
||||||
|
|
||||||
|
real 0m4.014s
|
||||||
|
user 0m4.173s
|
||||||
|
sys 0m0.088s
|
||||||
|
|
||||||
|
NodeJs - jsonpath-wasm module - select:
|
||||||
|
|
||||||
|
real 0m9.843s
|
||||||
|
user 0m9.897s
|
||||||
|
sys 0m0.244s
|
||||||
|
|
||||||
|
NodeJs - jsonpath-wasm module - select-alloc:
|
||||||
|
|
||||||
|
real 0m5.212s
|
||||||
|
user 0m5.339s
|
||||||
|
sys 0m0.096s
|
||||||
|
|
||||||
real 0m10.205s
|
|
||||||
user 0m10.281s
|
|
||||||
sys 0m0.383s
|
|
||||||
```
|
```
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bench_bin"
|
name = "bench_bin"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jsonpath_lib = {path = "../../"}
|
jsonpath_lib = {path = "../../"}
|
||||||
|
@ -14,8 +14,8 @@ fn read_json(path: &str) -> String {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let string = read_json("../example.json");
|
let string = read_json("../example.json");
|
||||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||||
let mut reader = jsonpath::reader(json);
|
let mut selector = jsonpath::selector(json);
|
||||||
for _ in 1..100000 {
|
for _ in 1..100000 {
|
||||||
let _ = reader(r#"$..book[?(@.price<30 && @.category=="fiction")]"#).unwrap();
|
let _ = selector(r#"$..book[?(@.price<30 && @.category=="fiction")]"#).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,14 @@ printf "\n\n"
|
|||||||
|
|
||||||
echo "Rust: " && time ./bench.sh
|
echo "Rust: " && time ./bench.sh
|
||||||
printf "\n"
|
printf "\n"
|
||||||
cd "${DIR}"/javascript && echo "NodeJs - jsonpath module: " && time ./bench.sh jsonpathOnly
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath module: " && time ./bench.sh jsonpath
|
||||||
printf "\n"
|
printf "\n"
|
||||||
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module: " && time ./bench.sh jsonpathWasmOnly
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - selector: " && time ./bench.sh wasmSelector
|
||||||
|
printf "\n"
|
||||||
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - compile: " && time ./bench.sh wasmCompile
|
||||||
|
printf "\n"
|
||||||
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - compile-alloc: " && time ./bench.sh wasmCompileAlloc
|
||||||
|
printf "\n"
|
||||||
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - select:" && time ./bench.sh wasmSelect
|
||||||
|
printf "\n"
|
||||||
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - select-alloc:" && time ./bench.sh wasmSelectAlloc
|
@ -1,118 +1,124 @@
|
|||||||
let json = {
|
let json = {
|
||||||
"store": {
|
'store': {
|
||||||
"book": [
|
'book': [
|
||||||
{
|
{
|
||||||
"category": "reference",
|
'category': 'reference',
|
||||||
"author": "Nigel Rees",
|
'author': 'Nigel Rees',
|
||||||
"title": "Sayings of the Century",
|
'title': 'Sayings of the Century',
|
||||||
"price": 8.95
|
'price': 8.95,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"category": "fiction",
|
'category': 'fiction',
|
||||||
"author": "Evelyn Waugh",
|
'author': 'Evelyn Waugh',
|
||||||
"title": "Sword of Honour",
|
'title': 'Sword of Honour',
|
||||||
"price": 12.99
|
'price': 12.99,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"category": "fiction",
|
'category': 'fiction',
|
||||||
"author": "Herman Melville",
|
'author': 'Herman Melville',
|
||||||
"title": "Moby Dick",
|
'title': 'Moby Dick',
|
||||||
"isbn": "0-553-21311-3",
|
'isbn': '0-553-21311-3',
|
||||||
"price": 8.99
|
'price': 8.99,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"category": "fiction",
|
'category': 'fiction',
|
||||||
"author": "J. R. R. Tolkien",
|
'author': 'J. R. R. Tolkien',
|
||||||
"title": "The Lord of the Rings",
|
'title': 'The Lord of the Rings',
|
||||||
"isbn": "0-395-19395-8",
|
'isbn': '0-395-19395-8',
|
||||||
"price": 22.99
|
'price': 22.99,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"bicycle": {
|
'bicycle': {
|
||||||
"color": "red",
|
'color': 'red',
|
||||||
"price": 19.95
|
'price': 19.95,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"expensive": 10
|
'expensive': 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
const jp = require('jsonpath');
|
const jp = require('jsonpath');
|
||||||
const jpw = require('@nodejs/jsonpath-wasm');
|
const jpw = require('@nodejs/jsonpath-wasm');
|
||||||
const Benchmark = require('benchmark');
|
const iter = 100000;
|
||||||
|
|
||||||
function compareJsonpath(path) {
|
function jsonpath() {
|
||||||
let r1 = jp.query(json, path);
|
for (var i = 0; i < iter; i++) {
|
||||||
let r2 = jpw.read(json, path);
|
|
||||||
|
|
||||||
let template = jpw.compile(path);
|
|
||||||
|
|
||||||
var suite = new Benchmark.Suite;
|
|
||||||
|
|
||||||
suite.add('jp', function() {
|
|
||||||
jp.query(json, path);
|
|
||||||
})
|
|
||||||
.add('jpw', function() {
|
|
||||||
template(json);
|
|
||||||
})
|
|
||||||
.on('cycle', function(event) {
|
|
||||||
console.log(String(event.target));
|
|
||||||
})
|
|
||||||
.on('complete', function() {
|
|
||||||
console.log('Fastest is ' + this.filter('fastest').map('name'));
|
|
||||||
console.log('Slowest is ' + this.filter('slowest').map('name'));
|
|
||||||
})
|
|
||||||
.run({ 'async': true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function compareEmptyFunction() {
|
|
||||||
var suite = new Benchmark.Suite;
|
|
||||||
|
|
||||||
suite.add('js', function() {
|
|
||||||
})
|
|
||||||
.add('rust', function() {
|
|
||||||
jpw.testa();
|
|
||||||
})
|
|
||||||
.on('cycle', function(event) {
|
|
||||||
console.log(String(event.target));
|
|
||||||
})
|
|
||||||
.on('complete', function() {
|
|
||||||
console.log('Fastest is ' + this.filter('fastest').map('name'));
|
|
||||||
console.log('Slowest is ' + this.filter('slowest').map('name'));
|
|
||||||
})
|
|
||||||
.run({});
|
|
||||||
}
|
|
||||||
|
|
||||||
function jsonpathOnly() {
|
|
||||||
for(var i = 0; i < 100000 ; i++) {
|
|
||||||
let _ = jp.query(json, '$..book[?(@.price<30 && @.category=="fiction")]');
|
let _ = jp.query(json, '$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsonpathWasmOnly() {
|
function wasmSelector() {
|
||||||
let reader = jpw.reader(json);
|
let selector = jpw.selector(json);
|
||||||
for(var i = 0; i < 100000 ; i++) {
|
for (var i = 0; i < iter; i++) {
|
||||||
let _ = reader('$..book[?(@.price<30 && @.category=="fiction")]');
|
let _ = selector('$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(process.argv.length < 3) {
|
function wasmCompile() {
|
||||||
let functions = ['', 'compareJsonpath', 'compareEmptyFunction', 'jsonpathOnly', 'jsonpathWasmOnly'];
|
let template = jpw.compile('$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
console.log("node bench.js", functions.join("\n\t|"));
|
for (var i = 0; i < iter; i++) {
|
||||||
return;
|
let _ = template(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wasmCompileAlloc() {
|
||||||
|
let ptr = jpw.alloc_json(json);
|
||||||
|
if (ptr == 0) {
|
||||||
|
console.error('Invalid pointer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let template = jpw.compile('$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
|
for (var i = 0; i < iter; i++) {
|
||||||
|
let _ = template(ptr);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
jpw.dealloc_json(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wasmSelect() {
|
||||||
|
for (var i = 0; i < iter; i++) {
|
||||||
|
let _ = jpw.select(json, '$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wasmSelectAlloc() {
|
||||||
|
let ptr = jpw.alloc_json(json);
|
||||||
|
if (ptr == 0) {
|
||||||
|
console.error('Invalid pointer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < iter; i++) {
|
||||||
|
let _ = jpw.select(ptr, '$..book[?(@.price<30 && @.category=="fiction")]');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
jpw.dealloc_json(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let functionName = process.argv[2];
|
let functionName = process.argv[2];
|
||||||
|
|
||||||
switch (functionName) {
|
switch (functionName) {
|
||||||
case 'compareJsonpath':
|
case 'jsonpath':
|
||||||
compareJsonpath('$..book[?(@.price<30 && @.category=="fiction")]');
|
jsonpath();
|
||||||
break;
|
break;
|
||||||
case 'compareEmptyFunction':
|
case 'wasmSelector':
|
||||||
compareEmptyFunction();
|
wasmSelector();
|
||||||
break;
|
break;
|
||||||
case 'jsonpathWasmOnly':
|
case 'wasmCompile':
|
||||||
jsonpathWasmOnly();
|
wasmCompile();
|
||||||
break;
|
break;
|
||||||
|
case 'wasmSelect':
|
||||||
|
wasmSelect();
|
||||||
|
break;
|
||||||
|
case 'wasmCompileAlloc':
|
||||||
|
wasmCompileAlloc();
|
||||||
|
break;
|
||||||
|
case 'wasmSelectAlloc':
|
||||||
|
wasmSelectAlloc();
|
||||||
default:
|
default:
|
||||||
jsonpathOnly();
|
console.error('Invalid function name');
|
||||||
}
|
}
|
||||||
|
19
benches/javascript/package-lock.json
generated
19
benches/javascript/package-lock.json
generated
@ -9,15 +9,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
|
||||||
"integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40="
|
"integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40="
|
||||||
},
|
},
|
||||||
"benchmark": {
|
|
||||||
"version": "2.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
|
|
||||||
"integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=",
|
|
||||||
"requires": {
|
|
||||||
"lodash": "^4.17.4",
|
|
||||||
"platform": "^1.3.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cjson": {
|
"cjson": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.2.1.tgz",
|
||||||
@ -131,11 +122,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz",
|
||||||
"integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA="
|
"integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA="
|
||||||
},
|
},
|
||||||
"lodash": {
|
|
||||||
"version": "4.17.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
|
||||||
},
|
|
||||||
"nomnom": {
|
"nomnom": {
|
||||||
"version": "1.5.2",
|
"version": "1.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz",
|
||||||
@ -165,11 +151,6 @@
|
|||||||
"wordwrap": "~1.0.0"
|
"wordwrap": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"platform": {
|
|
||||||
"version": "1.3.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
|
|
||||||
"integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
|
|
||||||
},
|
|
||||||
"prelude-ls": {
|
"prelude-ls": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonpath": "*",
|
"jsonpath": "*"
|
||||||
"benchmark": "*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
BIN
docs/9a826648f4cbc2bc8591.module.wasm
Normal file
BIN
docs/9a826648f4cbc2bc8591.module.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
BIN
docs/bench/9a826648f4cbc2bc8591.module.wasm
Normal file
BIN
docs/bench/9a826648f4cbc2bc8591.module.wasm
Normal file
Binary file not shown.
36
docs/bench/bootstrap.js
vendored
36
docs/bench/bootstrap.js
vendored
@ -55,20 +55,29 @@
|
|||||||
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
|
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
|
||||||
/******/ return {
|
/******/ return {
|
||||||
/******/ "./jsonpath_wasm": {
|
/******/ "./jsonpath_wasm": {
|
||||||
|
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
||||||
|
/******/ },
|
||||||
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
/******/ "__widl_f_log_1_": function(p0i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
/******/ "__wbindgen_number_get": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_is_string": function(p0i32) {
|
/******/ "__wbindgen_is_string": function(p0i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
||||||
@ -76,17 +85,14 @@
|
|||||||
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper33": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper33"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper35": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper35"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ };
|
/******/ };
|
||||||
@ -186,7 +192,7 @@
|
|||||||
/******/ promises.push(installedWasmModuleData);
|
/******/ promises.push(installedWasmModuleData);
|
||||||
/******/ else {
|
/******/ else {
|
||||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"95acaf85df86c0a76234"}[wasmModuleId] + ".module.wasm");
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"9a826648f4cbc2bc8591"}[wasmModuleId] + ".module.wasm");
|
||||||
/******/ var promise;
|
/******/ var promise;
|
||||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
60
docs/bootstrap.js
vendored
60
docs/bootstrap.js
vendored
@ -52,41 +52,47 @@
|
|||||||
/******/ function promiseResolve() { return Promise.resolve(); }
|
/******/ function promiseResolve() { return Promise.resolve(); }
|
||||||
/******/
|
/******/
|
||||||
/******/ var wasmImportObjects = {
|
/******/ var wasmImportObjects = {
|
||||||
/******/ "../pkg/jsonpath_wasm_bg.wasm": function() {
|
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
|
||||||
/******/ return {
|
/******/ return {
|
||||||
/******/ "./jsonpath_wasm": {
|
/******/ "./jsonpath_wasm": {
|
||||||
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_is_string": function(p0i32) {
|
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
|
||||||
/******/ },
|
|
||||||
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__widl_f_log_1_": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_number_get": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_is_string": function(p0i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper28": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper28"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper30": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper30"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ };
|
/******/ };
|
||||||
@ -176,7 +182,7 @@
|
|||||||
/******/
|
/******/
|
||||||
/******/ // Fetch + compile chunk loading for webassembly
|
/******/ // Fetch + compile chunk loading for webassembly
|
||||||
/******/
|
/******/
|
||||||
/******/ var wasmModules = {"0":["../pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
|
/******/ var wasmModules = {"0":["../browser_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
|
||||||
/******/
|
/******/
|
||||||
/******/ wasmModules.forEach(function(wasmModuleId) {
|
/******/ wasmModules.forEach(function(wasmModuleId) {
|
||||||
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
|
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
|
||||||
@ -186,7 +192,7 @@
|
|||||||
/******/ promises.push(installedWasmModuleData);
|
/******/ promises.push(installedWasmModuleData);
|
||||||
/******/ else {
|
/******/ else {
|
||||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/jsonpath_wasm_bg.wasm":"d6c7cff8a1d228da11b7"}[wasmModuleId] + ".module.wasm");
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"9a826648f4cbc2bc8591"}[wasmModuleId] + ".module.wasm");
|
||||||
/******/ var promise;
|
/******/ var promise;
|
||||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
Binary file not shown.
@ -23,7 +23,7 @@ mod tests {
|
|||||||
fn new_value_filter(file: &str) -> ValueFilter {
|
fn new_value_filter(file: &str) -> ValueFilter {
|
||||||
let string = read_json(file);
|
let string = read_json(file);
|
||||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||||
ValueFilter::new(json, false, false)
|
ValueFilter::new(json.into(), false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_filter(path: &str, file: &str) -> JsonValueFilter {
|
fn do_filter(path: &str, file: &str) -> JsonValueFilter {
|
||||||
@ -71,7 +71,7 @@ mod tests {
|
|||||||
"Vincent Cannon",
|
"Vincent Cannon",
|
||||||
"Gray Berry"
|
"Gray Berry"
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, current.get_val());
|
assert_eq!(friends, current.get_val().into_value());
|
||||||
}
|
}
|
||||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||||
{
|
{
|
||||||
@ -84,7 +84,7 @@ mod tests {
|
|||||||
"Vincent Cannon",
|
"Vincent Cannon",
|
||||||
"Gray Berry"
|
"Gray Berry"
|
||||||
]);
|
]);
|
||||||
assert_eq!(&names, current.get_val());
|
assert_eq!(names, current.get_val().into_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,32 +98,32 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
|
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
|
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json");
|
let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{"id": 0, "name": "Millicent Norman"}
|
{"id": 0, "name": "Millicent Norman"}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[2].name", "./benches/data_obj.json");
|
let jf = do_filter("$..friends[2].name", "./benches/data_obj.json");
|
||||||
let friends = json!(["Gray Berry", "Gray Berry"]);
|
let friends = json!(["Gray Berry", "Gray Berry"]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[*].name", "./benches/data_obj.json");
|
let jf = do_filter("$..friends[*].name", "./benches/data_obj.json");
|
||||||
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
||||||
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
||||||
let friends = json!("Millicent Norman");
|
let friends = json!("Millicent Norman");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -139,16 +139,16 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let jf = do_filter("$.school", "./benches/data_obj.json");
|
let jf = do_filter("$.school", "./benches/data_obj.json");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||||
assert_eq!(&Value::Null, jf.current_value());
|
assert_eq!(Value::Null, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
|
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
@ -156,7 +156,7 @@ mod tests {
|
|||||||
{"id": 1, "name": "Vincent Cannon" },
|
{"id": 1, "name": "Vincent Cannon" },
|
||||||
{"id": 2, "name": "Gray Berry"}
|
{"id": 2, "name": "Gray Berry"}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -171,42 +171,42 @@ mod tests {
|
|||||||
{"id": 2, "name": "Gray Berry"}
|
{"id": 2, "name": "Gray Berry"}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json");
|
let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
{ "id" : 1, "name" : "Vincent Cannon" },
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
{ "id" : 2, "name" : "Gray Berry" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
{ "id" : 2, "name" : "Gray Berry" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
||||||
let friends = json!([
|
let friends = json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" },
|
{ "id" : 2, "name" : "Gray Berry" },
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" }
|
{ "id" : 1, "name" : "Vincent Cannon" }
|
||||||
]);
|
]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
||||||
assert_eq!(&Value::Null, jf.current_value());
|
assert_eq!(Value::Null, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
||||||
let friends = json!([0, 0]);
|
let friends = json!([0, 0]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
||||||
let friends = json!([22.99]);
|
let friends = json!([22.99]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
||||||
let friends = json!([12.99]);
|
let friends = json!([12.99]);
|
||||||
assert_eq!(&friends, jf.current_value());
|
assert_eq!(friends, jf.current_value().into_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -215,10 +215,10 @@ mod tests {
|
|||||||
|
|
||||||
let jf = do_filter("$.store.book[*].author", "./benches/example.json");
|
let jf = do_filter("$.store.book[*].author", "./benches/example.json");
|
||||||
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..author", "./benches/example.json");
|
let jf = do_filter("$..author", "./benches/example.json");
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.store.*", "./benches/example.json");
|
let jf = do_filter("$.store.*", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -230,11 +230,11 @@ mod tests {
|
|||||||
],
|
],
|
||||||
{"color" : "red","price" : 19.95},
|
{"color" : "red","price" : 19.95},
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.store..price", "./benches/example.json");
|
let jf = do_filter("$.store..price", "./benches/example.json");
|
||||||
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[2]", "./benches/example.json");
|
let jf = do_filter("$..book[2]", "./benches/example.json");
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
@ -244,7 +244,7 @@ mod tests {
|
|||||||
"isbn" : "0-553-21311-3",
|
"isbn" : "0-553-21311-3",
|
||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}]);
|
}]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[-2]", "./benches/example.json");
|
let jf = do_filter("$..book[-2]", "./benches/example.json");
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
@ -254,7 +254,7 @@ mod tests {
|
|||||||
"isbn" : "0-553-21311-3",
|
"isbn" : "0-553-21311-3",
|
||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}]);
|
}]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[0,1]", "./benches/example.json");
|
let jf = do_filter("$..book[0,1]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -271,7 +271,7 @@ mod tests {
|
|||||||
"price" : 12.99
|
"price" : 12.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[:2]", "./benches/example.json");
|
let jf = do_filter("$..book[:2]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -288,7 +288,7 @@ mod tests {
|
|||||||
"price" : 12.99
|
"price" : 12.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[2:]", "./benches/example.json");
|
let jf = do_filter("$..book[2:]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -307,7 +307,7 @@ mod tests {
|
|||||||
"price" : 22.99
|
"price" : 22.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json");
|
let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -326,7 +326,7 @@ mod tests {
|
|||||||
"price" : 22.99
|
"price" : 22.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -344,10 +344,10 @@ mod tests {
|
|||||||
"price" : 8.99
|
"price" : 8.99
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
assert_eq!(&ret, jf.current_value());
|
assert_eq!(ret, jf.current_value().into_value());
|
||||||
|
|
||||||
let jf = do_filter("$..*", "./benches/example.json");
|
let jf = do_filter("$..*", "./benches/example.json");
|
||||||
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
|
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
|
||||||
assert_eq!(&json, jf.current_value());
|
assert_eq!(json, jf.current_value().into_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ pub enum TermContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TermContext {
|
impl TermContext {
|
||||||
fn cmp<F: PrivCmp + IntoType>(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext {
|
fn cmp<F: PrivCmp + IntoType>(&self, other: &TermContext, cmp_fn: F, default: bool) -> TermContext {
|
||||||
match self {
|
match self {
|
||||||
TermContext::Constants(et) => {
|
TermContext::Constants(et) => {
|
||||||
match other {
|
match other {
|
||||||
@ -51,7 +51,7 @@ impl TermContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_cond(&mut self, other: &mut TermContext, cmp_cond_type: CmpCondType) -> TermContext {
|
fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext {
|
||||||
match self {
|
match self {
|
||||||
TermContext::Constants(et) => {
|
TermContext::Constants(et) => {
|
||||||
match other {
|
match other {
|
||||||
@ -86,35 +86,35 @@ impl TermContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn eq(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpEq, false)
|
self.cmp(other, CmpEq, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ne(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn ne(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpNe, true)
|
self.cmp(other, CmpNe, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gt(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn gt(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpGt, false)
|
self.cmp(other, CmpGt, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ge(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn ge(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpGe, false)
|
self.cmp(other, CmpGe, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lt(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn lt(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpLt, false)
|
self.cmp(other, CmpLt, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn le(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn le(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp(other, CmpLe, false)
|
self.cmp(other, CmpLe, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn and(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp_cond(other, CmpCondType::And)
|
self.cmp_cond(other, CmpCondType::And)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn or(&mut self, other: &mut TermContext) -> TermContext {
|
pub fn or(&self, other: &TermContext) -> TermContext {
|
||||||
self.cmp_cond(other, CmpCondType::Or)
|
self.cmp_cond(other, CmpCondType::Or)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
use core::borrow::Borrow;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
|
use ref_value::*;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::parser::*;
|
use super::parser::*;
|
||||||
|
|
||||||
use super::term::*;
|
use super::term::*;
|
||||||
use super::value_wrapper::*;
|
use super::value_wrapper::*;
|
||||||
|
|
||||||
trait ArrayIndex {
|
trait ArrayIndex {
|
||||||
fn index(&self, v: &Value) -> usize;
|
fn index(&self, v: &RefValueWrapper) -> usize;
|
||||||
|
|
||||||
fn take_value(&self, v: &mut Value) -> Value {
|
fn take_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
|
||||||
let idx = self.index(v);
|
let idx = self.index(v);
|
||||||
match v.get_mut(idx) {
|
match v.get(idx) {
|
||||||
Some(v) => v.take(),
|
Some(v) => v,
|
||||||
_ => Value::Null
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArrayIndex for f64 {
|
impl ArrayIndex for f64 {
|
||||||
fn index(&self, v: &Value) -> usize {
|
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||||
if v.is_array() && self < &0_f64 {
|
if v.is_array() && self < &0_f64 {
|
||||||
(v.as_array().unwrap().len() as f64 + self) as usize
|
(v.as_array().unwrap().len() as f64 + self) as usize
|
||||||
} else {
|
} else {
|
||||||
@ -33,7 +32,7 @@ impl ArrayIndex for f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArrayIndex for isize {
|
impl ArrayIndex for isize {
|
||||||
fn index(&self, v: &Value) -> usize {
|
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||||
if v.is_array() && self < &0_isize {
|
if v.is_array() && self < &0_isize {
|
||||||
(v.as_array().unwrap().len() as isize + self) as usize
|
(v.as_array().unwrap().len() as isize + self) as usize
|
||||||
} else {
|
} else {
|
||||||
@ -43,7 +42,7 @@ impl ArrayIndex for isize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArrayIndex for usize {
|
impl ArrayIndex for usize {
|
||||||
fn index(&self, _: &Value) -> usize {
|
fn index(&self, _: &RefValueWrapper) -> usize {
|
||||||
*self as usize
|
*self as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,54 +62,55 @@ pub struct ValueFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ValueFilter {
|
impl ValueFilter {
|
||||||
pub fn new(v: Value, is_leaves: bool, filter_mode: bool) -> Self {
|
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
|
||||||
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a mut Value>>(iter: I) -> Vec<Value> {
|
fn iter_to_value_vec<'a, I: Iterator<Item=&'a TypeRefValue>>(iter: I) -> Vec<TypeRefValue> {
|
||||||
iter.map(|v| v.take())
|
iter
|
||||||
|
.map(|v| v.clone())
|
||||||
.filter(|v| !v.is_null())
|
.filter(|v| !v.is_null())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_nested_array<F: ArrayIndex>(v: &mut Value, key: F, filter_mode: bool) -> Value {
|
fn get_nested_array<F: ArrayIndex>(v: &RefValueWrapper, key: F, filter_mode: bool) -> RefValueWrapper {
|
||||||
if v.is_array() && v.as_array().unwrap().get(key.index(v)).is_some() {
|
if v.is_array() && v.as_array().unwrap().get(key.index(v)).is_some() {
|
||||||
if filter_mode {
|
if filter_mode {
|
||||||
v.take()
|
v.clone()
|
||||||
} else {
|
} else {
|
||||||
let idx = key.index(v);
|
let idx = key.index(v);
|
||||||
v.get_mut(idx).unwrap().take()
|
v.get(idx).unwrap().clone()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
key.take_value(v)
|
key.take_value(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_nested_object(v: &mut Value, key: &String, filter_mode: bool) -> Value {
|
fn get_nested_object(v: &RefValueWrapper, key: &String, filter_mode: bool) -> RefValueWrapper {
|
||||||
if v.is_object() && v.as_object().unwrap().contains_key(key) {
|
if v.is_object() && v.as_object().unwrap().contains_key(key) {
|
||||||
if filter_mode {
|
if filter_mode {
|
||||||
v.take()
|
v.clone()
|
||||||
} else {
|
} else {
|
||||||
v.get_mut(key).unwrap().take()
|
v.get(key.clone()).unwrap().clone()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Value::Null
|
RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_all(key: Option<&String>, v: &Value, buf: &mut Vec<Value>) {
|
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<TypeRefValue>) {
|
||||||
match v {
|
match v.get_data_ref() {
|
||||||
Value::Array(vec) => {
|
RefValue::Array(vec) => {
|
||||||
if key.is_none() {
|
if key.is_none() {
|
||||||
for v in vec {
|
for v in vec {
|
||||||
buf.push(v.clone());
|
buf.push(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i in vec {
|
for i in vec {
|
||||||
Self::collect_all(key, &i, buf);
|
Self::collect_all(key, &i.into(), buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Object(v) => {
|
RefValue::Object(v) => {
|
||||||
for (k, v) in v.into_iter() {
|
for (k, v) in v.into_iter() {
|
||||||
if match key {
|
if match key {
|
||||||
Some(map_key) => map_key == k,
|
Some(map_key) => map_key == k,
|
||||||
@ -120,7 +120,7 @@ impl ValueFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, v) in v.into_iter() {
|
for (_, v) in v.into_iter() {
|
||||||
Self::collect_all(key, &v, buf);
|
Self::collect_all(key, &v.into(), buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -133,7 +133,7 @@ impl ValueFilter {
|
|||||||
Self::collect_all(None, &self.vw.get_val(), &mut buf);
|
Self::collect_all(None, &self.vw.get_val(), &mut buf);
|
||||||
trace!("step_leaves_all - {:?}", buf);
|
trace!("step_leaves_all - {:?}", buf);
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
self.vw = ValueWrapper::new(Value::Array(buf), true);
|
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
||||||
&self.vw
|
&self.vw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,53 +143,63 @@ impl ValueFilter {
|
|||||||
|
|
||||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
||||||
debug!("step_leaves_string");
|
debug!("step_leaves_string");
|
||||||
let mut buf: Vec<Value> = Vec::new();
|
let mut buf = Vec::new();
|
||||||
Self::collect_all(Some(key), &self.vw.get_val(), &mut buf);
|
Self::collect_all(Some(key), &self.vw.get_val(), &mut buf);
|
||||||
trace!("step_leaves_string - {:?}", buf);
|
trace!("step_leaves_string - {:?}", buf);
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
self.vw = ValueWrapper::new(Value::Array(buf), true);
|
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
||||||
&self.vw
|
&self.vw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
||||||
debug!("step_in_all");
|
debug!("step_in_all");
|
||||||
|
|
||||||
let vec = match &mut self.vw.get_val_mut() {
|
let vec = match self.vw.get_val().get_data_ref() {
|
||||||
Value::Object(map) => Self::iter_to_value_vec(map.values_mut()),
|
RefValue::Object(ref map) => {
|
||||||
Value::Array(list) => Self::iter_to_value_vec(list.iter_mut()),
|
Self::iter_to_value_vec(map.values())
|
||||||
Value::Null => Vec::new(),
|
}
|
||||||
other => vec![other.take()]
|
RefValue::Array(ref list) => {
|
||||||
|
Self::iter_to_value_vec(list.iter())
|
||||||
|
}
|
||||||
|
RefValue::Null => Vec::new(),
|
||||||
|
_ => vec![self.vw.get_val().clone_data()]
|
||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
self.vw.replace(Value::Array(vec));
|
self.vw.replace(RefValue::Array(vec).into());
|
||||||
trace!("step_in_all - {:?}", self.vw.get_val());
|
trace!("step_in_all - {:?}", self.vw.get_val().get_data_ref());
|
||||||
&self.vw
|
&self.vw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
|
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
|
||||||
debug!("step_in_num");
|
debug!("step_in_num");
|
||||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val());
|
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||||
|
, self.vw.is_leaves()
|
||||||
|
, self.filter_mode
|
||||||
|
, self.vw.get_val().get_data_ref());
|
||||||
|
|
||||||
let v = if self.vw.is_leaves() {
|
let v = if self.vw.is_leaves() {
|
||||||
let filter_mode = self.filter_mode;
|
let filter_mode = self.filter_mode;
|
||||||
match &mut self.vw.get_val_mut() {
|
match self.vw.get_val().get_data_ref() {
|
||||||
Value::Array(v) => {
|
RefValue::Array(ref vec) => {
|
||||||
let vec: Vec<Value> = v.iter_mut()
|
let mut ret = Vec::new();
|
||||||
.map(|v| Self::get_nested_array(v, *key, filter_mode))
|
for v in vec {
|
||||||
.filter(|v| !v.is_null())
|
let wrapper = Self::get_nested_array(&v.into(), *key, filter_mode);
|
||||||
.collect();
|
if !wrapper.is_null() {
|
||||||
Value::Array(vec)
|
ret.push(wrapper.clone_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RefValue::Array(ret).into()
|
||||||
}
|
}
|
||||||
other => key.take_value(other)
|
_ => key.take_value(&self.vw.get_val())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
key.take_value(self.vw.get_val_mut())
|
key.take_value(&self.vw.get_val())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
||||||
self.vw.replace(v);
|
self.vw.replace(v);
|
||||||
trace!("step_in_num - after: {:?}", self.vw.get_val());
|
trace!("step_in_num - after: {:?}", self.vw.get_val().get_data_ref());
|
||||||
&self.vw
|
&self.vw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,55 +209,68 @@ impl ValueFilter {
|
|||||||
|
|
||||||
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
||||||
debug!("step_in_string");
|
debug!("step_in_string");
|
||||||
trace!("step_in_string - before: {},{},{:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val());
|
trace!("step_in_string - before: {},{},{:?}"
|
||||||
|
, self.vw.is_leaves()
|
||||||
|
, self.filter_mode
|
||||||
|
, self.vw.get_val().get_data_ref());
|
||||||
|
|
||||||
let filter_mode = self.filter_mode;
|
let filter_mode = self.filter_mode;
|
||||||
let is_leaves = self.vw.is_leaves();
|
let is_leaves = self.vw.is_leaves();
|
||||||
let v = match &mut self.vw.get_val_mut() {
|
let val = match self.vw.get_val().get_data_ref() {
|
||||||
Value::Array(ref mut vec) if is_leaves => {
|
RefValue::Array(ref vec) if is_leaves => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
for mut item in vec {
|
for mut v in vec {
|
||||||
if let Value::Array(v) = item {
|
let wrapper: RefValueWrapper = v.into();
|
||||||
let mut ret: Vec<Value> = v.iter_mut()
|
if wrapper.is_array() {
|
||||||
.map(|v| Self::get_nested_object(v, key, filter_mode))
|
let vec = wrapper.as_array().unwrap();
|
||||||
.filter(|v| !v.is_null())
|
let mut ret = Vec::new();
|
||||||
.collect();
|
for v in vec {
|
||||||
|
let nested_wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
|
||||||
|
if !nested_wrapper.is_null() {
|
||||||
|
ret.push(nested_wrapper.clone_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
buf.append(&mut ret);
|
buf.append(&mut ret);
|
||||||
} else {
|
} else {
|
||||||
match item.get_mut(key) {
|
match wrapper.get(key.clone()) {
|
||||||
Some(v) => buf.push(v.take()),
|
Some(v) => buf.push(v.clone_data()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Array(buf)
|
RefValue::Array(buf).into()
|
||||||
}
|
}
|
||||||
Value::Array(v) if !is_leaves => {
|
RefValue::Array(ref vec) if !is_leaves => {
|
||||||
let vec: Vec<Value> = v.iter_mut()
|
let mut ret = Vec::new();
|
||||||
.map(|v| Self::get_nested_object(v, key, filter_mode))
|
for v in vec {
|
||||||
.filter(|v| !v.is_null())
|
let wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
|
||||||
.collect();
|
if !wrapper.is_null() {
|
||||||
|
ret.push(wrapper.clone_data());
|
||||||
Value::Array(vec)
|
}
|
||||||
|
}
|
||||||
|
RefValue::Array(ret).into()
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
match other.get_mut(key) {
|
match self.vw.get_val().get(key.clone()) {
|
||||||
Some(v) => v.take(),
|
Some(v) => v.clone(),
|
||||||
_ => Value::Null
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
self.vw.replace(v);
|
self.vw.replace(val);
|
||||||
trace!("step_in_string - after: {},{},{:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val());
|
trace!("step_in_string - after: {},{},{:?}"
|
||||||
|
, self.vw.is_leaves()
|
||||||
|
, self.filter_mode
|
||||||
|
, self.vw.get_val().get_data_ref());
|
||||||
&self.vw
|
&self.vw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct JsonValueFilter {
|
pub struct JsonValueFilter {
|
||||||
json: Rc<Box<Value>>,
|
json: RefValueWrapper,
|
||||||
filter_stack: Vec<ValueFilter>,
|
filter_stack: Vec<ValueFilter>,
|
||||||
token_stack: Vec<ParseToken>,
|
token_stack: Vec<ParseToken>,
|
||||||
term_stack: Vec<TermContext>,
|
term_stack: Vec<TermContext>,
|
||||||
@ -257,12 +280,12 @@ impl JsonValueFilter {
|
|||||||
pub fn new(json: &str) -> result::Result<Self, String> {
|
pub fn new(json: &str) -> result::Result<Self, String> {
|
||||||
let json: Value = serde_json::from_str(json)
|
let json: Value = serde_json::from_str(json)
|
||||||
.map_err(|e| e.description().to_string())?;
|
.map_err(|e| e.description().to_string())?;
|
||||||
Ok(JsonValueFilter::new_from_value(Rc::new(Box::new(json))))
|
Ok(JsonValueFilter::new_from_value(json.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_value(json: Rc<Box<Value>>) -> Self {
|
pub fn new_from_value(json: RefValueWrapper) -> Self {
|
||||||
JsonValueFilter {
|
JsonValueFilter {
|
||||||
json: json,
|
json,
|
||||||
filter_stack: Vec::new(),
|
filter_stack: Vec::new(),
|
||||||
token_stack: Vec::new(),
|
token_stack: Vec::new(),
|
||||||
term_stack: Vec::new(),
|
term_stack: Vec::new(),
|
||||||
@ -287,14 +310,13 @@ impl JsonValueFilter {
|
|||||||
Some(self.filter_stack.push(vf))
|
Some(self.filter_stack.push(vf))
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let v: &Value = self.json.as_ref().borrow();
|
|
||||||
self.filter_stack.push({
|
self.filter_stack.push({
|
||||||
ValueFilter::new(v.clone(), false, from_current)
|
ValueFilter::new(self.json.clone(), false, from_current)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_filter_stack(&mut self, v: Value, is_leaves: bool) {
|
fn replace_filter_stack(&mut self, v: RefValueWrapper, is_leaves: bool) {
|
||||||
if self.filter_stack.is_empty() {
|
if self.filter_stack.is_empty() {
|
||||||
self.filter_stack.push(ValueFilter::new(v, is_leaves, false));
|
self.filter_stack.push(ValueFilter::new(v, is_leaves, false));
|
||||||
} else {
|
} else {
|
||||||
@ -312,17 +334,17 @@ impl JsonValueFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_value(&self) -> &Value {
|
pub fn current_value(&self) -> RefValueWrapper {
|
||||||
match self.filter_stack.last() {
|
match self.filter_stack.last() {
|
||||||
Some(v) => &v.vw.get_val(),
|
Some(v) => v.vw.get_val().clone(),
|
||||||
_ => &Value::Null
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_value(&mut self) -> Value {
|
pub fn take_value(&mut self) -> RefValueWrapper {
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(v) => v.vw.get_val_mut().take(),
|
Some(v) => v.vw.get_val().clone(),
|
||||||
_ => Value::Null
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,25 +353,28 @@ impl JsonValueFilter {
|
|||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
||||||
if let Value::Array(mut val) = vf.vw.get_val_mut().take() {
|
let mut ret = Vec::new();
|
||||||
let mut ret = Vec::new();
|
if let RefValue::Array(val) = vf.vw.get_val().get_data_ref() {
|
||||||
for mut v in &mut val {
|
for mut v in val {
|
||||||
for i in &indices {
|
for i in &indices {
|
||||||
let v = i.take_value(v);
|
let v = i.take_value(&v.into());
|
||||||
if !v.is_null() {
|
if !v.is_null() {
|
||||||
ret.push(v);
|
ret.push(v.clone_data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vf.vw.replace(Value::Array(ret));
|
|
||||||
}
|
}
|
||||||
|
vf.vw.replace(RefValue::Array(ret).into());
|
||||||
}
|
}
|
||||||
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
||||||
let ret = indices.into_iter()
|
let mut ret = Vec::new();
|
||||||
.map(|i| i.take_value(vf.vw.get_val_mut()))
|
for i in indices {
|
||||||
.filter(|v| !v.is_null())
|
let wrapper = i.take_value(&vf.vw.get_val());
|
||||||
.collect();
|
if !wrapper.is_null() {
|
||||||
vf.vw.replace(Value::Array(ret));
|
ret.push(wrapper.clone_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vf.vw.replace(RefValue::Array(ret).into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -358,43 +383,51 @@ impl JsonValueFilter {
|
|||||||
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
|
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
|
||||||
self.token_stack.pop();
|
self.token_stack.pop();
|
||||||
|
|
||||||
fn _from_to<F: ArrayIndex>(from: Option<F>, to: Option<F>, val: &Value) -> (usize, usize) {
|
fn _from_to<F: ArrayIndex>(from: Option<F>, to: Option<F>, val: &RefValueWrapper) -> (usize, usize) {
|
||||||
let from = match from {
|
let from = match from {
|
||||||
Some(v) => v.index(val),
|
Some(v) => v.index(val),
|
||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
let to = match to {
|
let to = match to {
|
||||||
Some(v) => v.index(val),
|
Some(v) => v.index(val),
|
||||||
_ => if let Value::Array(v) = val { v.len() } else { 0 }
|
_ => {
|
||||||
|
if let RefValue::Array(v) = val.get_data_ref() {
|
||||||
|
v.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
(from, to)
|
(from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _range(from: usize, to: usize, v: &mut Value) -> Vec<Value> {
|
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<TypeRefValue> {
|
||||||
trace!("range - {}:{}", from, to);
|
trace!("range - {}:{}", from, to);
|
||||||
|
|
||||||
(from..to).into_iter()
|
(from..to).into_iter()
|
||||||
.map(|i| i.take_value(v))
|
.map(|i| i.take_value(v))
|
||||||
.filter(|v| !v.is_null())
|
.filter(|v| !v.is_null())
|
||||||
|
.map(|v| v.clone_data())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
||||||
if let Value::Array(mut vec) = vf.vw.get_val_mut().take() {
|
let mut buf = Vec::new();
|
||||||
let mut buf = Vec::new();
|
if let RefValue::Array(vec) = vf.vw.get_val().get_data_ref() {
|
||||||
for mut item in &mut vec {
|
for mut v in vec {
|
||||||
let (from, to) = _from_to(from, to, item);
|
let wrapper = v.into();
|
||||||
let mut v: Vec<Value> = _range(from, to, item);
|
let (from, to) = _from_to(from, to, &wrapper);
|
||||||
|
let mut v: Vec<TypeRefValue> = _range(from, to, &wrapper);
|
||||||
buf.append(&mut v);
|
buf.append(&mut v);
|
||||||
}
|
}
|
||||||
vf.vw.replace(Value::Array(buf));
|
|
||||||
}
|
}
|
||||||
|
vf.vw.replace(RefValue::Array(buf).into());
|
||||||
}
|
}
|
||||||
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
||||||
let (from, to) = _from_to(from, to, vf.vw.get_val());
|
let (from, to) = _from_to(from, to, &vf.vw.get_val());
|
||||||
let v: Vec<Value> = _range(from, to, vf.vw.get_val_mut());
|
let vec: Vec<TypeRefValue> = _range(from, to, vf.vw.get_val());
|
||||||
vf.vw.replace(Value::Array(v));
|
vf.vw.replace(RefValue::Array(vec).into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -449,19 +482,19 @@ impl JsonValueFilter {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(TermContext::Json(_, mut vw)) => {
|
Some(TermContext::Json(_, vw)) => {
|
||||||
self.replace_filter_stack(vw.get_val_mut().take(), vw.is_leaves());
|
self.replace_filter_stack(vw.get_val().clone(), vw.is_leaves());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
match self.filter_stack.pop() {
|
match self.filter_stack.pop() {
|
||||||
Some(mut vf) => {
|
Some(mut vf) => {
|
||||||
let is_leaves = vf.vw.is_leaves();
|
let is_leaves = vf.vw.is_leaves();
|
||||||
match vf.vw.get_val_mut() {
|
match vf.vw.get_val().get_data_ref() {
|
||||||
Value::Null | Value::Bool(false) => {
|
RefValue::Null | RefValue::Bool(false) => {
|
||||||
self.replace_filter_stack(Value::Null, is_leaves);
|
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
self.replace_filter_stack(other.take(), is_leaves);
|
self.replace_filter_stack(vf.vw.get_val().clone(), is_leaves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,18 +512,18 @@ impl JsonValueFilter {
|
|||||||
trace!("right {:?}", right);
|
trace!("right {:?}", right);
|
||||||
|
|
||||||
if left.is_some() && right.is_some() {
|
if left.is_some() && right.is_some() {
|
||||||
let mut left = left.unwrap();
|
let left = left.unwrap();
|
||||||
let mut right = right.unwrap();
|
let right = right.unwrap();
|
||||||
|
|
||||||
let tc = match ft {
|
let tc = match ft {
|
||||||
FilterToken::Equal => left.eq(&mut right),
|
FilterToken::Equal => left.eq(&right),
|
||||||
FilterToken::NotEqual => left.ne(&mut right),
|
FilterToken::NotEqual => left.ne(&right),
|
||||||
FilterToken::Greater => left.gt(&mut right),
|
FilterToken::Greater => left.gt(&right),
|
||||||
FilterToken::GreaterOrEqual => left.ge(&mut right),
|
FilterToken::GreaterOrEqual => left.ge(&right),
|
||||||
FilterToken::Little => left.lt(&mut right),
|
FilterToken::Little => left.lt(&right),
|
||||||
FilterToken::LittleOrEqual => left.le(&mut right),
|
FilterToken::LittleOrEqual => left.le(&right),
|
||||||
FilterToken::And => left.and(&mut right),
|
FilterToken::And => left.and(&right),
|
||||||
FilterToken::Or => left.or(&mut right),
|
FilterToken::Or => left.or(&right),
|
||||||
};
|
};
|
||||||
self.term_stack.push(tc);
|
self.term_stack.push(tc);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use indexmap::map::IndexMap;
|
use indexmap::map::IndexMap;
|
||||||
|
use ref_value::*;
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use super::cmp::*;
|
use super::cmp::*;
|
||||||
use super::term::*;
|
use super::term::*;
|
||||||
@ -8,12 +7,12 @@ use super::value_filter::*;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ValueWrapper {
|
pub struct ValueWrapper {
|
||||||
val: Value,
|
val: RefValueWrapper,
|
||||||
is_leaves: bool,
|
is_leaves: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueWrapper {
|
impl ValueWrapper {
|
||||||
pub fn new(val: Value, leaves: bool) -> Self {
|
pub fn new(val: RefValueWrapper, leaves: bool) -> Self {
|
||||||
ValueWrapper { val, is_leaves: leaves }
|
ValueWrapper { val, is_leaves: leaves }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ impl ValueWrapper {
|
|||||||
self.is_leaves = is_leaves;
|
self.is_leaves = is_leaves;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmp(&mut self, other: &mut ValueWrapper, cmp_type: CmpType) -> TermContext {
|
pub fn cmp(&self, other: &ValueWrapper, cmp_type: CmpType) -> TermContext {
|
||||||
match cmp_type {
|
match cmp_type {
|
||||||
CmpType::Eq => {
|
CmpType::Eq => {
|
||||||
TermContext::Json(None, self.intersect(other))
|
TermContext::Json(None, self.intersect(other))
|
||||||
@ -39,24 +38,19 @@ impl ValueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_with_term<F: PrivCmp>(val: &Value, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
||||||
match val {
|
match val.get_data_ref() {
|
||||||
Value::Bool(ref v1) => {
|
RefValue::Bool(ref v1) => {
|
||||||
match et {
|
match et {
|
||||||
ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) },
|
ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) },
|
||||||
_ => default
|
_ => default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Number(ref v1) => match v1.as_f64() {
|
RefValue::Number(ref v1) => match et {
|
||||||
Some(ref v1) => {
|
ExprTerm::Number(v2) => if reverse { cmp_fn.cmp_f64(v2, &v1.as_f64().unwrap()) } else { cmp_fn.cmp_f64(&v1.as_f64().unwrap(), v2) },
|
||||||
match et {
|
|
||||||
ExprTerm::Number(v2) => if reverse { cmp_fn.cmp_f64(v2, v1) } else { cmp_fn.cmp_f64(v1, v2) },
|
|
||||||
_ => default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => default
|
_ => default
|
||||||
},
|
},
|
||||||
Value::String(ref v1) => {
|
RefValue::String(ref v1) => {
|
||||||
match et {
|
match et {
|
||||||
ExprTerm::String(v2) => if reverse { cmp_fn.cmp_string(v2, v1) } else { cmp_fn.cmp_string(v1, v2) },
|
ExprTerm::String(v2) => if reverse { cmp_fn.cmp_string(v2, v1) } else { cmp_fn.cmp_string(v1, v2) },
|
||||||
_ => default
|
_ => default
|
||||||
@ -66,12 +60,12 @@ impl ValueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_object_in_array<F: PrivCmp>(&mut self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
fn take_object_in_array<F: PrivCmp>(&self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
||||||
fn _filter_with_object<F: Fn(&Value) -> bool>(v: &&mut Value, key: &String, fun: F) -> bool {
|
fn _filter_with_object<F: Fn(&RefValueWrapper) -> bool>(v: &RefValueWrapper, key: &String, fun: F) -> bool {
|
||||||
match &v {
|
match v.get_data_ref() {
|
||||||
Value::Object(map) => {
|
RefValue::Object(map) => {
|
||||||
match map.get(key) {
|
match map.get(key) {
|
||||||
Some(vv) => fun(vv),
|
Some(val) => fun(&val.into()),
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,21 +73,24 @@ impl ValueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.val.take() {
|
match self.val.get_data_ref() {
|
||||||
Value::Array(mut vec) => {
|
RefValue::Array(vec) => {
|
||||||
let mut ret: Vec<Value> = vec.iter_mut()
|
let mut ret = Vec::new();
|
||||||
.filter(|v| {
|
for v in vec {
|
||||||
_filter_with_object(v, key, |vv| Self::cmp_with_term(vv, et, cmp, false, reverse))
|
if _filter_with_object(&v.into(), key, |vv| {
|
||||||
})
|
Self::cmp_with_term(vv, et, cmp, false, reverse)
|
||||||
.map(|v| v.take())
|
}) {
|
||||||
.collect();
|
ret.push(v.clone());
|
||||||
Some(ValueWrapper::new(Value::Array(ret), false))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_with_key_type<F: PrivCmp>(&mut self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
fn take_with_key_type<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
||||||
match key {
|
match key {
|
||||||
Some(ValueFilterKey::String(key)) => {
|
Some(ValueFilterKey::String(key)) => {
|
||||||
self.take_object_in_array(key, et, cmp, reverse)
|
self.take_object_in_array(key, et, cmp, reverse)
|
||||||
@ -102,23 +99,25 @@ impl ValueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_with<F: PrivCmp>(&mut self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
|
pub fn take_with<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
|
||||||
match self.take_with_key_type(key, et, &cmp, reverse) {
|
match self.take_with_key_type(key, et, &cmp, reverse) {
|
||||||
Some(vw) => vw,
|
Some(vw) => vw,
|
||||||
_ => {
|
_ => {
|
||||||
match self.val.take() {
|
match self.val.get_data_ref() {
|
||||||
Value::Array(mut vec) => {
|
RefValue::Array(vec) => {
|
||||||
let mut ret = vec.iter_mut()
|
let mut ret = Vec::new();
|
||||||
.filter(|v| Self::cmp_with_term(&v, et, &cmp, false, reverse))
|
for v in vec {
|
||||||
.map(|v| v.take())
|
if Self::cmp_with_term(&v.into(), et, &cmp, false, reverse) {
|
||||||
.collect();
|
ret.push(v.clone());
|
||||||
ValueWrapper::new(Value::Array(ret), false)
|
}
|
||||||
|
}
|
||||||
|
ValueWrapper::new(RefValue::Array(ret).into(), false)
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
if Self::cmp_with_term(&other, et, &cmp, false, reverse) {
|
if Self::cmp_with_term(&self.val, et, &cmp, false, reverse) {
|
||||||
ValueWrapper::new(other, false)
|
ValueWrapper::new(self.val.clone(), false)
|
||||||
} else {
|
} else {
|
||||||
ValueWrapper::new(Value::Null, false)
|
ValueWrapper::new(RefValue::Null.into(), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,24 +125,25 @@ impl ValueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace(&mut self, val: Value) {
|
pub fn replace(&mut self, val: RefValueWrapper) {
|
||||||
let is_null = match &val {
|
let is_null = match val.get_data_ref() {
|
||||||
Value::Array(v) => if v.is_empty() { true } else { false },
|
RefValue::Array(v) => if v.is_empty() { true } else { false },
|
||||||
Value::Object(m) => if m.is_empty() { true } else { false },
|
RefValue::Object(m) => if m.is_empty() { true } else { false },
|
||||||
_ => val.is_null()
|
_ => val.is_null()
|
||||||
};
|
};
|
||||||
self.val = if is_null { Value::Null } else { val };
|
self.val = if is_null {
|
||||||
|
let v = RefValueWrapper::wrap(RefValue::Null);
|
||||||
|
RefValueWrapper::new(v)
|
||||||
|
} else {
|
||||||
|
val
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_val(&self) -> &Value {
|
pub fn get_val(&self) -> &RefValueWrapper {
|
||||||
&self.val
|
&self.val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_val_mut(&mut self) -> &mut Value {
|
pub fn clone_val(&self) -> RefValueWrapper {
|
||||||
&mut self.val
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_val(&self) -> Value {
|
|
||||||
self.val.clone()
|
self.val.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,150 +151,161 @@ impl ValueWrapper {
|
|||||||
self.val.is_array()
|
self.val.is_array()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uuid(v: &Value) -> String {
|
fn uuid(v: &RefValueWrapper) -> String {
|
||||||
fn _fn(v: &Value) -> String {
|
fn _fn(v: &RefValueWrapper, acc: &mut String) {
|
||||||
match v {
|
match v.get_data_ref() {
|
||||||
Value::Null => "null".to_string(),
|
RefValue::Null => acc.push_str("null"),
|
||||||
Value::String(v) => v.to_string(),
|
RefValue::String(v) => acc.push_str(v),
|
||||||
Value::Bool(v) => v.to_string(),
|
RefValue::Bool(v) => acc.push_str(if *v { "true" } else { "false" }),
|
||||||
Value::Number(v) => v.to_string(),
|
RefValue::Number(v) => acc.push_str(&*v.to_string()),
|
||||||
Value::Array(v) => {
|
RefValue::Array(v) => {
|
||||||
v.iter().enumerate()
|
for (i, v) in v.iter().enumerate() {
|
||||||
.map(|(i, v)| { format!("{}{}", i, _fn(v)) })
|
acc.push_str(&*i.to_string());
|
||||||
.collect()
|
_fn(&v.into(), acc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Value::Object(v) => {
|
RefValue::Object(ref v) => {
|
||||||
v.into_iter().map(|(k, v)| { format!("{}{}", k, _fn(v)) }).collect()
|
for (k, v) in v.into_iter() {
|
||||||
|
acc.push_str(&*k.to_string());
|
||||||
|
_fn(&v.into(), acc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_fn(v)
|
let mut acc = String::new();
|
||||||
|
_fn(v, &mut acc);
|
||||||
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_map(&mut self) -> IndexMap<String, Value> {
|
fn into_map(&self) -> IndexMap<String, RefValueWrapper> {
|
||||||
let mut map = IndexMap::new();
|
let mut map = IndexMap::new();
|
||||||
match &mut self.val {
|
match self.val.get_data_ref() {
|
||||||
Value::Array(v1) => {
|
RefValue::Array(ref v1) => {
|
||||||
for v in v1 {
|
for v in v1 {
|
||||||
map.insert(Self::uuid(v), v.take());
|
let wrapper = v.into();
|
||||||
|
let key = Self::uuid(&wrapper);
|
||||||
|
map.insert(key, wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
map.insert(Self::uuid(other), other.take());
|
map.insert(Self::uuid(&self.val), self.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn except(&mut self, other: &mut Self) -> Self {
|
pub fn except(&self, other: &Self) -> Self {
|
||||||
let map = self.into_map();
|
let map = self.into_map();
|
||||||
let mut ret: IndexMap<String, Value> = IndexMap::new();
|
let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||||
match &mut other.val {
|
match other.val.get_data_ref() {
|
||||||
Value::Array(v1) => {
|
RefValue::Array(ref v1) => {
|
||||||
for v in v1 {
|
for v in v1 {
|
||||||
let key = Self::uuid(v);
|
let wrapper = v.into();
|
||||||
|
let key = Self::uuid(&wrapper);
|
||||||
if !map.contains_key(&key) {
|
if !map.contains_key(&key) {
|
||||||
ret.insert(key, v.take());
|
ret.insert(key, wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
let key = Self::uuid(other);
|
let key = Self::uuid(&other.val);
|
||||||
if !map.contains_key(&key) {
|
if !map.contains_key(&key) {
|
||||||
ret.insert(key, other.take());
|
ret.insert(key, other.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let v = ret.values_mut().into_iter().map(|v| v.take()).collect();
|
let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
|
||||||
ValueWrapper::new(v, false)
|
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersect(&mut self, other: &mut Self) -> Self {
|
pub fn intersect(&self, other: &Self) -> Self {
|
||||||
let map = self.into_map();
|
let map = self.into_map();
|
||||||
let mut ret: IndexMap<String, Value> = IndexMap::new();
|
let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||||
match &mut other.val {
|
match other.val.get_data_ref() {
|
||||||
Value::Array(v1) => {
|
RefValue::Array(ref v1) => {
|
||||||
for v in v1 {
|
for v in v1 {
|
||||||
let key = Self::uuid(v);
|
let wrapper = v.into();
|
||||||
|
let key = Self::uuid(&wrapper);
|
||||||
if map.contains_key(&key) {
|
if map.contains_key(&key) {
|
||||||
ret.insert(key, v.take());
|
ret.insert(key, wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
let key = Self::uuid(other);
|
let key = Self::uuid(&other.val);
|
||||||
if map.contains_key(&key) {
|
if map.contains_key(&key) {
|
||||||
ret.insert(key, other.take());
|
ret.insert(key, other.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let v = ret.values_mut().into_iter().map(|v| v.take()).collect();
|
let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
|
||||||
ValueWrapper::new(v, false)
|
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union(&mut self, other: &mut Self) -> Self {
|
pub fn union(&self, other: &Self) -> Self {
|
||||||
let mut map = self.into_map();
|
let mut map = self.into_map();
|
||||||
match &mut other.val {
|
match other.val.get_data_ref() {
|
||||||
Value::Array(v1) => {
|
RefValue::Array(ref v1) => {
|
||||||
for v in v1 {
|
for v in v1 {
|
||||||
let key = Self::uuid(v);
|
let wrapper = v.into();
|
||||||
|
let key = Self::uuid(&wrapper);
|
||||||
if !map.contains_key(&key) {
|
if !map.contains_key(&key) {
|
||||||
map.insert(key, v.take());
|
map.insert(key, wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
_ => {
|
||||||
let key = Self::uuid(other);
|
let key = Self::uuid(&other.val);
|
||||||
if !map.contains_key(&key) {
|
if !map.contains_key(&key) {
|
||||||
map.insert(key, other.take());
|
map.insert(key, other.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vw = ValueWrapper::new(Value::Null, false);
|
let mut vw = ValueWrapper::new(RefValue::Null.into(), false);
|
||||||
let list: Vec<Value> = map.values_mut().into_iter().map(|val| val.take()).collect();
|
let list = map.values().into_iter().map(|val| val.clone_data()).collect();
|
||||||
vw.replace(Value::Array(list));
|
vw.replace(RefValue::Array(list).into());
|
||||||
vw
|
vw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_term(&mut self, key: &mut Option<ValueFilterKey>) -> TermContext {
|
pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
|
||||||
match self.val.take() {
|
match self.val.get_data_ref() {
|
||||||
Value::String(s) => TermContext::Constants(ExprTerm::String(s)),
|
RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
|
||||||
Value::Number(n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
||||||
Value::Bool(b) => TermContext::Constants(ExprTerm::Bool(b)),
|
RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
|
||||||
other => TermContext::Json(match key {
|
_ => TermContext::Json(match key {
|
||||||
Some(vk) => Some(vk.clone()),
|
Some(vk) => Some(vk.clone()),
|
||||||
_ => None
|
_ => None
|
||||||
}, ValueWrapper::new(other, false))
|
}, ValueWrapper::new(self.val.clone(), false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter(&mut self, key: &mut Option<ValueFilterKey>) -> Self {
|
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
|
||||||
let v = match &mut self.val {
|
let v = match self.val.get_data_ref() {
|
||||||
Value::Array(vec) => {
|
RefValue::Array(ref vec) => {
|
||||||
let ret = vec.iter_mut()
|
let mut ret = Vec::new();
|
||||||
.filter(|v| match key {
|
for v in vec {
|
||||||
Some(ValueFilterKey::String(val_key)) => {
|
if let Some(ValueFilterKey::String(k)) = key {
|
||||||
v.get(val_key.as_str()).is_some()
|
let wrapper: RefValueWrapper = v.into();
|
||||||
|
if wrapper.get(k.clone()).is_some() {
|
||||||
|
ret.push(v.clone());
|
||||||
}
|
}
|
||||||
_ => false
|
}
|
||||||
})
|
}
|
||||||
.map(|v| v.take())
|
RefValue::Array(ret).into()
|
||||||
.collect();
|
|
||||||
Value::Array(ret)
|
|
||||||
}
|
}
|
||||||
Value::Object(map) => {
|
RefValue::Object(ref map) => {
|
||||||
match key {
|
match key {
|
||||||
Some(ValueFilterKey::String(val_key)) => match map.get_mut(val_key) {
|
Some(ValueFilterKey::String(k)) => match map.get(k) {
|
||||||
Some(v) => v.take(),
|
Some(v) => v.into(),
|
||||||
_ => Value::Null
|
_ => RefValue::Null.into()
|
||||||
},
|
},
|
||||||
_ => Value::Null
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => other.take()
|
_ => self.val.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
ValueWrapper::new(v, false)
|
ValueWrapper::new(v, false)
|
||||||
|
73
src/lib.rs
73
src/lib.rs
@ -43,26 +43,26 @@
|
|||||||
//! "expensive": 10
|
//! "expensive": 10
|
||||||
//! });
|
//! });
|
||||||
//!
|
//!
|
||||||
//! let mut reader = jsonpath::reader(json_obj);
|
//! let mut selector = jsonpath::selector(json_obj);
|
||||||
//!
|
//!
|
||||||
//! //
|
//! //
|
||||||
//! // $.store.book[*].author
|
//! // $.store.book[*].author
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$.store.book[*].author").unwrap();
|
//! let json = selector("$.store.book[*].author").unwrap();
|
||||||
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||||
//! assert_eq!(json, ret);
|
//! assert_eq!(json, ret);
|
||||||
//!
|
//!
|
||||||
//! //
|
//! //
|
||||||
//! // $..author
|
//! // $..author
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..author").unwrap();
|
//! let json = selector("$..author").unwrap();
|
||||||
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||||
//! assert_eq!(json, ret);
|
//! assert_eq!(json, ret);
|
||||||
//!
|
//!
|
||||||
//! //
|
//! //
|
||||||
//! // $.store.*
|
//! // $.store.*
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$.store.*").unwrap();
|
//! let json = selector("$.store.*").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! [
|
//! [
|
||||||
//! {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
|
//! {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
|
||||||
@ -77,14 +77,14 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $.store..price
|
//! // $.store..price
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$.store..price").unwrap();
|
//! let json = selector("$.store..price").unwrap();
|
||||||
//! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
//! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||||
//! assert_eq!(ret, json);
|
//! assert_eq!(ret, json);
|
||||||
//!
|
//!
|
||||||
//! //
|
//! //
|
||||||
//! // $..book[2]
|
//! // $..book[2]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[2]").unwrap();
|
//! let json = selector("$..book[2]").unwrap();
|
||||||
//! let ret = json!([{
|
//! let ret = json!([{
|
||||||
//! "category" : "fiction",
|
//! "category" : "fiction",
|
||||||
//! "author" : "Herman Melville",
|
//! "author" : "Herman Melville",
|
||||||
@ -97,7 +97,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $..book[-2]
|
//! // $..book[-2]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[-2]").unwrap();
|
//! let json = selector("$..book[-2]").unwrap();
|
||||||
//! let ret = json!([{
|
//! let ret = json!([{
|
||||||
//! "category" : "fiction",
|
//! "category" : "fiction",
|
||||||
//! "author" : "Herman Melville",
|
//! "author" : "Herman Melville",
|
||||||
@ -110,7 +110,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $..book[0,1]
|
//! // $..book[0,1]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[0,1]").unwrap();
|
//! let json = selector("$..book[0,1]").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
||||||
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
|
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
|
||||||
@ -120,7 +120,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $..book[:2]
|
//! // $..book[:2]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[:2]").unwrap();
|
//! let json = selector("$..book[:2]").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
||||||
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
|
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
|
||||||
@ -130,7 +130,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $..book[2:]
|
//! // $..book[2:]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[2:]").unwrap();
|
//! let json = selector("$..book[2:]").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
|
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
|
||||||
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
|
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
|
||||||
@ -140,7 +140,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $..book[?(@.isbn)]
|
//! // $..book[?(@.isbn)]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$..book[?(@.isbn)]").unwrap();
|
//! let json = selector("$..book[?(@.isbn)]").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
|
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
|
||||||
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
|
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
|
||||||
@ -150,7 +150,7 @@
|
|||||||
//! //
|
//! //
|
||||||
//! // $.store.book[?(@.price < 10)]
|
//! // $.store.book[?(@.price < 10)]
|
||||||
//! //
|
//! //
|
||||||
//! let json = reader("$.store.book[?(@.price < 10)]").unwrap();
|
//! let json = selector("$.store.book[?(@.price < 10)]").unwrap();
|
||||||
//! let ret = json!([
|
//! let ret = json!([
|
||||||
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
|
||||||
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}
|
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}
|
||||||
@ -175,14 +175,17 @@ extern crate indexmap;
|
|||||||
pub mod parser;
|
pub mod parser;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod ref_value;
|
||||||
|
|
||||||
use parser::parser::*;
|
use parser::parser::*;
|
||||||
use filter::value_filter::*;
|
use filter::value_filter::*;
|
||||||
|
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::rc::Rc;
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use ref_value::*;
|
||||||
|
|
||||||
type Result = result::Result<Value, String>;
|
type Result = result::Result<Value, String>;
|
||||||
|
|
||||||
/// # Read multiple Json multiple times with the same JsonPath
|
/// # Read multiple Json multiple times with the same JsonPath
|
||||||
@ -223,9 +226,9 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(Value) -> Result + 'a {
|
|||||||
move |json| {
|
move |json| {
|
||||||
match &node {
|
match &node {
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json)));
|
let mut jf = JsonValueFilter::new_from_value(json.into());
|
||||||
jf.visit(n.clone());
|
jf.visit(n.clone());
|
||||||
Ok(jf.take_value())
|
Ok(jf.take_value().into_value())
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.clone())
|
Err(e) => Err(e.clone())
|
||||||
}
|
}
|
||||||
@ -246,26 +249,31 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(Value) -> Result + 'a {
|
|||||||
/// "friends": [{"id": 0},{"id": 1}]
|
/// "friends": [{"id": 0},{"id": 1}]
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// let mut reader = jsonpath::reader(json_obj);
|
/// let mut selector = jsonpath::selector(json_obj);
|
||||||
///
|
///
|
||||||
/// let json = reader("$..friends[0]").unwrap();
|
/// let json = selector("$..friends[0]").unwrap();
|
||||||
/// let ret = json!([ {"id": 0}, {"id": 0} ]);
|
/// let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
///
|
///
|
||||||
/// let json = reader("$..friends[1]").unwrap();
|
/// let json = selector("$..friends[1]").unwrap();
|
||||||
/// let ret = json!([ {"id": 1}, {"id": 1} ]);
|
/// let ret = json!([ {"id": 1}, {"id": 1} ]);
|
||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn reader(json: Value) -> impl FnMut(&str) -> Result {
|
pub fn selector(json: Value) -> impl FnMut(&str) -> Result {
|
||||||
let n = Rc::new(Box::new(json));
|
let wrapper: RefValueWrapper = json.into();
|
||||||
move |path: &str| {
|
move |path: &str| {
|
||||||
let mut jf = JsonValueFilter::new_from_value(n.clone());
|
let mut jf = JsonValueFilter::new_from_value(wrapper.clone());
|
||||||
let mut parser = Parser::new(path);
|
let mut parser = Parser::new(path);
|
||||||
parser.parse(&mut jf)?;
|
parser.parse(&mut jf)?;
|
||||||
Ok(jf.take_value())
|
Ok(jf.take_value().into_value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Read the same Json multiple times using different JsonPath - Deprecated. use selector
|
||||||
|
pub fn reader(json: Value) -> impl FnMut(&str) -> Result {
|
||||||
|
selector(json)
|
||||||
|
}
|
||||||
|
|
||||||
/// # Read Json using JsonPath
|
/// # Read Json using JsonPath
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -278,15 +286,20 @@ pub fn reader(json: Value) -> impl FnMut(&str) -> Result {
|
|||||||
/// },
|
/// },
|
||||||
/// "friends": [{"id": 0}, {"id": 1}]
|
/// "friends": [{"id": 0}, {"id": 1}]
|
||||||
/// });
|
/// });
|
||||||
/// let json = jsonpath::read(json_obj, "$..friends[0]").unwrap();
|
/// let json = jsonpath::select(json_obj, "$..friends[0]").unwrap();
|
||||||
/// let ret = json!([ {"id": 0}, {"id": 0} ]);
|
/// let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn read(json: Value, path: &str) -> Result {
|
pub fn select(json: Value, path: &str) -> Result {
|
||||||
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json)));
|
let mut jf = JsonValueFilter::new_from_value(json.into());
|
||||||
let mut parser = Parser::new(path);
|
let mut parser = Parser::new(path);
|
||||||
parser.parse(&mut jf)?;
|
parser.parse(&mut jf)?;
|
||||||
Ok(jf.take_value())
|
Ok(jf.take_value().into_value())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Read Json using JsonPath - Deprecated. use select
|
||||||
|
pub fn read(json: Value, path: &str) -> Result {
|
||||||
|
select(json, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -323,9 +336,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reader() {
|
fn selector() {
|
||||||
let json_obj = read_json("./benches/data_obj.json");
|
let json_obj = read_json("./benches/data_obj.json");
|
||||||
let mut reader = super::reader(json_obj);
|
let mut reader = super::selector(json_obj);
|
||||||
let json = reader("$..friends[2]").unwrap();
|
let json = reader("$..friends[2]").unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
{"id": 2,"name": "Gray Berry"},
|
{"id": 2,"name": "Gray Berry"},
|
||||||
@ -342,9 +355,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read() {
|
fn select() {
|
||||||
let json_obj = read_json("./benches/example.json");
|
let json_obj = read_json("./benches/example.json");
|
||||||
let json = super::read(json_obj, "$..book[2]").unwrap();
|
let json = super::select(json_obj, "$..book[2]").unwrap();
|
||||||
let ret = json!([{
|
let ret = json!([{
|
||||||
"category" : "fiction",
|
"category" : "fiction",
|
||||||
"author" : "Herman Melville",
|
"author" : "Herman Melville",
|
||||||
|
@ -13,25 +13,21 @@ type Result<T> = result::Result<T, String>;
|
|||||||
mod utils {
|
mod utils {
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
pub fn vec_to_int<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<isize, String>
|
pub fn string_to_isize<F>(string: &String, msg_handler: F) -> result::Result<isize, String>
|
||||||
where F: Fn() -> String {
|
where F: Fn() -> String {
|
||||||
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<isize>() {
|
match string.as_str().parse::<isize>() {
|
||||||
Ok(n) => Ok(n),
|
Ok(n) => Ok(n),
|
||||||
_ => Err(msg_handler())
|
_ => Err(msg_handler())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vec_to_float<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<f64, String>
|
pub fn string_to_f64<F>(string: &String, msg_handler: F) -> result::Result<f64, String>
|
||||||
where F: Fn() -> String {
|
where F: Fn() -> String {
|
||||||
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<f64>() {
|
match string.as_str().parse::<f64>() {
|
||||||
Ok(n) => Ok(n),
|
Ok(n) => Ok(n),
|
||||||
_ => Err(msg_handler())
|
_ => Err(msg_handler())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vec_to_string(vec: &Vec<char>) -> String {
|
|
||||||
vec.iter().map(|c| *c).collect::<String>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -236,7 +232,7 @@ impl<'a> Parser<'a> {
|
|||||||
debug!("#key");
|
debug!("#key");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(_, v)) => {
|
Ok(Token::Key(_, v)) => {
|
||||||
Ok(self.node(ParseToken::Key(utils::vec_to_string(&v))))
|
Ok(self.node(ParseToken::Key(v)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Err(self.tokenizer.err_msg())
|
Err(self.tokenizer.err_msg())
|
||||||
@ -247,9 +243,9 @@ impl<'a> Parser<'a> {
|
|||||||
fn array_quota_value(&mut self) -> Result<Node> {
|
fn array_quota_value(&mut self) -> Result<Node> {
|
||||||
debug!("#array_quota_value");
|
debug!("#array_quota_value");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::SingleQuoted(_, ref vec))
|
Ok(Token::SingleQuoted(_, val))
|
||||||
| Ok(Token::DoubleQuoted(_, ref vec)) => {
|
| Ok(Token::DoubleQuoted(_, val)) => {
|
||||||
Ok(self.node(ParseToken::Key(utils::vec_to_string(vec))))
|
Ok(self.node(ParseToken::Key(val)))
|
||||||
}
|
}
|
||||||
Err(TokenError::Eof) => {
|
Err(TokenError::Eof) => {
|
||||||
Ok(self.node(ParseToken::Eof))
|
Ok(self.node(ParseToken::Eof))
|
||||||
@ -299,9 +295,8 @@ impl<'a> Parser<'a> {
|
|||||||
fn array_value_key(&mut self) -> Result<Node> {
|
fn array_value_key(&mut self) -> Result<Node> {
|
||||||
debug!("#array_value_key");
|
debug!("#array_value_key");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, ref vec)) => {
|
Ok(Token::Key(pos, ref val)) => {
|
||||||
let digit = utils::vec_to_int(vec,
|
let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
self.eat_whitespace();
|
self.eat_whitespace();
|
||||||
|
|
||||||
match self.tokenizer.peek_token() {
|
match self.tokenizer.peek_token() {
|
||||||
@ -357,9 +352,8 @@ impl<'a> Parser<'a> {
|
|||||||
self.eat_token();
|
self.eat_token();
|
||||||
self.eat_whitespace();
|
self.eat_whitespace();
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, ref vec)) => {
|
Ok(Token::Key(pos, ref val)) => {
|
||||||
let digit = utils::vec_to_int(vec,
|
let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
values.push(digit);
|
values.push(digit);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -387,9 +381,8 @@ impl<'a> Parser<'a> {
|
|||||||
fn range_to(&mut self) -> Result<Node> {
|
fn range_to(&mut self) -> Result<Node> {
|
||||||
debug!("#range_to");
|
debug!("#range_to");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, ref vec)) => {
|
Ok(Token::Key(pos, ref val)) => {
|
||||||
let digit = utils::vec_to_int(vec,
|
let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
Ok(self.node(ParseToken::Range(None, Some(digit))))
|
Ok(self.node(ParseToken::Range(None, Some(digit))))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -401,9 +394,8 @@ impl<'a> Parser<'a> {
|
|||||||
fn range(&mut self, num: isize) -> Result<Node> {
|
fn range(&mut self, num: isize) -> Result<Node> {
|
||||||
debug!("#range");
|
debug!("#range");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, ref vec)) => {
|
Ok(Token::Key(pos, ref val)) => {
|
||||||
let digit = utils::vec_to_int(vec,
|
let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
Ok(self.node(ParseToken::Range(Some(num), Some(digit))))
|
Ok(self.node(ParseToken::Range(Some(num), Some(digit))))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -505,14 +497,13 @@ impl<'a> Parser<'a> {
|
|||||||
fn term_num(&mut self) -> Result<Node> {
|
fn term_num(&mut self) -> Result<Node> {
|
||||||
debug!("#term_num");
|
debug!("#term_num");
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, mut vec)) => {
|
Ok(Token::Key(pos, val)) => {
|
||||||
match self.tokenizer.peek_token() {
|
match self.tokenizer.peek_token() {
|
||||||
Ok(Token::Dot(_)) => {
|
Ok(Token::Dot(_)) => {
|
||||||
self.term_num_float(&mut vec)
|
self.term_num_float(val.as_str())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let number = utils::vec_to_float(&vec,
|
let number = utils::string_to_f64(&val, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
Ok(self.node(ParseToken::Number(number)))
|
Ok(self.node(ParseToken::Number(number)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,17 +517,16 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term_num_float(&mut self, mut num: &mut Vec<char>) -> Result<Node> {
|
fn term_num_float(&mut self, mut num: &str) -> Result<Node> {
|
||||||
debug!("#term_num_float");
|
debug!("#term_num_float");
|
||||||
self.eat_token();
|
self.eat_token();
|
||||||
match self.tokenizer.next_token() {
|
match self.tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, mut frac)) => {
|
Ok(Token::Key(pos, frac)) => {
|
||||||
let mut f = vec![];
|
let mut f = String::new();
|
||||||
f.append(&mut num);
|
f.push_str(&mut num);
|
||||||
f.push('.');
|
f.push('.');
|
||||||
f.append(&mut frac);
|
f.push_str(frac.as_str());
|
||||||
let number = utils::vec_to_float(&f,
|
let number = utils::string_to_f64(&f, || self.tokenizer.err_msg_with_pos(pos))?;
|
||||||
|| self.tokenizer.err_msg_with_pos(pos))?;
|
|
||||||
Ok(self.node(ParseToken::Number(number)))
|
Ok(self.node(ParseToken::Number(number)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -23,19 +23,23 @@ impl<'a> PathReader<'a> {
|
|||||||
Ok((self.pos + ch.len_utf8(), ch))
|
Ok((self.pos + ch.len_utf8(), ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_while<F>(&mut self, fun: F) -> result::Result<(usize, Vec<char>), ReaderError>
|
pub fn take_while<F>(&mut self, fun: F) -> result::Result<(usize, String), ReaderError>
|
||||||
where
|
where
|
||||||
F: Fn(&char) -> bool
|
F: Fn(&char) -> bool
|
||||||
{
|
{
|
||||||
let vec: Vec<char> = self.input.chars()
|
let mut char_len: usize = 0;
|
||||||
.by_ref()
|
let mut ret = String::new();
|
||||||
.take_while(fun)
|
for c in self.input.chars().by_ref() {
|
||||||
.collect();
|
if !fun(&c) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char_len += c.len_utf8();
|
||||||
|
ret.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
let char_len: usize = vec.iter().by_ref().map(|c| c.len_utf8()).sum();
|
|
||||||
self.pos += char_len;
|
self.pos += char_len;
|
||||||
self.input = &self.input[char_len..];
|
self.input = &self.input[char_len..];
|
||||||
Ok((self.pos, vec))
|
Ok((self.pos, ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_char(&mut self) -> result::Result<(usize, char), ReaderError> {
|
pub fn next_char(&mut self) -> result::Result<(usize, char), ReaderError> {
|
||||||
|
@ -75,9 +75,9 @@ pub enum Token {
|
|||||||
Split(usize),
|
Split(usize),
|
||||||
OpenParenthesis(usize),
|
OpenParenthesis(usize),
|
||||||
CloseParenthesis(usize),
|
CloseParenthesis(usize),
|
||||||
Key(usize, Vec<char>),
|
Key(usize, String),
|
||||||
DoubleQuoted(usize, Vec<char>),
|
DoubleQuoted(usize, String),
|
||||||
SingleQuoted(usize, Vec<char>),
|
SingleQuoted(usize, String),
|
||||||
Equal(usize),
|
Equal(usize),
|
||||||
GreaterOrEqual(usize),
|
GreaterOrEqual(usize),
|
||||||
Greater(usize),
|
Greater(usize),
|
||||||
@ -153,15 +153,15 @@ impl<'a> Tokenizer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn single_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
|
fn single_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
|
||||||
let (_, vec) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||||
self.input.next_char().map_err(to_token_error)?;
|
self.input.next_char().map_err(to_token_error)?;
|
||||||
Ok(Token::SingleQuoted(pos, vec))
|
Ok(Token::SingleQuoted(pos, val))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn double_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
|
fn double_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
|
||||||
let (_, vec) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||||
self.input.next_char().map_err(to_token_error)?;
|
self.input.next_char().map_err(to_token_error)?;
|
||||||
Ok(Token::DoubleQuoted(pos, vec))
|
Ok(Token::DoubleQuoted(pos, val))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equal(&mut self, pos: usize, _: char) -> result::Result<Token, TokenError> {
|
fn equal(&mut self, pos: usize, _: char) -> result::Result<Token, TokenError> {
|
||||||
@ -414,9 +414,9 @@ mod tests {
|
|||||||
vec![
|
vec![
|
||||||
Token::Absolute(0),
|
Token::Absolute(0),
|
||||||
Token::Dot(1),
|
Token::Dot(1),
|
||||||
Token::Key(2, vec!['0', '1']),
|
Token::Key(2, "01".to_string()),
|
||||||
Token::Dot(4),
|
Token::Dot(4),
|
||||||
Token::Key(5, vec!['a'])
|
Token::Key(5, "a".to_string())
|
||||||
]
|
]
|
||||||
, Some(TokenError::Eof)
|
, Some(TokenError::Eof)
|
||||||
));
|
));
|
||||||
@ -449,7 +449,7 @@ mod tests {
|
|||||||
Token::Absolute(0),
|
Token::Absolute(0),
|
||||||
Token::Dot(1),
|
Token::Dot(1),
|
||||||
Token::Dot(2),
|
Token::Dot(2),
|
||||||
Token::Key(3, vec!['a', 'b'])
|
Token::Key(3, "ab".to_string())
|
||||||
]
|
]
|
||||||
, Some(TokenError::Eof)
|
, Some(TokenError::Eof)
|
||||||
));
|
));
|
||||||
@ -460,7 +460,7 @@ mod tests {
|
|||||||
Token::Absolute(0),
|
Token::Absolute(0),
|
||||||
Token::Dot(1),
|
Token::Dot(1),
|
||||||
Token::Dot(2),
|
Token::Dot(2),
|
||||||
Token::Key(3, vec!['가']),
|
Token::Key(3, "가".to_string()),
|
||||||
Token::Whitespace(6, 0),
|
Token::Whitespace(6, 0),
|
||||||
Token::OpenArray(7),
|
Token::OpenArray(7),
|
||||||
]
|
]
|
||||||
@ -471,10 +471,10 @@ mod tests {
|
|||||||
(
|
(
|
||||||
vec![
|
vec![
|
||||||
Token::OpenArray(0),
|
Token::OpenArray(0),
|
||||||
Token::Key(1, vec!['-', '1']),
|
Token::Key(1, "-1".to_string()),
|
||||||
Token::Comma(3),
|
Token::Comma(3),
|
||||||
Token::Whitespace(4, 0),
|
Token::Whitespace(4, 0),
|
||||||
Token::Key(5, vec!['2']),
|
Token::Key(5, "2".to_string()),
|
||||||
Token::Whitespace(6, 0),
|
Token::Whitespace(6, 0),
|
||||||
Token::CloseArray(7),
|
Token::CloseArray(7),
|
||||||
]
|
]
|
||||||
@ -486,19 +486,19 @@ mod tests {
|
|||||||
vec![
|
vec![
|
||||||
Token::OpenArray(0),
|
Token::OpenArray(0),
|
||||||
Token::Whitespace(1, 0),
|
Token::Whitespace(1, 0),
|
||||||
Token::Key(2, vec!['1']),
|
Token::Key(2, "1".to_string()),
|
||||||
Token::Whitespace(3, 0),
|
Token::Whitespace(3, 0),
|
||||||
Token::Key(4, vec!['2']),
|
Token::Key(4, "2".to_string()),
|
||||||
Token::Whitespace(5, 0),
|
Token::Whitespace(5, 0),
|
||||||
Token::Comma(6),
|
Token::Comma(6),
|
||||||
Token::Whitespace(7, 0),
|
Token::Whitespace(7, 0),
|
||||||
Token::Key(8, vec!['3']),
|
Token::Key(8, "3".to_string()),
|
||||||
Token::Whitespace(9, 0),
|
Token::Whitespace(9, 0),
|
||||||
Token::DoubleQuoted(10, vec!['a', 'b', 'c']),
|
Token::DoubleQuoted(10, "abc".to_string()),
|
||||||
Token::Whitespace(15, 0),
|
Token::Whitespace(15, 0),
|
||||||
Token::Split(16),
|
Token::Split(16),
|
||||||
Token::Whitespace(17, 0),
|
Token::Whitespace(17, 0),
|
||||||
Token::Key(18, vec!['-', '1', '0']),
|
Token::Key(18, "-10".to_string()),
|
||||||
Token::Whitespace(21, 0),
|
Token::Whitespace(21, 0),
|
||||||
Token::CloseArray(22),
|
Token::CloseArray(22),
|
||||||
]
|
]
|
||||||
@ -512,12 +512,12 @@ mod tests {
|
|||||||
Token::OpenParenthesis(1),
|
Token::OpenParenthesis(1),
|
||||||
Token::At(2),
|
Token::At(2),
|
||||||
Token::Dot(3),
|
Token::Dot(3),
|
||||||
Token::Key(4, vec!['a', '가']),
|
Token::Key(4, "a가".to_string()),
|
||||||
Token::Whitespace(8, 0),
|
Token::Whitespace(8, 0),
|
||||||
Token::Little(9),
|
Token::Little(9),
|
||||||
Token::Key(10, vec!['4', '1']),
|
Token::Key(10, "41".to_string()),
|
||||||
Token::Dot(12),
|
Token::Dot(12),
|
||||||
Token::Key(13, vec!['0', '1']),
|
Token::Key(13, "01".to_string()),
|
||||||
Token::CloseParenthesis(15),
|
Token::CloseParenthesis(15),
|
||||||
]
|
]
|
||||||
, Some(TokenError::Eof)
|
, Some(TokenError::Eof)
|
||||||
@ -530,12 +530,12 @@ mod tests {
|
|||||||
Token::OpenParenthesis(1),
|
Token::OpenParenthesis(1),
|
||||||
Token::At(2),
|
Token::At(2),
|
||||||
Token::Dot(3),
|
Token::Dot(3),
|
||||||
Token::Key(4, vec!['a']),
|
Token::Key(4, "a".to_string()),
|
||||||
Token::Whitespace(5, 0),
|
Token::Whitespace(5, 0),
|
||||||
Token::Little(6),
|
Token::Little(6),
|
||||||
Token::Key(7, vec!['4', 'a']),
|
Token::Key(7, "4a".to_string()),
|
||||||
Token::Dot(9),
|
Token::Dot(9),
|
||||||
Token::Key(10, vec!['0', '1']),
|
Token::Key(10, "01".to_string()),
|
||||||
Token::CloseParenthesis(12),
|
Token::CloseParenthesis(12),
|
||||||
]
|
]
|
||||||
, Some(TokenError::Eof)
|
, Some(TokenError::Eof)
|
||||||
@ -547,11 +547,11 @@ mod tests {
|
|||||||
Token::OpenParenthesis(1),
|
Token::OpenParenthesis(1),
|
||||||
Token::Absolute(2),
|
Token::Absolute(2),
|
||||||
Token::Dot(3),
|
Token::Dot(3),
|
||||||
Token::Key(4, vec!['c']),
|
Token::Key(4, "c".to_string()),
|
||||||
Token::Greater(5),
|
Token::Greater(5),
|
||||||
Token::At(6),
|
Token::At(6),
|
||||||
Token::Dot(7),
|
Token::Dot(7),
|
||||||
Token::Key(8, vec!['d']),
|
Token::Key(8, "d".to_string()),
|
||||||
Token::CloseParenthesis(9)
|
Token::CloseParenthesis(9)
|
||||||
]
|
]
|
||||||
, Some(TokenError::Eof)
|
, Some(TokenError::Eof)
|
||||||
|
384
src/ref_value/mod.rs
Normal file
384
src/ref_value/mod.rs
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
extern crate indexmap;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::convert::Into;
|
||||||
|
|
||||||
|
use indexmap::map::IndexMap;
|
||||||
|
use serde_json::Number;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
pub type TypeRefValue = Arc<Box<RefValue>>;
|
||||||
|
|
||||||
|
impl Into<RefValueWrapper> for TypeRefValue {
|
||||||
|
fn into(self) -> RefValueWrapper {
|
||||||
|
RefValueWrapper::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<RefValueWrapper> for &TypeRefValue {
|
||||||
|
fn into(self) -> RefValueWrapper {
|
||||||
|
RefValueWrapper::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// serde_json::Value 참고
|
||||||
|
///
|
||||||
|
|
||||||
|
pub trait RefIndex {
|
||||||
|
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue>;
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue>;
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefIndex for usize {
|
||||||
|
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
|
||||||
|
match *v {
|
||||||
|
RefValue::Array(ref vec) => vec.get(*self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
|
||||||
|
match *v {
|
||||||
|
RefValue::Array(ref mut vec) => vec.get_mut(*self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
|
||||||
|
match *v {
|
||||||
|
RefValue::Array(ref mut vec) => {
|
||||||
|
let len = vec.len();
|
||||||
|
vec.get_mut(*self).unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"cannot access index {} of JSON array of length {}",
|
||||||
|
self, len
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => panic!("cannot access index {} of JSON {:?}", self, v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefIndex for str {
|
||||||
|
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
|
||||||
|
match *v {
|
||||||
|
RefValue::Object(ref map) => map.get(self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
|
||||||
|
match *v {
|
||||||
|
RefValue::Object(ref mut map) => map.get_mut(self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
|
||||||
|
if let RefValue::Null = *v {
|
||||||
|
*v = RefValue::Object(IndexMap::new());
|
||||||
|
}
|
||||||
|
match *v {
|
||||||
|
RefValue::Object(ref mut map) => {
|
||||||
|
map.entry(self.to_owned()).or_insert(RefValueWrapper::wrap(RefValue::Null))
|
||||||
|
},
|
||||||
|
_ => panic!("cannot access key {:?} in JSON {:?}", self, v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefIndex for String {
|
||||||
|
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
|
||||||
|
self[..].index_into(v)
|
||||||
|
}
|
||||||
|
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
|
||||||
|
self[..].index_into_mut(v)
|
||||||
|
}
|
||||||
|
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
|
||||||
|
self[..].index_or_insert(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RefValueWrapper {
|
||||||
|
data: TypeRefValue
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefValueWrapper {
|
||||||
|
pub fn new(ref_value: TypeRefValue) -> Self {
|
||||||
|
RefValueWrapper { data: ref_value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap(ref_val: RefValue) -> TypeRefValue {
|
||||||
|
Arc::new(Box::new(ref_val))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_value(&self) -> Value {
|
||||||
|
ValueConverter::new(&self.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone(&self) -> Self {
|
||||||
|
RefValueWrapper { data: self.data.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone_data(&self) -> TypeRefValue {
|
||||||
|
self.data.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<I: RefIndex>(&self, index: I) -> Option<RefValueWrapper> {
|
||||||
|
index.index_into(&**self.data).map(|v| Self::new(v.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_object(&self) -> bool {
|
||||||
|
(**self.data).is_object()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_object(&self) -> Option<&IndexMap<String, TypeRefValue>> {
|
||||||
|
(**self.data).as_object()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_array(&self) -> bool {
|
||||||
|
(**self.data).is_array()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_array(&self) -> Option<&Vec<TypeRefValue>> {
|
||||||
|
(**self.data).as_array()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_string(&self) -> bool {
|
||||||
|
(**self.data).is_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
(**self.data).as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_number(&self) -> bool {
|
||||||
|
(**self.data).is_number()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_number(&self) -> Option<Number> {
|
||||||
|
(**self.data).as_number()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_boolean(&self) -> bool {
|
||||||
|
(**self.data).is_boolean()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_bool(&self) -> Option<bool> {
|
||||||
|
(**self.data).as_bool()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_null(&self) -> bool {
|
||||||
|
(**self.data).is_null()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_null(&self) -> Option<()> {
|
||||||
|
(**self.data).as_null()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data_ref(&self) -> &RefValue {
|
||||||
|
&(**self.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<RefValueWrapper> for Value {
|
||||||
|
fn into(self) -> RefValueWrapper {
|
||||||
|
let ref_val = RefValueConverter::new(self);
|
||||||
|
RefValueWrapper::new(ref_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RefValue {
|
||||||
|
Null,
|
||||||
|
Bool(bool),
|
||||||
|
Number(Number),
|
||||||
|
String(String),
|
||||||
|
Array(Vec<TypeRefValue>),
|
||||||
|
Object(IndexMap<String, TypeRefValue>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefValue {
|
||||||
|
pub fn get<I: RefIndex>(&self, index: I) -> Option<&TypeRefValue> {
|
||||||
|
index.index_into(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_object(&self) -> bool {
|
||||||
|
self.as_object().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_object(&self) -> Option<&IndexMap<String, TypeRefValue>> {
|
||||||
|
match *self {
|
||||||
|
RefValue::Object(ref map) => Some(map),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_array(&self) -> bool {
|
||||||
|
self.as_array().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_array(&self) -> Option<&Vec<TypeRefValue>> {
|
||||||
|
match *self {
|
||||||
|
RefValue::Array(ref array) => Some(&*array),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_string(&self) -> bool {
|
||||||
|
self.as_str().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
match *self {
|
||||||
|
RefValue::String(ref s) => Some(s),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_number(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
RefValue::Number(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_number(&self) -> Option<Number> {
|
||||||
|
match *self {
|
||||||
|
RefValue::Number(ref n) => Some(n.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_boolean(&self) -> bool {
|
||||||
|
self.as_bool().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_bool(&self) -> Option<bool> {
|
||||||
|
match *self {
|
||||||
|
RefValue::Bool(b) => Some(b),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_null(&self) -> bool {
|
||||||
|
self.as_null().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_null(&self) -> Option<()> {
|
||||||
|
match *self {
|
||||||
|
RefValue::Null => Some(()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<RefValueWrapper> for RefValue {
|
||||||
|
|
||||||
|
fn into(self) -> RefValueWrapper {
|
||||||
|
let wrap = RefValueWrapper::wrap(self);
|
||||||
|
RefValueWrapper::new(wrap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RefValueConverter;
|
||||||
|
|
||||||
|
impl RefValueConverter {
|
||||||
|
fn new(value: Value) -> TypeRefValue {
|
||||||
|
RefValueConverter {}.visit_value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_value(&self, value: Value) -> TypeRefValue {
|
||||||
|
match value {
|
||||||
|
Value::Null => self.visit_null(),
|
||||||
|
Value::Bool(v) => self.visit_bool(v),
|
||||||
|
Value::Number(v) => self.visit_number(v),
|
||||||
|
Value::String(v) => self.visit_string(v),
|
||||||
|
Value::Array(v) => self.visit_array(v),
|
||||||
|
Value::Object(v) => self.visit_object(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_null(&self) -> TypeRefValue {
|
||||||
|
RefValueWrapper::wrap(RefValue::Null)
|
||||||
|
}
|
||||||
|
fn visit_bool(&self, value: bool) -> TypeRefValue {
|
||||||
|
RefValueWrapper::wrap(RefValue::Bool(value))
|
||||||
|
}
|
||||||
|
fn visit_number(&self, value: serde_json::Number) -> TypeRefValue {
|
||||||
|
RefValueWrapper::wrap(RefValue::Number(value))
|
||||||
|
}
|
||||||
|
fn visit_string(&self, value: String) -> TypeRefValue {
|
||||||
|
RefValueWrapper::wrap(RefValue::String(value.to_string()))
|
||||||
|
}
|
||||||
|
fn visit_array(&self, value: Vec<Value>) -> TypeRefValue {
|
||||||
|
let mut values = Vec::new();
|
||||||
|
for v in value {
|
||||||
|
values.push(self.visit_value(v));
|
||||||
|
}
|
||||||
|
RefValueWrapper::wrap(RefValue::Array(values))
|
||||||
|
}
|
||||||
|
fn visit_object(&self, mut value: serde_json::Map<String, Value>) -> TypeRefValue {
|
||||||
|
let mut map = IndexMap::new();
|
||||||
|
let keys: Vec<String> = value.keys().into_iter().map(|k| k.to_string()).collect();
|
||||||
|
for k in keys {
|
||||||
|
let value = self.visit_value(match value.get_mut(&k) {
|
||||||
|
Some(v) => v.take(),
|
||||||
|
_ => Value::Null
|
||||||
|
});
|
||||||
|
map.insert(k, value);
|
||||||
|
}
|
||||||
|
RefValueWrapper::wrap(RefValue::Object(map))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ValueConverter;
|
||||||
|
|
||||||
|
impl ValueConverter {
|
||||||
|
fn new(value: &TypeRefValue) -> Value {
|
||||||
|
ValueConverter {}.visit_value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_value(&self, value: &TypeRefValue) -> Value {
|
||||||
|
match &***value {
|
||||||
|
RefValue::Null => self.visit_null(),
|
||||||
|
RefValue::Bool(v) => self.visit_bool(v),
|
||||||
|
RefValue::Number(v) => self.visit_number(v),
|
||||||
|
RefValue::String(v) => self.visit_string(v),
|
||||||
|
RefValue::Array(v) => self.visit_array(v),
|
||||||
|
RefValue::Object(v) => self.visit_object(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_null(&self) -> Value {
|
||||||
|
Value::Null
|
||||||
|
}
|
||||||
|
fn visit_bool(&self, value: &bool) -> Value {
|
||||||
|
Value::Bool(*value)
|
||||||
|
}
|
||||||
|
fn visit_number(&self, value: &serde_json::Number) -> Value {
|
||||||
|
Value::Number(value.clone())
|
||||||
|
}
|
||||||
|
fn visit_string(&self, value: &String) -> Value {
|
||||||
|
Value::String(value.clone())
|
||||||
|
}
|
||||||
|
fn visit_array(&self, value: &Vec<TypeRefValue>) -> Value {
|
||||||
|
let mut values = Vec::new();
|
||||||
|
for v in value {
|
||||||
|
values.push(self.visit_value(v));
|
||||||
|
}
|
||||||
|
Value::Array(values)
|
||||||
|
}
|
||||||
|
fn visit_object(&self, map: &IndexMap<String, TypeRefValue>) -> Value {
|
||||||
|
let mut ret = serde_json::Map::new();
|
||||||
|
let keys: Vec<String> = map.keys().into_iter().map(|k: &String| k.to_string()).collect();
|
||||||
|
let tmp_null = &RefValueWrapper::wrap(RefValue::Null);
|
||||||
|
for k in keys {
|
||||||
|
let value = self.visit_value(match map.get(&k) {
|
||||||
|
Some(e) => e,
|
||||||
|
_ => tmp_null
|
||||||
|
});
|
||||||
|
ret.insert(k, value);
|
||||||
|
}
|
||||||
|
Value::Object(ret)
|
||||||
|
}
|
||||||
|
}
|
2
wasm/.gitignore
vendored
2
wasm/.gitignore
vendored
@ -4,3 +4,5 @@ Cargo.lock
|
|||||||
bin/
|
bin/
|
||||||
pkg/
|
pkg/
|
||||||
wasm-pack.log
|
wasm-pack.log
|
||||||
|
.idea/*
|
||||||
|
.vscode
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "jsonpath-wasm"
|
name = "jsonpath-wasm"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||||
|
|
||||||
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
||||||
@ -22,8 +22,10 @@ wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
|||||||
console_error_panic_hook = { version = "0.1.1", optional = true }
|
console_error_panic_hook = { version = "0.1.1", optional = true }
|
||||||
wee_alloc = { version = "0.4.2", optional = true }
|
wee_alloc = { version = "0.4.2", optional = true }
|
||||||
|
|
||||||
jsonpath_lib = {path = "../"}
|
jsonpath_lib = { path = "../" }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
|
lazy_static = "1.3.0"
|
||||||
|
web-sys = { version = "0.3", features = ['console'] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.2"
|
wasm-bindgen-test = "0.2"
|
||||||
|
@ -6,8 +6,10 @@ set -e
|
|||||||
DIR="$(pwd)"
|
DIR="$(pwd)"
|
||||||
|
|
||||||
cd "${DIR}"/www && \
|
cd "${DIR}"/www && \
|
||||||
rm -rf "${DIR}"/dist && \
|
rm -rf "${DIR}"/www/dist && \
|
||||||
rm -rf "${DIR}"/node_modules && \
|
rm -rf "${DIR}"/www/node_modules && \
|
||||||
|
rm -rf "${DIR}"/www_bench/dist && \
|
||||||
|
rm -rf "${DIR}"/www_bench/node_modules && \
|
||||||
npm install && \
|
npm install && \
|
||||||
cd "${DIR}"
|
cd "${DIR}"
|
||||||
|
|
||||||
@ -24,6 +26,10 @@ echo "-------------------- build nodejs pkg done --------------------"
|
|||||||
|
|
||||||
cd "${DIR}"
|
cd "${DIR}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
echo "-------------------- start build browser pkg --------------------"
|
echo "-------------------- start build browser pkg --------------------"
|
||||||
@ -34,10 +40,40 @@ cd "${DIR}"/browser_pkg && npm link && \
|
|||||||
cd "${DIR}"/www && npm link @browser/jsonpath-wasm
|
cd "${DIR}"/www && npm link @browser/jsonpath-wasm
|
||||||
echo "-------------------- build browser pkg done --------------------"
|
echo "-------------------- build browser pkg done --------------------"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
echo "-------------------- start build browser bench pkg --------------------"
|
echo "-------------------- start build browser bench pkg --------------------"
|
||||||
echo
|
echo
|
||||||
rm -rf "${DIR}"/www_bench/node_modules && \
|
rm -rf "${DIR}"/www_bench/node_modules && \
|
||||||
cd "${DIR}"/www_bench && npm install && npm link @browser/jsonpath-wasm
|
cd "${DIR}"/www_bench && npm install && npm link @browser/jsonpath-wasm
|
||||||
echo "-------------------- build browser bench pkg done --------------------"
|
echo "-------------------- build browser bench pkg done --------------------"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "-------------------- start build docs --------------------"
|
||||||
|
cd "${DIR}"/www && \
|
||||||
|
npm run build && \
|
||||||
|
rm -f "${DIR}"/../docs/*.js && rm -f "${DIR}"/../docs/*.wasm && rm -f "${DIR}"/../docs/*.html && \
|
||||||
|
cp "${DIR}"/www/dist/*.* "${DIR}"/../docs/
|
||||||
|
echo "-------------------- build docs done --------------------"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "-------------------- start build docs bench --------------------"
|
||||||
|
cd "${DIR}"/www_bench && \
|
||||||
|
npm run build && \
|
||||||
|
rm -f "${DIR}"/../docs/bench/*.js && rm -f "${DIR}"/../docs/bench/*.wasm && rm -f "${DIR}"/../docs/bench/*.html && \
|
||||||
|
cp "${DIR}"/www_bench/dist/*.* "${DIR}"/../docs/bench/
|
||||||
|
echo "-------------------- build docs bench done --------------------"
|
125
wasm/src/lib.rs
125
wasm/src/lib.rs
@ -1,19 +1,24 @@
|
|||||||
extern crate cfg_if;
|
extern crate cfg_if;
|
||||||
extern crate wasm_bindgen;
|
|
||||||
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate jsonpath_lib as jsonpath;
|
extern crate jsonpath_lib as jsonpath;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
extern crate serde_json;
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
extern crate web_sys;
|
||||||
|
|
||||||
mod utils;
|
use std::collections::HashMap;
|
||||||
|
use std::result::Result;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use std::result::Result;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use jsonpath::parser::parser::*;
|
|
||||||
use jsonpath::filter::value_filter::*;
|
use jsonpath::filter::value_filter::*;
|
||||||
|
use jsonpath::parser::parser::*;
|
||||||
|
use jsonpath::ref_value::*;
|
||||||
|
use serde_json::Value;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use web_sys::console;
|
||||||
|
|
||||||
|
mod utils;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "wee_alloc")] {
|
if #[cfg(feature = "wee_alloc")] {
|
||||||
@ -23,17 +28,17 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_value(json: Value, node: Node) -> JsValue {
|
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||||
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json)));
|
let mut jf = JsonValueFilter::new_from_value(json);
|
||||||
jf.visit(node);
|
jf.visit(node);
|
||||||
let taken = jf.take_value();
|
let taken = jf.take_value().into_value();
|
||||||
match JsValue::from_serde(&taken) {
|
match JsValue::from_serde(&taken) {
|
||||||
Ok(js_value) => js_value,
|
Ok(js_value) => js_value,
|
||||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_value(js_value: &JsValue) -> Result<Value, String> {
|
fn into_serde_json(js_value: &JsValue) -> Result<Value, String> {
|
||||||
if js_value.is_string() {
|
if js_value.is_string() {
|
||||||
match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
|
match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
|
||||||
Ok(json) => Ok(json),
|
Ok(json) => Ok(json),
|
||||||
@ -47,20 +52,64 @@ fn into_value(js_value: &JsValue) -> Result<Value, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_js_value(js_value: &JsValue, node: Node) -> JsValue {
|
fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue {
|
||||||
match into_value(js_value) {
|
match into_serde_json(js_value) {
|
||||||
Ok(json) => filter_value(json, node),
|
Ok(json) => filter_ref_value(json.into(), node),
|
||||||
Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e))
|
Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_ref_value(js_value: JsValue, node: Node) -> JsValue {
|
||||||
|
match js_value.as_f64() {
|
||||||
|
Some(val) => {
|
||||||
|
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||||
|
Some(json) => filter_ref_value(json.clone(), node),
|
||||||
|
_ => JsValue::from_str("Invalid pointer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => into_ref_value(&js_value, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
|
||||||
|
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn alloc_json(js_value: JsValue) -> usize {
|
||||||
|
match into_serde_json(&js_value) {
|
||||||
|
Ok(json) => {
|
||||||
|
let mut map = CACHE_JSON.lock().unwrap();
|
||||||
|
if map.len() >= std::u8::MAX as usize {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
||||||
|
*idx += 1;
|
||||||
|
map.insert(*idx, json.into());
|
||||||
|
*idx
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
console::log_1(&e.into());
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn dealloc_json(ptr: usize) -> bool {
|
||||||
|
let mut map = CACHE_JSON.lock().unwrap();
|
||||||
|
map.remove(&ptr).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn compile(path: &str) -> JsValue {
|
pub fn compile(path: &str) -> JsValue {
|
||||||
let mut parser = Parser::new(path);
|
let mut parser = Parser::new(path);
|
||||||
let node = parser.compile();
|
let node = parser.compile();
|
||||||
let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
|
let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
|
||||||
match &node {
|
match &node {
|
||||||
Ok(node) => into_js_value(&js_value, node.clone()),
|
Ok(node) => get_ref_value(js_value, node.clone()),
|
||||||
Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e))
|
Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e))
|
||||||
}
|
}
|
||||||
}) as Box<Fn(JsValue) -> JsValue>);
|
}) as Box<Fn(JsValue) -> JsValue>);
|
||||||
@ -70,12 +119,35 @@ pub fn compile(path: &str) -> JsValue {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// deprecated. use selector
|
||||||
|
///
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn reader(js_value: JsValue) -> JsValue {
|
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() {
|
||||||
|
Some(val) => {
|
||||||
|
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
|
||||||
|
Some(json) => json.clone(),
|
||||||
|
_ => return JsValue::from_str("Invalid pointer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
match into_serde_json(&js_value) {
|
||||||
|
Ok(json) => json.into(),
|
||||||
|
Err(e) => return JsValue::from_str(e.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let cb = Closure::wrap(Box::new(move |path: String| {
|
let cb = Closure::wrap(Box::new(move |path: String| {
|
||||||
let mut parser = Parser::new(path.as_str());
|
let mut parser = Parser::new(path.as_str());
|
||||||
match parser.compile() {
|
match parser.compile() {
|
||||||
Ok(node) => into_js_value(&js_value, node),
|
Ok(node) => filter_ref_value(json.clone(), node),
|
||||||
Err(e) => return JsValue::from_str(e.as_str())
|
Err(e) => return JsValue::from_str(e.as_str())
|
||||||
}
|
}
|
||||||
}) as Box<Fn(String) -> JsValue>);
|
}) as Box<Fn(String) -> JsValue>);
|
||||||
@ -86,14 +158,21 @@ pub fn reader(js_value: JsValue) -> JsValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn read(js_value: JsValue, path: &str) -> JsValue {
|
pub fn select(js_value: JsValue, path: &str) -> JsValue {
|
||||||
let mut parser = Parser::new(path);
|
let mut parser = Parser::new(path);
|
||||||
match parser.compile() {
|
match parser.compile() {
|
||||||
Ok(node) => into_js_value(&js_value, node),
|
Ok(node) => get_ref_value(js_value, node),
|
||||||
Err(e) => return JsValue::from_str(e.as_str())
|
Err(e) => return JsValue::from_str(e.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// deprecated. use select
|
||||||
|
///
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn testa() {
|
pub fn read(js_value: JsValue, path: &str) -> JsValue {
|
||||||
}
|
select(js_value, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn testa() {}
|
@ -2,11 +2,14 @@ import * as jpw from "@browser/jsonpath-wasm";
|
|||||||
import * as jp from "jsonpath/jsonpath.js";
|
import * as jp from "jsonpath/jsonpath.js";
|
||||||
|
|
||||||
function run(message, iter, cb) {
|
function run(message, iter, cb) {
|
||||||
let d = Date.now();
|
return new Promise(function(resolve, _reject) {
|
||||||
for (let i = 0; i < iter; i++) {
|
let d = Date.now();
|
||||||
cb();
|
for (let i = 0; i < iter; i++) {
|
||||||
}
|
cb();
|
||||||
msg([message, Date.now() - d].join(", "));
|
}
|
||||||
|
msg([message, Date.now() - d].join(", "));
|
||||||
|
setTimeout(resolve, 0);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function msg(msg) {
|
function msg(msg) {
|
||||||
@ -54,12 +57,33 @@ let json = {
|
|||||||
"expensive": 10
|
"expensive": 10
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(function() {
|
let path = '$..book[?(@.price<30 && @.category=="fiction")]';
|
||||||
let path = '$..book[?(@.price<30 && @.category=="fiction")]';
|
let template = jpw.compile(path);
|
||||||
let template = jpw.compile(path);
|
let selector = jpw.selector(json);
|
||||||
let reader = jpw.reader(json);
|
|
||||||
run('jsonpath', 1000, function() { jp.query(json, path) });
|
let ptr = jpw.alloc_json(json);
|
||||||
run('jsonpath-wasm- reader', 1000, function() { reader(path) });
|
if(ptr == 0) console.error('invalid ptr');
|
||||||
run('jsonpath-wasm- compile', 1000, function() { template(json) });
|
|
||||||
run('jsonpath-wasm- read', 1000, function() { jpw.read(json, path) });
|
let iterCount = 2000;
|
||||||
}, 0);
|
|
||||||
|
run('jsonpath', iterCount, function() { jp.query(json, path) })
|
||||||
|
.then(function() {
|
||||||
|
return run('jsonpath-wasm- selector', iterCount, function() { selector(path) });
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return run('jsonpath-wasm- compile', iterCount, function() { template(json) });
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return run('jsonpath-wasm- compile-alloc', iterCount, function() { template(ptr) });
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return run('jsonpath-wasm- select', iterCount, function() { jpw.select(json, path) });
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) });
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
if(!jpw.dealloc_json(ptr)) {
|
||||||
|
console.error('fail to dealloc');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user