mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 17:32:15 +00:00
Resolved #6 (from v0.2.2), new array filter (range step, escaped quote notation, array keys)
This commit is contained in:
commit
ebd49c2205
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
|
||||
description = "It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript also. - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
BIN
docs/936e94ea88fa30f5750a.module.wasm
Normal file
BIN
docs/936e94ea88fa30f5750a.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/936e94ea88fa30f5750a.module.wasm
Normal file
BIN
docs/bench/936e94ea88fa30f5750a.module.wasm
Normal file
Binary file not shown.
38
docs/bench/bootstrap.js
vendored
38
docs/bench/bootstrap.js
vendored
@ -58,23 +58,26 @@
|
||||
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_error_af8a3e3880eae1c8": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_af8a3e3880eae1c8"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_call_88d2a6153573084e": function(p0i32,p1i32,p2i32,p3i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_88d2a6153573084e"](p0i32,p1i32,p2i32,p3i32);
|
||||
/******/ "__wbg_error_8015049cb5adfca2": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_8015049cb5adfca2"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_call_972de3aa550c37b2": function(p0i32,p1i32,p2i32,p3i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_972de3aa550c37b2"](p0i32,p1i32,p2i32,p3i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_is_string": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
||||
@ -82,9 +85,6 @@
|
||||
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_debug_string": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_debug_string"](p0i32,p1i32);
|
||||
/******/ },
|
||||
@ -94,11 +94,11 @@
|
||||
/******/ "__wbindgen_rethrow": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper22": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper22"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper18": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper18"](p0i32,p1i32,p2i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper24": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper24"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper20": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper20"](p0i32,p1i32,p2i32);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
@ -198,7 +198,7 @@
|
||||
/******/ promises.push(installedWasmModuleData);
|
||||
/******/ else {
|
||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"7a2fe8020c3403dd4ce6"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"936e94ea88fa30f5750a"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var promise;
|
||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||
|
38
docs/bootstrap.js
vendored
38
docs/bootstrap.js
vendored
@ -58,23 +58,26 @@
|
||||
/******/ "__wbindgen_cb_forget": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_error_af8a3e3880eae1c8": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_af8a3e3880eae1c8"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_call_88d2a6153573084e": function(p0i32,p1i32,p2i32,p3i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_88d2a6153573084e"](p0i32,p1i32,p2i32,p3i32);
|
||||
/******/ "__wbg_error_8015049cb5adfca2": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_8015049cb5adfca2"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbg_call_972de3aa550c37b2": function(p0i32,p1i32,p2i32,p3i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_972de3aa550c37b2"](p0i32,p1i32,p2i32,p3i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_is_string": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
|
||||
@ -82,9 +85,6 @@
|
||||
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_debug_string": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_debug_string"](p0i32,p1i32);
|
||||
/******/ },
|
||||
@ -94,11 +94,11 @@
|
||||
/******/ "__wbindgen_rethrow": function(p0i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper22": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper22"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper18": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper18"](p0i32,p1i32,p2i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper24": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper24"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper20": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper20"](p0i32,p1i32,p2i32);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
@ -198,7 +198,7 @@
|
||||
/******/ promises.push(installedWasmModuleData);
|
||||
/******/ else {
|
||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"7a2fe8020c3403dd4ce6"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"936e94ea88fa30f5750a"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var promise;
|
||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||
|
@ -398,6 +398,93 @@ describe('filter test', () => {
|
||||
run (done, i, list[i]);
|
||||
})
|
||||
}
|
||||
|
||||
it('object equal', (done) => {
|
||||
let selector = new jsonpath.Selector();
|
||||
selector.path('$..[?(@.a == 1)]');
|
||||
selector.value({
|
||||
'a': 1,
|
||||
'b': {'a': 1},
|
||||
'c': {'a': 1},
|
||||
});
|
||||
let result = selector.select();
|
||||
if (JSON.stringify(result) === JSON.stringify([{'a': 1}, {'a': 1}])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
// it('escaped single quote notation', (done) => {
|
||||
// let result = jsonpath.select({"single'quote":"value"}, "$['single\\'quote']");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["value"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('escaped double quote notation', (done) => {
|
||||
// let result = jsonpath.select({"single\"quote":"value"}, "$['single\"quote']");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["value"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[::]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["first", "second", "third", "forth", "fifth"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[::2]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::2]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["first", "third", "fifth"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[1: :]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1: :]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["second", "third", "forth", "fifth"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[1:2:]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1:2:]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["second"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[1::2]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1::2]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["second", "forth"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[0:3:1]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:1]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["first", "second", "third"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array range with step - $[0:3:2]', (done) => {
|
||||
// let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:2]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["first", "third"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// it('array keys', (done) => {
|
||||
// let result = jsonpath.select({
|
||||
// "key1": "value1",
|
||||
// "key2": 2
|
||||
// }, "$['key1', 'key2']");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["value1", 2])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
});
|
||||
|
||||
describe('SelectorMut test', () => {
|
||||
@ -797,4 +884,13 @@ describe('README test', () => {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// describe('ISSUE test', () => {
|
||||
// it('Results do not match other implementations #6', (done) => {
|
||||
// let result = jsonpath.select(["first", "second"], "$[:]");
|
||||
// if (JSON.stringify(result) === JSON.stringify(["first", "second"])) {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
// });
|
@ -4,7 +4,7 @@ pub mod parser;
|
||||
|
||||
#[cfg(test)]
|
||||
mod parser_tests {
|
||||
use parser::parser::{ParseToken, Parser, NodeVisitor, FilterToken};
|
||||
use parser::parser::{FilterToken, NodeVisitor, Parser, ParseToken};
|
||||
|
||||
struct NodeVisitorTestImpl<'a> {
|
||||
input: &'a str,
|
||||
@ -162,21 +162,63 @@ mod parser_tests {
|
||||
assert_eq!(run("$.a[10:]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(Some(10), None),
|
||||
ParseToken::Range(Some(10), None, None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[:11]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, Some(11)),
|
||||
ParseToken::Range(None, Some(11), None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[-12:13]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(Some(-12), Some(13)),
|
||||
ParseToken::Range(Some(-12), Some(13), None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$[0:3:2]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(Some(0), Some(3), Some(2)),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$[:3:2]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, Some(3), Some(2)),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$[:]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, None, None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$[::]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, None, None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$[::2]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, None, Some(2)),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$["a", 'b']"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Keys(vec!["a".to_string(), "b".to_string()]),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
@ -263,6 +305,27 @@ mod parser_tests {
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[:]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(None, None, None),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$['single\'quote']"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key("single'quote".to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run(r#"$["single\"quote"]"#), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key(r#"single"quote"#.to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$[") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
@ -331,6 +394,10 @@ mod parser_tests {
|
||||
mod tokenizer_tests {
|
||||
use parser::tokenizer::{Token, TokenError, Tokenizer, TokenReader};
|
||||
|
||||
fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
fn collect_token(input: &str) -> (Vec<Token>, Option<TokenError>) {
|
||||
let mut tokenizer = Tokenizer::new(input);
|
||||
let mut vec = vec![];
|
||||
@ -373,6 +440,8 @@ mod tokenizer_tests {
|
||||
|
||||
#[test]
|
||||
fn token() {
|
||||
setup();
|
||||
|
||||
run("$.01.a",
|
||||
(
|
||||
vec![
|
||||
@ -520,5 +589,26 @@ mod tokenizer_tests {
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$[:]", (vec![
|
||||
Token::Absolute(0),
|
||||
Token::OpenArray(1),
|
||||
Token::Split(2),
|
||||
Token::CloseArray(3)
|
||||
], Some(TokenError::Eof)));
|
||||
|
||||
run(r#"$['single\'quote']"#, (vec![
|
||||
Token::Absolute(0),
|
||||
Token::OpenArray(1),
|
||||
Token::SingleQuoted(2, "single\'quote".to_string()),
|
||||
Token::CloseArray(17)
|
||||
], Some(TokenError::Eof)));
|
||||
|
||||
run(r#"$["double\"quote"]"#, (vec![
|
||||
Token::Absolute(0),
|
||||
Token::OpenArray(1),
|
||||
Token::DoubleQuoted(2, "double\"quote".to_string()),
|
||||
Token::CloseArray(17)
|
||||
], Some(TokenError::Eof)));
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::tokenizer::*;
|
||||
|
||||
const DUMMY: usize = 0;
|
||||
@ -5,17 +7,12 @@ const DUMMY: usize = 0;
|
||||
type ParseResult<T> = Result<T, String>;
|
||||
|
||||
mod utils {
|
||||
pub fn string_to_isize<F>(string: &String, msg_handler: F) -> Result<isize, String>
|
||||
where F: Fn() -> String {
|
||||
match string.as_str().parse::<isize>() {
|
||||
Ok(n) => Ok(n),
|
||||
_ => Err(msg_handler())
|
||||
}
|
||||
}
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn string_to_f64<F>(string: &String, msg_handler: F) -> Result<f64, String>
|
||||
where F: Fn() -> String {
|
||||
match string.as_str().parse::<f64>() {
|
||||
pub fn string_to_num<F, S: FromStr>(string: &String, msg_handler: F) -> Result<S, String>
|
||||
where F: Fn() -> String
|
||||
{
|
||||
match string.as_str().parse() {
|
||||
Ok(n) => Ok(n),
|
||||
_ => Err(msg_handler())
|
||||
}
|
||||
@ -36,6 +33,7 @@ pub enum ParseToken {
|
||||
All,
|
||||
|
||||
Key(String),
|
||||
Keys(Vec<String>),
|
||||
// []
|
||||
Array,
|
||||
// 메타토큰
|
||||
@ -43,7 +41,7 @@ pub enum ParseToken {
|
||||
// ?( filter )
|
||||
Filter(FilterToken),
|
||||
// 1 : 2
|
||||
Range(Option<isize>, Option<isize>),
|
||||
Range(Option<isize>, Option<isize>, Option<usize>),
|
||||
// 1, 2, 3
|
||||
Union(Vec<isize>),
|
||||
|
||||
@ -235,12 +233,39 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn array_quota_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quota_value");
|
||||
fn array_keys(tokenizer: &mut TokenReader, first_key: String) -> ParseResult<Node> {
|
||||
let mut keys = vec![first_key];
|
||||
while tokenizer.peek_is(COMMA) {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
if !(tokenizer.peek_is(SINGLE_QUOTE) || tokenizer.peek_is(DOUBLE_QUOTE)) {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val))
|
||||
| Ok(Token::DoubleQuoted(_, val)) => {
|
||||
keys.push(val);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
|
||||
Ok(Self::node(ParseToken::Keys(keys)))
|
||||
}
|
||||
|
||||
fn array_quote_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quote_value");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val))
|
||||
| Ok(Token::DoubleQuoted(_, val)) => {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
if !tokenizer.peek_is(COMMA) {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
} else {
|
||||
Self::array_keys(tokenizer, val)
|
||||
}
|
||||
}
|
||||
Err(TokenError::Eof) => {
|
||||
Ok(Self::node(ParseToken::Eof))
|
||||
@ -291,7 +316,7 @@ impl Parser {
|
||||
debug!("#array_value_key");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
@ -325,7 +350,7 @@ impl Parser {
|
||||
}
|
||||
Ok(Token::DoubleQuoted(_, _))
|
||||
| Ok(Token::SingleQuoted(_, _)) => {
|
||||
Self::array_quota_value(tokenizer)
|
||||
Self::array_quote_value(tokenizer)
|
||||
}
|
||||
Err(TokenError::Eof) => {
|
||||
Ok(Self::node(ParseToken::Eof))
|
||||
@ -348,7 +373,7 @@ impl Parser {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
values.push(digit);
|
||||
}
|
||||
_ => {
|
||||
@ -359,26 +384,70 @@ impl Parser {
|
||||
Ok(Self::node(ParseToken::Union(values)))
|
||||
}
|
||||
|
||||
fn range_from(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
fn range_value<S: FromStr>(tokenizer: &mut TokenReader) -> Result<Option<S>, String> {
|
||||
if tokenizer.peek_is(SPLIT) {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
if tokenizer.peek_is(KEY) {
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, str_step)) => {
|
||||
match utils::string_to_num(&str_step, || tokenizer.err_msg_with_pos(pos)) {
|
||||
Ok(step) => Ok(Some(step)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
_ => Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn range_from(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_from");
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => {
|
||||
Self::range(num, tokenizer)
|
||||
Self::range(from, tokenizer)
|
||||
}
|
||||
Ok(Token::Split(_)) => {
|
||||
match Self::range_value(tokenizer)? {
|
||||
Some(step) => Ok(Self::node(ParseToken::Range(Some(from), None, Some(step)))),
|
||||
_ => Ok(Self::node(ParseToken::Range(Some(from), None, None)))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Ok(Self::node(ParseToken::Range(Some(num), None)))
|
||||
Ok(Self::node(ParseToken::Range(Some(from), None, None)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_to");
|
||||
|
||||
match Self::range_value(tokenizer)? {
|
||||
Some(step) => return Ok(Self::node(ParseToken::Range(None, None, Some(step)))),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::CloseArray(_)) => {
|
||||
return Ok(Self::node(ParseToken::Range(None, None, None)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Range(None, Some(digit))))
|
||||
Ok(Token::Key(pos, ref to_str)) => {
|
||||
let to = utils::string_to_num(to_str, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(None, Some(to), step)))
|
||||
}
|
||||
_ => {
|
||||
Err(tokenizer.err_msg())
|
||||
@ -386,12 +455,13 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn range(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
fn range(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Range(Some(num), Some(digit))))
|
||||
Ok(Token::Key(pos, ref str_to)) => {
|
||||
let to = utils::string_to_num(str_to, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(Some(from), Some(to), step)))
|
||||
}
|
||||
_ => {
|
||||
Err(tokenizer.err_msg())
|
||||
@ -498,7 +568,7 @@ impl Parser {
|
||||
Self::term_num_float(val.as_str(), tokenizer)
|
||||
}
|
||||
_ => {
|
||||
let number = utils::string_to_f64(&val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let number = utils::string_to_num(&val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
}
|
||||
@ -521,7 +591,7 @@ impl Parser {
|
||||
f.push_str(&mut num);
|
||||
f.push('.');
|
||||
f.push_str(frac.as_str());
|
||||
let number = utils::string_to_f64(&f, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let number = utils::string_to_num(&f, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
_ => {
|
||||
@ -560,8 +630,8 @@ impl Parser {
|
||||
return Self::json_path(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(DOUBLE_QUOTA) || tokenizer.peek_is(SINGLE_QUOTA) {
|
||||
return Self::array_quota_value(tokenizer);
|
||||
if tokenizer.peek_is(DOUBLE_QUOTE) || tokenizer.peek_is(SINGLE_QUOTE) {
|
||||
return Self::array_quote_value(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(KEY) {
|
||||
@ -652,7 +722,8 @@ pub trait NodeVisitor {
|
||||
| ParseToken::Relative
|
||||
| ParseToken::All
|
||||
| ParseToken::Key(_)
|
||||
| ParseToken::Range(_, _)
|
||||
| ParseToken::Keys(_)
|
||||
| ParseToken::Range(_, _, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_)
|
||||
| ParseToken::Bool(_) => {
|
||||
|
@ -15,8 +15,8 @@ pub const SPLIT: &'static str = ":";
|
||||
pub const OPEN_PARENTHESIS: &'static str = "(";
|
||||
pub const CLOSE_PARENTHESIS: &'static str = ")";
|
||||
pub const KEY: &'static str = "Key";
|
||||
pub const DOUBLE_QUOTA: &'static str = "\"";
|
||||
pub const SINGLE_QUOTA: &'static str = "'";
|
||||
pub const DOUBLE_QUOTE: &'static str = "\"";
|
||||
pub const SINGLE_QUOTE: &'static str = "'";
|
||||
pub const EQUAL: &'static str = "==";
|
||||
pub const GREATER_OR_EQUAL: &'static str = ">=";
|
||||
pub const GREATER: &'static str = ">";
|
||||
@ -44,8 +44,8 @@ const CH_PIPE: char = '|';
|
||||
const CH_LITTLE: char = '<';
|
||||
const CH_GREATER: char = '>';
|
||||
const CH_EXCLAMATION: char = '!';
|
||||
const CH_SINGLE_QUOTA: char = '\'';
|
||||
const CH_DOUBLE_QUOTA: char = '"';
|
||||
const CH_SINGLE_QUOTE: char = '\'';
|
||||
const CH_DOUBLE_QUOTE: char = '"';
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TokenError {
|
||||
@ -109,8 +109,8 @@ impl Token {
|
||||
Token::OpenParenthesis(_) => OPEN_PARENTHESIS,
|
||||
Token::CloseParenthesis(_) => CLOSE_PARENTHESIS,
|
||||
Token::Key(_, _) => KEY,
|
||||
Token::DoubleQuoted(_, _) => DOUBLE_QUOTA,
|
||||
Token::SingleQuoted(_, _) => SINGLE_QUOTA,
|
||||
Token::DoubleQuoted(_, _) => DOUBLE_QUOTE,
|
||||
Token::SingleQuoted(_, _) => SINGLE_QUOTE,
|
||||
Token::Equal(_) => EQUAL,
|
||||
Token::GreaterOrEqual(_) => GREATER_OR_EQUAL,
|
||||
Token::Greater(_) => GREATER,
|
||||
@ -147,20 +147,36 @@ pub struct Tokenizer<'a> {
|
||||
|
||||
impl<'a> Tokenizer<'a> {
|
||||
pub fn new(input: &'a str) -> Self {
|
||||
trace!("input: {}", input);
|
||||
Tokenizer {
|
||||
input: PathReader::new(input),
|
||||
}
|
||||
}
|
||||
|
||||
fn single_quota(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
fn quote(&mut self, ch: char) -> Result<String, TokenError> {
|
||||
let (_, mut val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||
|
||||
if let Some('\\') = val.chars().last() {
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
let _ = val.pop();
|
||||
let (_, mut val_remain) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
val.push(ch);
|
||||
val.push_str(val_remain.as_str());
|
||||
} else {
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
}
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn single_quote(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||
let val = self.quote(ch)?;
|
||||
Ok(Token::SingleQuoted(pos, val))
|
||||
}
|
||||
|
||||
fn double_quota(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
fn double_quote(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
|
||||
let val = self.quote(ch)?;
|
||||
Ok(Token::DoubleQuoted(pos, val))
|
||||
}
|
||||
|
||||
@ -259,8 +275,8 @@ impl<'a> Tokenizer<'a> {
|
||||
Some(t) => Ok(t),
|
||||
None => {
|
||||
match ch {
|
||||
CH_SINGLE_QUOTA => self.single_quota(pos, ch),
|
||||
CH_DOUBLE_QUOTA => self.double_quota(pos, ch),
|
||||
CH_SINGLE_QUOTE => self.single_quote(pos, ch),
|
||||
CH_DOUBLE_QUOTE => self.double_quote(pos, ch),
|
||||
CH_EQUAL => self.equal(pos, ch),
|
||||
CH_GREATER => self.greater(pos, ch),
|
||||
CH_LITTLE => self.little(pos, ch),
|
||||
|
@ -693,20 +693,22 @@ impl<'a, 'b> Selector<'a, 'b> {
|
||||
debug!("next_from_current_with_num : {:?}, {:?}", &index, self.current);
|
||||
}
|
||||
|
||||
fn next_from_current_with_str(&mut self, key: &str) {
|
||||
fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, key: &str, visited: &mut HashSet<*const Value>) {
|
||||
fn next_from_current_with_str(&mut self, keys: &Vec<String>) {
|
||||
fn _collect<'a>(v: &'a Value, tmp: &mut Vec<&'a Value>, keys: &Vec<String>, visited: &mut HashSet<*const Value>) {
|
||||
match v {
|
||||
Value::Object(map) => {
|
||||
if let Some(v) = map.get(key) {
|
||||
let ptr = v as *const Value;
|
||||
if !visited.contains(&ptr) {
|
||||
visited.insert(ptr);
|
||||
tmp.push(v)
|
||||
for key in keys {
|
||||
if let Some(v) = map.get(key) {
|
||||
let ptr = v as *const Value;
|
||||
if !visited.contains(&ptr) {
|
||||
visited.insert(ptr);
|
||||
tmp.push(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Array(vec) => for v in vec {
|
||||
_collect(v, tmp, key, visited);
|
||||
_collect(v, tmp, keys, visited);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -716,12 +718,12 @@ impl<'a, 'b> Selector<'a, 'b> {
|
||||
let mut tmp = Vec::new();
|
||||
let mut visited = HashSet::new();
|
||||
for c in current {
|
||||
_collect(c, &mut tmp, key, &mut visited);
|
||||
_collect(c, &mut tmp, keys, &mut visited);
|
||||
}
|
||||
self.current = Some(tmp);
|
||||
}
|
||||
|
||||
debug!("next_from_current_with_str : {}, {:?}", key, self.current);
|
||||
debug!("next_from_current_with_str : {:?}, {:?}", keys, self.current);
|
||||
}
|
||||
|
||||
fn next_all_from_current(&mut self) {
|
||||
@ -838,7 +840,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
self.next_from_current_with_num(to_f64(&n));
|
||||
}
|
||||
ExprTerm::String(key) => {
|
||||
self.next_from_current_with_str(&key);
|
||||
self.next_from_current_with_str(&vec![key]);
|
||||
}
|
||||
ExprTerm::Json(_, v) => {
|
||||
if v.is_empty() {
|
||||
@ -886,7 +888,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
self.all_from_current_with_str(key.as_str())
|
||||
}
|
||||
ParseToken::In => {
|
||||
self.next_from_current_with_str(key.as_str())
|
||||
self.next_from_current_with_str(&vec![key.clone()])
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -905,6 +907,17 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ParseToken::Keys(keys) => {
|
||||
if !self.terms.is_empty() {
|
||||
unimplemented!("keys in filter");
|
||||
}
|
||||
|
||||
if let Some(ParseToken::Array) = self.tokens.pop() {
|
||||
self.next_from_current_with_str(keys);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
ParseToken::Number(v) => {
|
||||
self.terms.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
||||
}
|
||||
@ -933,7 +946,7 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ParseToken::Range(from, to) => {
|
||||
ParseToken::Range(from, to, step) => {
|
||||
if !self.terms.is_empty() {
|
||||
unimplemented!("range syntax in filter");
|
||||
}
|
||||
@ -955,7 +968,10 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
||||
vec.len()
|
||||
};
|
||||
|
||||
for i in from..to {
|
||||
for i in (from..to).step_by(match step {
|
||||
Some(step) => *step,
|
||||
_ => 1
|
||||
}) {
|
||||
if let Some(v) = vec.get(i) {
|
||||
tmp.push(v);
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ fn array() {
|
||||
select_and_then_compare("$['school']['friends'][0].['name']", read_json("./benches/data_obj.json"), json!([
|
||||
"Millicent Norman"
|
||||
]));
|
||||
|
||||
select_and_then_compare(r#"$.["eyeColor", "name"]"#, read_json("./benches/data_obj.json"), json!([
|
||||
"blue", "Leonor Herman"
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -349,4 +353,26 @@ fn filer_same_obj() {
|
||||
{"a": 1},
|
||||
{"a": 1}
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range() {
|
||||
setup();
|
||||
|
||||
select_and_then_compare("$[:]", json!(["first", "second"]), json!(["first", "second"]));
|
||||
select_and_then_compare("$[::]", json!(["first", "second", "third", "forth", "fifth"]), json!(["first", "second", "third", "forth", "fifth"]));
|
||||
select_and_then_compare("$[::2]", json!(["first", "second", "third", "forth", "fifth"]), json!(["first", "third", "fifth"]));
|
||||
select_and_then_compare("$[1: :]", json!(["first", "second", "third", "forth", "fifth"]), json!(["second", "third", "forth", "fifth"]));
|
||||
select_and_then_compare("$[1:2:]", json!(["first", "second", "third", "forth", "fifth"]), json!(["second"]));
|
||||
select_and_then_compare("$[1::2]", json!(["first", "second", "third", "forth", "fifth"]), json!(["second", "forth"]));
|
||||
select_and_then_compare("$[0:3:1]", json!(["first", "second", "third", "forth", "fifth"]), json!(["first", "second", "third"]));
|
||||
select_and_then_compare("$[0:3:2]", json!(["first", "second", "third", "forth", "fifth"]), json!(["first", "third"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quote() {
|
||||
setup();
|
||||
|
||||
select_and_then_compare(r#"$['single\'quote']"#, json!({"single'quote":"value"}), json!(["value"]));
|
||||
select_and_then_compare(r#"$["double\"quote"]"#, json!({"double\"quote":"value"}), json!(["value"]));
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-wasm"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
description = "It is Webassembly version of jsonpath_lib that is JsonPath engine written in Rust - Demo: https://freestrings.github.io/jsonpath"
|
||||
keywords = ["jsonpath", "json", "webassembly", "parsing", "rust"]
|
||||
|
@ -412,6 +412,79 @@ describe('filter test', () => {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('escaped single quote notation', (done) => {
|
||||
let result = jsonpath.select({"single'quote":"value"}, "$['single\\'quote']");
|
||||
if (JSON.stringify(result) === JSON.stringify(["value"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('escaped double quote notation', (done) => {
|
||||
let result = jsonpath.select({"single\"quote":"value"}, "$['single\"quote']");
|
||||
if (JSON.stringify(result) === JSON.stringify(["value"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[::]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["first", "second", "third", "forth", "fifth"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[::2]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::2]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["first", "third", "fifth"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[1: :]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1: :]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["second", "third", "forth", "fifth"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[1:2:]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1:2:]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["second"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[1::2]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1::2]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["second", "forth"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[0:3:1]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:1]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["first", "second", "third"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array range with step - $[0:3:2]', (done) => {
|
||||
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:2]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["first", "third"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('array keys', (done) => {
|
||||
let result = jsonpath.select({
|
||||
"key1": "value1",
|
||||
"key2": 2
|
||||
}, "$['key1', 'key2']");
|
||||
if (JSON.stringify(result) === JSON.stringify(["value1", 2])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('SelectorMut test', () => {
|
||||
@ -821,4 +894,13 @@ describe('README test', () => {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ISSUE test', () => {
|
||||
it('Results do not match other implementations #6', (done) => {
|
||||
let result = jsonpath.select(["first", "second"], "$[:]");
|
||||
if (JSON.stringify(result) === JSON.stringify(["first", "second"])) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user