mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-06-15 17:11:27 +00:00
0.2.0 initail commit
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.1.13"
|
||||
version = "0.2.0"
|
||||
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"
|
||||
@ -23,6 +23,7 @@ env_logger = "0.6.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||
indexmap = "1.0.2"
|
||||
array_tool = "~1.0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
bencher = "0.1.5"
|
||||
@ -32,5 +33,5 @@ name = "jsonpath_lib"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
#debug = true
|
||||
#lto = false
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![feature(test)]
|
||||
extern crate bencher;
|
||||
extern crate indexmap;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
@ -8,13 +7,10 @@ extern crate test;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use self::test::Bencher;
|
||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||
use jsonpath::ref_value::ser::RefValueSerializer;
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
@ -103,71 +99,7 @@ fn bench_select_as(b: &mut Bencher) {
|
||||
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _: Book = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn refval_de(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = RefValue::deserialize(&json).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn refval_se(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = &json.serialize(RefValueSerializer).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn refval_refcopy(b: &mut Bencher) {
|
||||
use std::ops::Deref;
|
||||
|
||||
let json = get_json();
|
||||
let ref_json: RefValue = json.serialize(RefValueSerializer).unwrap();
|
||||
let store = ref_json.get("store".to_string()).unwrap();
|
||||
let book = store.get("book".to_string()).unwrap();
|
||||
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
if let RefValue::Array(vec) = book.deref() {
|
||||
let _: Vec<RefValueWrapper> = vec.iter().map(|v| v.clone()).collect();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn refval_copy(b: &mut Bencher) {
|
||||
|
||||
let json = get_json();
|
||||
let store = json.get("store".to_string()).unwrap();
|
||||
let book = store.get("book".to_string()).unwrap();
|
||||
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
if let Value::Array(vec) = book {
|
||||
let _: Vec<Value> = vec.iter().map(|v| v.clone()).collect();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn value_clone(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = json.clone();
|
||||
let _: Vec<Book> = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate bencher;
|
||||
extern crate indexmap;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
@ -12,7 +11,6 @@ use std::io::Read;
|
||||
use serde_json::Value;
|
||||
|
||||
use self::test::Bencher;
|
||||
use jsonpath::ref_value::model::RefValueWrapper;
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
@ -44,77 +42,46 @@ fn get_path(i: usize) -> &'static str {
|
||||
"$..book[-2:]", //9
|
||||
"$..book[2:]", //10
|
||||
"$..book[?(@.isbn)]", //11
|
||||
"$.store.book[?(@.price < 10)]", //12
|
||||
"$.store.book[?(@.price == 10)]", //12
|
||||
"$..*", //13
|
||||
"$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]" //14
|
||||
"$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]", //14
|
||||
"$.store.book[?( (@.price < 10 || @.price > 10) && @.price > 10 )]"
|
||||
];
|
||||
paths[i]
|
||||
}
|
||||
|
||||
fn _as_value(b: &mut Bencher, index: usize) {
|
||||
fn _selector(b: &mut Bencher, index: usize) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = jsonpath::select(&json, get_path(index));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn _as_ref_value(b: &mut Bencher, index: usize) {
|
||||
let ref json = get_json();
|
||||
let rv: RefValueWrapper = json.into();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let mut selector = jsonpath::Selector::new();
|
||||
let _ = selector.path(get_path(index));
|
||||
let _ = selector.value_from_ref_value(rv.clone());
|
||||
let _ = selector.select_as_value();
|
||||
selector.value(&json);
|
||||
let _ = selector.select();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! example_val {
|
||||
macro_rules! selector {
|
||||
($name:ident, $i:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) { _as_value(b, $i); }
|
||||
fn $name(b: &mut Bencher) { _selector(b, $i); }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! example_val_ref {
|
||||
($name:ident, $i:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) { _as_ref_value(b, $i); }
|
||||
};
|
||||
}
|
||||
|
||||
example_val!(example_val_0, 0);
|
||||
example_val!(example_val_1, 1);
|
||||
example_val!(example_val_2, 2);
|
||||
example_val!(example_val_3, 3);
|
||||
example_val!(example_val_4, 4);
|
||||
example_val!(example_val_5, 5);
|
||||
example_val!(example_val_6, 6);
|
||||
example_val!(example_val_7, 7);
|
||||
example_val!(example_val_8, 8);
|
||||
example_val!(example_val_9, 9);
|
||||
example_val!(example_val_10, 10);
|
||||
example_val!(example_val_11, 11);
|
||||
example_val!(example_val_12, 12);
|
||||
example_val!(example_val_13, 13);
|
||||
example_val!(example_val_14, 14);
|
||||
|
||||
example_val_ref!(example_val_ref_0, 0);
|
||||
example_val_ref!(example_val_ref_1, 1);
|
||||
example_val_ref!(example_val_ref_2, 2);
|
||||
example_val_ref!(example_val_ref_3, 3);
|
||||
example_val_ref!(example_val_ref_4, 4);
|
||||
example_val_ref!(example_val_ref_5, 5);
|
||||
example_val_ref!(example_val_ref_6, 6);
|
||||
example_val_ref!(example_val_ref_7, 7);
|
||||
example_val_ref!(example_val_ref_8, 8);
|
||||
example_val_ref!(example_val_ref_9, 9);
|
||||
example_val_ref!(example_val_ref_10, 10);
|
||||
example_val_ref!(example_val_ref_11, 11);
|
||||
example_val_ref!(example_val_ref_12, 12);
|
||||
example_val_ref!(example_val_ref_13, 13);
|
||||
example_val_ref!(example_val_ref_14, 14);
|
||||
selector!(example0_1, 0);
|
||||
selector!(example1_1, 1);
|
||||
selector!(example2_1, 2);
|
||||
selector!(example3_1, 3);
|
||||
selector!(example4_1, 4);
|
||||
selector!(example5_1, 5);
|
||||
selector!(example6_1, 6);
|
||||
selector!(example7_1, 7);
|
||||
selector!(example8_1, 8);
|
||||
selector!(example9_1, 9);
|
||||
selector!(example_10_1, 10);
|
||||
selector!(example_11_1, 11);
|
||||
selector!(example_12_1, 12);
|
||||
selector!(example_13_1, 13);
|
||||
selector!(example_14_1, 14);
|
||||
selector!(example_15_1, 15);
|
@ -1,191 +0,0 @@
|
||||
#[derive(Debug)]
|
||||
pub enum CmpType {
|
||||
Eq,
|
||||
Ne,
|
||||
Gt,
|
||||
Ge,
|
||||
Lt,
|
||||
Le,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CmpCondType {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
pub trait PrivCmp {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool;
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool;
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool;
|
||||
}
|
||||
|
||||
pub trait IntoType {
|
||||
fn into_type(&self) -> CmpType;
|
||||
}
|
||||
|
||||
pub struct CmpEq;
|
||||
|
||||
impl PrivCmp for CmpEq {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 == v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 == v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 == v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpEq {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Eq
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpNe;
|
||||
|
||||
impl PrivCmp for CmpNe {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 != v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 != v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 != v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpNe {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Ne
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpGt;
|
||||
|
||||
impl PrivCmp for CmpGt {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 > v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 > v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 > v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpGt {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Gt
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpGe;
|
||||
|
||||
impl PrivCmp for CmpGe {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 >= v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 >= v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 >= v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpGe {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Ge
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpLt;
|
||||
|
||||
impl PrivCmp for CmpLt {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 < v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 < v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 < v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpLt {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Lt
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpLe;
|
||||
|
||||
impl PrivCmp for CmpLe {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
v1 <= v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 <= v2
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
v1 <= v2
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoType for CmpLe {
|
||||
fn into_type(&self) -> CmpType {
|
||||
CmpType::Le
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpAnd;
|
||||
|
||||
impl PrivCmp for CmpAnd {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
*v1 && *v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 > &0_f64 && v2 > &0_f64
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
!v1.is_empty() && !v2.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CmpOr;
|
||||
|
||||
impl PrivCmp for CmpOr {
|
||||
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
|
||||
*v1 || *v2
|
||||
}
|
||||
|
||||
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
|
||||
v1 > &0_f64 || v2 > &0_f64
|
||||
}
|
||||
|
||||
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
|
||||
!v1.is_empty() || !v2.is_empty()
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
mod cmp;
|
||||
mod term;
|
||||
pub mod value_filter;
|
||||
pub mod value_manager;
|
||||
#[deprecated(since = "0.1.14", note = "Please use the value_manager module instead")]
|
||||
pub use self::value_manager as value_wrapper;
|
@ -1,154 +0,0 @@
|
||||
use super::cmp::*;
|
||||
use super::value_filter::ValueFilterKey;
|
||||
use super::value_manager::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TermContext {
|
||||
Constants(ExprTerm),
|
||||
Json(Option<ValueFilterKey>, ValueManager),
|
||||
}
|
||||
|
||||
impl TermContext {
|
||||
fn cmp<F: PrivCmp + IntoType>(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext {
|
||||
match self {
|
||||
TermContext::Constants(et) => {
|
||||
match other {
|
||||
TermContext::Constants(oet) => {
|
||||
trace!("const-const");
|
||||
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default)))
|
||||
}
|
||||
TermContext::Json(ref mut key, ref mut v) => {
|
||||
trace!("const-json");
|
||||
TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
TermContext::Json(key, v) => {
|
||||
match other {
|
||||
TermContext::Json(key_other, ov) => {
|
||||
trace!("json-json");
|
||||
|
||||
fn is_json(t: &TermContext) -> bool {
|
||||
match t {
|
||||
TermContext::Json(_, _) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
let mut c = v.into_term(key);
|
||||
let mut oc = ov.into_term(key_other);
|
||||
if is_json(&c) && is_json(&oc) {
|
||||
v.cmp(&ov, cmp_fn.into_type())
|
||||
} else {
|
||||
c.cmp(&mut oc, cmp_fn, default)
|
||||
}
|
||||
}
|
||||
TermContext::Constants(et) => {
|
||||
trace!("json-const");
|
||||
TermContext::Json(None, v.get_compare_with(key, et, cmp_fn, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext {
|
||||
match self {
|
||||
TermContext::Constants(et) => {
|
||||
match other {
|
||||
TermContext::Constants(oet) => {
|
||||
match cmp_cond_type {
|
||||
CmpCondType::Or => {
|
||||
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, CmpOr, false)))
|
||||
}
|
||||
CmpCondType::And => {
|
||||
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, CmpAnd, false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
TermContext::Json(_, v) => {
|
||||
TermContext::Json(None, ValueManager::new(v.get_val().clone(), false))
|
||||
}
|
||||
}
|
||||
}
|
||||
TermContext::Json(_, v) => {
|
||||
match other {
|
||||
TermContext::Json(_, ov) => {
|
||||
match cmp_cond_type {
|
||||
CmpCondType::Or => TermContext::Json(None, v.union(ov)),
|
||||
CmpCondType::And => TermContext::Json(None, v.intersect(ov)),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
TermContext::Json(None, ValueManager::new(v.get_val().clone(), false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("eq");
|
||||
self.cmp(other, CmpEq, false)
|
||||
}
|
||||
|
||||
pub fn ne(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("ne");
|
||||
self.cmp(other, CmpNe, true)
|
||||
}
|
||||
|
||||
pub fn gt(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("gt");
|
||||
self.cmp(other, CmpGt, false)
|
||||
}
|
||||
|
||||
pub fn ge(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("ge");
|
||||
self.cmp(other, CmpGe, false)
|
||||
}
|
||||
|
||||
pub fn lt(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("lt");
|
||||
self.cmp(other, CmpLt, false)
|
||||
}
|
||||
|
||||
pub fn le(&mut self, other: &mut TermContext) -> TermContext {
|
||||
trace!("le");
|
||||
self.cmp(other, CmpLe, false)
|
||||
}
|
||||
|
||||
pub fn and(&mut self, other: &mut TermContext) -> TermContext {
|
||||
self.cmp_cond(other, CmpCondType::And)
|
||||
}
|
||||
|
||||
pub fn or(&mut self, other: &mut TermContext) -> TermContext {
|
||||
self.cmp_cond(other, CmpCondType::Or)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExprTerm {
|
||||
String(String),
|
||||
Number(f64),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
impl ExprTerm {
|
||||
fn cmp<F: PrivCmp>(&self, other: &ExprTerm, cmp_fn: F, default: bool) -> bool {
|
||||
match self {
|
||||
ExprTerm::Bool(v1) => match other {
|
||||
ExprTerm::Bool(v2) => cmp_fn.cmp_bool(v1, v2),
|
||||
_ => default
|
||||
}
|
||||
ExprTerm::Number(v1) => match other {
|
||||
ExprTerm::Number(v2) => cmp_fn.cmp_f64(v1, v2),
|
||||
_ => default
|
||||
}
|
||||
ExprTerm::String(v1) => match other {
|
||||
ExprTerm::String(v2) => cmp_fn.cmp_string(v1, v2),
|
||||
_ => default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,442 +0,0 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use filter::term::*;
|
||||
use filter::value_manager::*;
|
||||
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
|
||||
use ref_value::model::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ValueFilterKey {
|
||||
Num(usize),
|
||||
String(String),
|
||||
All,
|
||||
}
|
||||
|
||||
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<RefValueWrapper>) {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
if key.is_none() {
|
||||
for v in vec.iter() {
|
||||
buf.push(v.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for v in vec {
|
||||
collect_all(key, v, buf);
|
||||
}
|
||||
}
|
||||
RefValue::Object(map) => {
|
||||
if let Some(k) = key {
|
||||
if let Some(val) = map.get(k) {
|
||||
buf.push(val.clone());
|
||||
}
|
||||
} else {
|
||||
let mut c = map.values().map(|v| v.clone()).collect();
|
||||
buf.append(&mut c);
|
||||
}
|
||||
for (_, v) in map {
|
||||
collect_all(key, v, buf);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ValueFilter {
|
||||
value_mgr: ValueManager,
|
||||
last_key: Option<ValueFilterKey>,
|
||||
is_relative: bool,
|
||||
}
|
||||
|
||||
impl ValueFilter {
|
||||
pub fn new(v: RefValueWrapper, is_leaves: bool, is_relative: bool) -> Self {
|
||||
ValueFilter {
|
||||
value_mgr: ValueManager::new(v, is_leaves),
|
||||
last_key: None,
|
||||
is_relative,
|
||||
}
|
||||
}
|
||||
|
||||
fn step_leaves(&mut self, key: Option<&String>) {
|
||||
let mut buf = Vec::new();
|
||||
collect_all(key, &self.value_mgr.get_val(), &mut buf);
|
||||
trace!("step_leaves - {:?}", buf);
|
||||
self.value_mgr = ValueManager::new(RefValue::Array(buf).into(), true);
|
||||
}
|
||||
|
||||
pub fn step_leaves_all(&mut self) -> &ValueManager {
|
||||
debug!("step_leaves_all");
|
||||
self.step_leaves(None);
|
||||
self.last_key = Some(ValueFilterKey::All);
|
||||
&self.value_mgr
|
||||
}
|
||||
|
||||
pub fn step_leaves_str(&mut self, key: &str) -> &ValueManager {
|
||||
self.step_leaves_string(&key.to_string())
|
||||
}
|
||||
|
||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueManager {
|
||||
debug!("step_leaves_string");
|
||||
self.step_leaves(Some(key));
|
||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||
&self.value_mgr
|
||||
}
|
||||
|
||||
pub fn step_in_all(&mut self) -> &ValueManager {
|
||||
debug!("step_in_all");
|
||||
self.last_key = Some(ValueFilterKey::All);
|
||||
self.value_mgr.replace(self.value_mgr.get_as_array());
|
||||
trace!("step_in_all - {:?}", self.value_mgr.get_val());
|
||||
&self.value_mgr
|
||||
}
|
||||
|
||||
pub fn step_in_num(&mut self, key: &f64) -> &ValueManager {
|
||||
debug!("step_in_num");
|
||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||
, self.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, self.value_mgr.get_val());
|
||||
|
||||
|
||||
self.last_key = Some(ValueFilterKey::Num(self.value_mgr.get_index(*key)));
|
||||
let v = self.value_mgr.get_with_num(key, self.is_relative);
|
||||
self.value_mgr.replace(v);
|
||||
trace!("step_in_num - after: {:?}", self.value_mgr.get_val());
|
||||
&self.value_mgr
|
||||
}
|
||||
|
||||
pub fn step_in_str(&mut self, key: &str) -> &ValueManager {
|
||||
self.step_in_string(&key.to_string())
|
||||
}
|
||||
|
||||
pub fn step_in_string(&mut self, key: &String) -> &ValueManager {
|
||||
debug!("step_in_string");
|
||||
trace!("step_in_string - before: {},{},{:?}"
|
||||
, self.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, self.value_mgr.get_val());
|
||||
|
||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||
self.value_mgr.replace(self.value_mgr.get_with_str(key, self.is_relative));
|
||||
trace!("step_in_string - after: {},{},{:?}"
|
||||
, self.value_mgr.is_leaves()
|
||||
, self.is_relative
|
||||
, self.value_mgr.get_val());
|
||||
&self.value_mgr
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JsonValueFilter {
|
||||
json: RefValueWrapper,
|
||||
filter_stack: Vec<ValueFilter>,
|
||||
token_stack: Vec<ParseToken>,
|
||||
term_stack: Vec<TermContext>,
|
||||
}
|
||||
|
||||
impl JsonValueFilter {
|
||||
pub fn new(json: RefValueWrapper) -> Self {
|
||||
JsonValueFilter {
|
||||
json,
|
||||
filter_stack: Vec::new(),
|
||||
token_stack: Vec::new(),
|
||||
term_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_peek_token_array(&self) -> bool {
|
||||
if let Some(ParseToken::Array) = self.token_stack.last() { true } else { false }
|
||||
}
|
||||
|
||||
fn create_new_filter(&mut self, is_relative: bool) {
|
||||
if is_relative {
|
||||
self.filter_stack.last()
|
||||
.map(|vf| {
|
||||
ValueFilter::new(vf.value_mgr.get_val().clone(),
|
||||
vf.value_mgr.is_leaves(),
|
||||
is_relative,
|
||||
)
|
||||
})
|
||||
.and_then(|vf| {
|
||||
Some(self.filter_stack.push(vf))
|
||||
});
|
||||
} else {
|
||||
let vf = ValueFilter::new(
|
||||
self.json.clone(),
|
||||
false,
|
||||
is_relative,
|
||||
);
|
||||
self.filter_stack.push(vf);
|
||||
}
|
||||
}
|
||||
|
||||
fn append_to_current_filter(&mut self, v: RefValueWrapper, is_leaves: bool) {
|
||||
if self.filter_stack.is_empty() {
|
||||
self.filter_stack.push(ValueFilter::new(
|
||||
v,
|
||||
is_leaves,
|
||||
false,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
vf.value_mgr.set_leaves(is_leaves);
|
||||
if v.is_null() || v.is_empty() {
|
||||
vf.value_mgr.replace(RefValue::Null.into());
|
||||
} else if vf.value_mgr.is_array() {
|
||||
vf.value_mgr.replace(v);
|
||||
} else {
|
||||
// ignore. the current filter context is object that include v: RefValueWrapper as a child.
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_value(&self) -> Value {
|
||||
match self.filter_stack.last() {
|
||||
Some(v) => v.value_mgr.into_value(),
|
||||
_ => Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.14", note = "Please use the clone_value function instead")]
|
||||
pub fn take_value(&mut self) -> RefValueWrapper {
|
||||
self.clone_value()
|
||||
}
|
||||
|
||||
pub fn clone_value(&mut self) -> RefValueWrapper {
|
||||
match self.filter_stack.last() {
|
||||
Some(v) => v.value_mgr.get_val().clone(),
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn token_union(&mut self, indices: Vec<isize>) {
|
||||
self.token_stack.pop();
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
if let Some(vec) = vf.value_mgr.pick_with_nums(indices) {
|
||||
vf.value_mgr.replace(vec);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
|
||||
self.token_stack.pop();
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(ref mut vf) => {
|
||||
if let Some(vec) = vf.value_mgr.range_with(from, to) {
|
||||
vf.value_mgr.replace(vec);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_key(&mut self, key: String) {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
match self.token_stack.pop() {
|
||||
Some(ParseToken::In) | Some(ParseToken::Array) => {
|
||||
vf.step_in_string(&key);
|
||||
}
|
||||
Some(ParseToken::Leaves) => {
|
||||
vf.step_leaves_string(&key);
|
||||
}
|
||||
_ => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::String(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_all(&mut self) {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
match self.token_stack.pop() {
|
||||
Some(ParseToken::In) => {
|
||||
vf.step_in_all();
|
||||
}
|
||||
Some(ParseToken::Leaves) => {
|
||||
vf.step_leaves_all();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_end_array(&mut self) {
|
||||
trace!("array_eof - term_stack: {:?}", self.term_stack);
|
||||
trace!("array_eof - filter_stack: {:?}", self.filter_stack);
|
||||
|
||||
match self.term_stack.pop() {
|
||||
Some(TermContext::Constants(ExprTerm::Number(v))) => {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(vf) => {
|
||||
vf.step_in_num(&v);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some(TermContext::Constants(ExprTerm::Bool(false))) => {
|
||||
self.append_to_current_filter(RefValue::Null.into(), false);
|
||||
}
|
||||
Some(TermContext::Json(_, vw)) => {
|
||||
self.append_to_current_filter(vw.get_val().clone(), vw.is_leaves());
|
||||
}
|
||||
_ => {
|
||||
|
||||
//
|
||||
// None, TermContext::Constants(ExprTerm::Bool(true))
|
||||
//
|
||||
|
||||
match self.filter_stack.pop() {
|
||||
Some(vf) => {
|
||||
match vf.value_mgr.get_val().deref() {
|
||||
RefValue::Null | RefValue::Bool(false) => {
|
||||
self.append_to_current_filter(RefValue::Null.into(), vf.value_mgr.is_leaves());
|
||||
}
|
||||
_ => {
|
||||
self.append_to_current_filter(vf.value_mgr.get_val().clone(), vf.value_mgr.is_leaves());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_op(&mut self, ft: &FilterToken) {
|
||||
let right = self.term_stack.pop();
|
||||
let left = self.term_stack.pop();
|
||||
|
||||
trace!("left {:?}", left);
|
||||
trace!("right {:?}", right);
|
||||
|
||||
if left.is_some() && right.is_some() {
|
||||
let mut left = left.unwrap();
|
||||
let mut right = right.unwrap();
|
||||
|
||||
let tc = match ft {
|
||||
FilterToken::Equal => left.eq(&mut right),
|
||||
FilterToken::NotEqual => left.ne(&mut right),
|
||||
FilterToken::Greater => left.gt(&mut right),
|
||||
FilterToken::GreaterOrEqual => left.ge(&mut right),
|
||||
FilterToken::Little => left.lt(&mut right),
|
||||
FilterToken::LittleOrEqual => left.le(&mut right),
|
||||
FilterToken::And => left.and(&mut right),
|
||||
FilterToken::Or => left.or(&mut right),
|
||||
};
|
||||
self.term_stack.push(tc);
|
||||
}
|
||||
|
||||
trace!("filter - {:?}", self.term_stack)
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeVisitor for JsonValueFilter {
|
||||
fn visit_token(&mut self, token: ParseToken) {
|
||||
debug!("visit_token: {:?}", token);
|
||||
|
||||
match token {
|
||||
ParseToken::Absolute
|
||||
| ParseToken::Relative => {
|
||||
if self.is_peek_token_array() {
|
||||
self.token_stack.pop();
|
||||
}
|
||||
self.create_new_filter(ParseToken::Relative == token);
|
||||
}
|
||||
ParseToken::In
|
||||
| ParseToken::Leaves => {
|
||||
self.token_stack.push(token);
|
||||
}
|
||||
ParseToken::Array => {
|
||||
if let Some(ParseToken::Leaves) = self.token_stack.last() {
|
||||
self.token_all();
|
||||
}
|
||||
self.token_stack.push(token);
|
||||
}
|
||||
ParseToken::ArrayEof => {
|
||||
self.token_end_array();
|
||||
}
|
||||
ParseToken::All => {
|
||||
self.token_all();
|
||||
}
|
||||
ParseToken::Key(key) => {
|
||||
self.token_key(key);
|
||||
}
|
||||
ParseToken::Filter(ref ft) => {
|
||||
self.token_op(ft);
|
||||
}
|
||||
ParseToken::Number(v) => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::Number(v)))
|
||||
}
|
||||
ParseToken::Range(from, to) => {
|
||||
self.token_range(from, to);
|
||||
}
|
||||
ParseToken::Union(v) => {
|
||||
self.token_union(v);
|
||||
}
|
||||
ParseToken::Eof => {
|
||||
debug!("visit_token eof");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn end_term(&mut self) {
|
||||
debug!("end_term");
|
||||
|
||||
if let Some(ParseToken::Array) = self.token_stack.last() {
|
||||
self.token_stack.pop();
|
||||
}
|
||||
|
||||
trace!("end_term - term_stack {:?}", self.term_stack);
|
||||
trace!("end_term - token_stack {:?}", self.token_stack);
|
||||
trace!("end_term - filter_stack {:?}", self.filter_stack);
|
||||
|
||||
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
||||
match self.filter_stack.pop() {
|
||||
Some(vf) => {
|
||||
self.term_stack.push(TermContext::Json(vf.last_key, vf.value_mgr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if match self.token_stack.last() {
|
||||
Some(ParseToken::Key(_))
|
||||
| Some(ParseToken::Number(_)) => true,
|
||||
_ => false
|
||||
} {
|
||||
match self.token_stack.pop() {
|
||||
Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("true") => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::Bool(true)))
|
||||
}
|
||||
Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("false") => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::Bool(false)))
|
||||
}
|
||||
Some(ParseToken::Key(v)) => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::String(v)))
|
||||
}
|
||||
Some(ParseToken::Number(v)) => {
|
||||
self.term_stack.push(TermContext::Constants(ExprTerm::Number(v)))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,517 +0,0 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use serde_json::Value;
|
||||
|
||||
use ref_value::model::*;
|
||||
|
||||
use super::cmp::*;
|
||||
use super::term::*;
|
||||
use super::value_filter::*;
|
||||
|
||||
pub trait ArrayIndex {
|
||||
fn index(&self, v: &RefValueWrapper) -> usize;
|
||||
|
||||
fn ref_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
|
||||
let idx = self.index(v);
|
||||
match v.get(idx) {
|
||||
Some(v) => v.clone(),
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArrayIndex for f64 {
|
||||
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||
if v.is_array() && self < &0_f64 {
|
||||
(v.len() as f64 + self) as usize
|
||||
} else {
|
||||
*self as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArrayIndex for isize {
|
||||
fn index(&self, v: &RefValueWrapper) -> usize {
|
||||
if v.is_array() && self < &0_isize {
|
||||
(v.len() as isize + self) as usize
|
||||
} else {
|
||||
*self as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArrayIndex for usize {
|
||||
fn index(&self, _: &RefValueWrapper) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
||||
match val.deref() {
|
||||
RefValue::Bool(ref v1) => {
|
||||
match et {
|
||||
ExprTerm::Bool(v2) => if reverse {
|
||||
cmp_fn.cmp_bool(v2, v1)
|
||||
} else {
|
||||
cmp_fn.cmp_bool(v1, v2)
|
||||
},
|
||||
_ => default
|
||||
}
|
||||
}
|
||||
RefValue::Number(ref v1) => match et {
|
||||
ExprTerm::Number(v2) => if reverse {
|
||||
cmp_fn.cmp_f64(v2, &v1.as_f64().unwrap())
|
||||
} else {
|
||||
cmp_fn.cmp_f64(&v1.as_f64().unwrap(), v2)
|
||||
},
|
||||
_ => default
|
||||
},
|
||||
RefValue::String(ref v1) => {
|
||||
match et {
|
||||
ExprTerm::String(v2) => if reverse {
|
||||
cmp_fn.cmp_string(v2, v1)
|
||||
} else {
|
||||
cmp_fn.cmp_string(v1, v2)
|
||||
},
|
||||
_ => default
|
||||
}
|
||||
}
|
||||
_ => default
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_not_null<'a,
|
||||
I: Iterator<Item=&'a RefValueWrapper>,
|
||||
F: FnMut(&RefValueWrapper) -> RefValueWrapper>(iter: I, func: F) -> Vec<RefValueWrapper>
|
||||
{
|
||||
iter.map(func)
|
||||
.filter(|v| !v.is_null())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn collect_some<'a,
|
||||
I: Iterator<Item=&'a RefValueWrapper>,
|
||||
F: FnMut(&RefValueWrapper) -> Option<RefValueWrapper>>(iter: I, func: F) -> Vec<RefValueWrapper>
|
||||
{
|
||||
iter.map(func)
|
||||
.filter(|v| v.is_some())
|
||||
.map(|v| v.unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_in_array<I: ArrayIndex>(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option<RefValueWrapper> {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) if vec.get(key.index(v)).is_some() => {
|
||||
Some(if is_relative { v.clone() } else { v.get(key.index(v)).unwrap().clone() })
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_in_object(v: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||
match v.deref() {
|
||||
RefValue::Object(map) if map.contains_key(key) => {
|
||||
Some(if is_relative { v.clone() } else { v.get(key.to_string()).unwrap().clone() })
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_in_nested_array<I: ArrayIndex>(v: &RefValueWrapper, key: &I, is_relative: bool) -> Option<RefValueWrapper> {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
let ret = collect_some(vec.iter(), |v| { get_in_array(v, key, is_relative) });
|
||||
Some(RefValue::Array(ret).into())
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_object_in_array(val: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||
match val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
let ret = collect_some(vec.iter(), |v| get_in_object(v, key, is_relative));
|
||||
Some(RefValue::Array(ret).into())
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_in_nested_object(val: &RefValueWrapper, key: &str, is_relative: bool) -> Option<RefValueWrapper> {
|
||||
match val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
let ret = vec.iter()
|
||||
.map(|v| {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
Some(collect_some(vec.iter(), |v| get_in_object(v, key, is_relative)))
|
||||
}
|
||||
RefValue::Object(_) => {
|
||||
match get_in_object(v, key, is_relative) {
|
||||
Some(v) => Some(vec![v]),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.filter(|v| v.is_some())
|
||||
.map(|v| v.unwrap())
|
||||
.filter(|v| !v.is_empty())
|
||||
.flatten()
|
||||
.collect();
|
||||
Some(RefValue::Array(ret).into())
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.14", note = "Please use the ValueManager instead")]
|
||||
pub type ValueWrapper = ValueManager;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ValueManager {
|
||||
val: RefValueWrapper,
|
||||
is_leaves: bool,
|
||||
}
|
||||
|
||||
impl ValueManager {
|
||||
pub fn new(val: RefValueWrapper, is_leaves: bool) -> Self {
|
||||
ValueManager { val, is_leaves }
|
||||
}
|
||||
|
||||
pub fn is_leaves(&self) -> bool {
|
||||
self.is_leaves
|
||||
}
|
||||
|
||||
pub fn set_leaves(&mut self, is_leaves: bool) {
|
||||
self.is_leaves = is_leaves;
|
||||
}
|
||||
|
||||
pub fn cmp(&self, other: &Self, cmp_type: CmpType) -> TermContext {
|
||||
match cmp_type {
|
||||
CmpType::Eq => {
|
||||
TermContext::Json(None, self.intersect(other))
|
||||
}
|
||||
CmpType::Ne => {
|
||||
TermContext::Json(None, self.except(other))
|
||||
}
|
||||
CmpType::Gt | CmpType::Ge | CmpType::Lt | CmpType::Le => {
|
||||
TermContext::Constants(ExprTerm::Bool(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_compare_with<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
|
||||
match self.val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
let mut set = IndexSet::new();
|
||||
for v in vec {
|
||||
if let Some(ValueFilterKey::String(key)) = key {
|
||||
if let Some(ret_v) = get_in_object(v, key, false) {
|
||||
if cmp_with_term(&ret_v, et, &cmp, false, reverse) {
|
||||
set.insert(v.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if cmp_with_term(v, et, &cmp, false, reverse) {
|
||||
set.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ret = set.into_iter().collect();
|
||||
Self::new(RefValue::Array(ret).into(), false)
|
||||
}
|
||||
_ => {
|
||||
if cmp_with_term(&self.val, et, &cmp, false, reverse) {
|
||||
Self::new(self.val.clone(), false)
|
||||
} else {
|
||||
Self::new(RefValue::Null.into(), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_index<I: ArrayIndex>(&self, i: I) -> usize {
|
||||
i.index(&self.val)
|
||||
}
|
||||
|
||||
pub fn get_with_num<I: ArrayIndex>(&self, key: &I, is_relative: bool) -> RefValueWrapper {
|
||||
if self.val.is_array() && self.is_leaves {
|
||||
match get_in_nested_array(&self.val, key, is_relative) {
|
||||
Some(v) => v,
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
} else {
|
||||
key.ref_value(&self.val)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_array(&self) -> RefValueWrapper {
|
||||
let vec = match self.val.deref() {
|
||||
RefValue::Object(ref map) => {
|
||||
collect_not_null(map.values(), |v| v.clone())
|
||||
}
|
||||
RefValue::Array(ref vec) => {
|
||||
vec.clone()
|
||||
}
|
||||
RefValue::Null => Vec::new(),
|
||||
_ => vec![self.val.clone()]
|
||||
};
|
||||
RefValue::Array(vec).into()
|
||||
}
|
||||
|
||||
pub fn get_with_str(&self, key: &String, is_relative: bool) -> RefValueWrapper {
|
||||
if self.val.is_array() && self.is_leaves {
|
||||
match get_in_nested_object(&self.val, key, is_relative) {
|
||||
Some(v) => v,
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
} else if self.val.is_array() && !self.is_leaves {
|
||||
match get_object_in_array(&self.val, key, is_relative) {
|
||||
Some(v) => v,
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
} else {
|
||||
match self.val.get(key.clone()) {
|
||||
Some(v) => v.clone(),
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range_with(&self, from: Option<isize>, to: Option<isize>) -> Option<RefValueWrapper> {
|
||||
fn _from<F: ArrayIndex>(from: Option<F>, val: &RefValueWrapper) -> usize {
|
||||
match from {
|
||||
Some(v) => v.index(val),
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
fn _to<F: ArrayIndex>(to: Option<F>, val: &RefValueWrapper) -> usize {
|
||||
match to {
|
||||
Some(v) => v.index(val),
|
||||
_ => {
|
||||
if let RefValue::Array(v) = val.deref() {
|
||||
v.len()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<RefValueWrapper> {
|
||||
trace!("range - {}:{}", from, to);
|
||||
|
||||
(from..to).into_iter()
|
||||
.map(|i| i.ref_value(v))
|
||||
.filter(|v| !v.is_null())
|
||||
.map(|v| v.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
if let RefValue::Array(vec) = &self.val.deref() {
|
||||
let ret = if self.is_leaves {
|
||||
vec.iter()
|
||||
.map(|v| _range(_from(from, v), _to(to, v), v))
|
||||
.flatten()
|
||||
.collect()
|
||||
} else {
|
||||
_range(_from(from, &self.val), _to(to, &self.val), &self.val)
|
||||
};
|
||||
Some(RefValue::Array(ret).into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pick_with_nums<I: ArrayIndex>(&self, indices: Vec<I>) -> Option<RefValueWrapper> {
|
||||
if let RefValue::Array(vec) = &self.val.deref() {
|
||||
let ret = if self.is_leaves {
|
||||
indices.iter()
|
||||
.map(|index| collect_not_null(vec.iter(), |v| { index.ref_value(v) }))
|
||||
.flatten()
|
||||
.collect()
|
||||
} else {
|
||||
indices.iter()
|
||||
.map(|index| index.ref_value(&self.val))
|
||||
.filter(|v| !v.is_null())
|
||||
.collect()
|
||||
};
|
||||
Some(RefValue::Array(ret).into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, val: RefValueWrapper) {
|
||||
self.val = match val.deref() {
|
||||
RefValue::Array(v) if v.is_empty() => RefValue::Null.into(),
|
||||
RefValue::Object(m) if m.is_empty() => RefValue::Null.into(),
|
||||
_ => val
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_val(&self) -> &RefValueWrapper {
|
||||
&self.val
|
||||
}
|
||||
|
||||
pub fn into_value(&self) -> Value {
|
||||
self.get_val().into()
|
||||
}
|
||||
|
||||
pub fn is_array(&self) -> bool {
|
||||
self.val.is_array()
|
||||
}
|
||||
|
||||
fn into_hashset(&self) -> IndexSet<&RefValue> {
|
||||
trace!("into_hashset");
|
||||
let mut hashset = IndexSet::new();
|
||||
match self.val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
for v in vec {
|
||||
hashset.insert(v.deref());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
hashset.insert(self.val.deref());
|
||||
}
|
||||
}
|
||||
hashset
|
||||
}
|
||||
|
||||
fn into_hashmap(&self) -> IndexMap<&RefValue, RefValueWrapper> {
|
||||
trace!("into_hashmap");
|
||||
let mut hashmap = IndexMap::new();
|
||||
match self.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
hashmap.insert(v.deref(), v.clone());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
hashmap.insert(self.val.deref(), self.val.clone());
|
||||
}
|
||||
}
|
||||
hashmap
|
||||
}
|
||||
|
||||
pub fn except(&self, other: &Self) -> Self {
|
||||
trace!("except");
|
||||
let hashset = self.into_hashset();
|
||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref vec) => {
|
||||
for v in vec {
|
||||
if !hashset.contains(v.deref()) {
|
||||
ret.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if !hashset.contains(&other.val.deref()) {
|
||||
ret.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||
ValueManager::new(RefValue::Array(vec).into(), false)
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: &Self) -> Self {
|
||||
trace!("intersect");
|
||||
let hashset = self.into_hashset();
|
||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
if hashset.contains(v.deref()) {
|
||||
ret.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
e => {
|
||||
if hashset.contains(e) {
|
||||
ret.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||
ValueManager::new(RefValue::Array(vec).into(), false)
|
||||
}
|
||||
|
||||
pub fn union(&self, other: &Self) -> Self {
|
||||
trace!("union");
|
||||
let origin = self.into_hashmap();
|
||||
let mut ret = IndexSet::new();
|
||||
|
||||
for o in origin.values() {
|
||||
ret.insert(o.clone());
|
||||
}
|
||||
|
||||
match other.val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
for v in vec {
|
||||
if !origin.contains_key(v.deref()) {
|
||||
ret.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if !origin.contains_key(&other.val.deref()) {
|
||||
ret.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||
ValueManager::new(RefValue::Array(vec).into(), false)
|
||||
}
|
||||
|
||||
pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
|
||||
match self.val.deref() {
|
||||
RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
|
||||
RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
||||
RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
|
||||
_ => TermContext::Json(match key {
|
||||
Some(vk) => Some(vk.clone()),
|
||||
_ => None
|
||||
}, ValueManager::new(self.val.clone(), false))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
|
||||
trace!("filter");
|
||||
let v = match self.val.deref() {
|
||||
RefValue::Array(ref vec) => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
if let Some(ValueFilterKey::String(k)) = key {
|
||||
if v.get(k.clone()).is_some() {
|
||||
ret.push(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
RefValue::Array(ret).into()
|
||||
}
|
||||
RefValue::Object(ref map) => {
|
||||
match key {
|
||||
Some(ValueFilterKey::String(k)) => match map.get(k) {
|
||||
Some(v) => v.clone(),
|
||||
_ => RefValue::Null.into()
|
||||
},
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
}
|
||||
_ => self.val.clone()
|
||||
};
|
||||
|
||||
ValueManager::new(v, false)
|
||||
}
|
||||
}
|
278
src/lib.rs
278
src/lib.rs
@ -1,10 +1,9 @@
|
||||
//! JsonPath implementation for Rust
|
||||
//! JsonPath implementation written in Rust.
|
||||
//!
|
||||
//! # Example
|
||||
//! ```
|
||||
//! extern crate jsonpath_lib as jsonpath;
|
||||
//! #[macro_use] extern crate serde_json;
|
||||
//!
|
||||
//! let json_obj = json!({
|
||||
//! "store": {
|
||||
//! "book": [
|
||||
@ -45,143 +44,103 @@
|
||||
//!
|
||||
//! let mut selector = jsonpath::selector(&json_obj);
|
||||
//!
|
||||
//! //
|
||||
//! // $.store.book[*].author
|
||||
//! //
|
||||
//! let json = selector("$.store.book[*].author").unwrap();
|
||||
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||
//! assert_eq!(json, ret);
|
||||
//!
|
||||
//! //
|
||||
//! // $..author
|
||||
//! //
|
||||
//! let json = selector("$..author").unwrap();
|
||||
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||
//! assert_eq!(json, ret);
|
||||
//!
|
||||
//! //
|
||||
//! // $.store.*
|
||||
//! //
|
||||
//! let json = selector("$.store.*").unwrap();
|
||||
//! let ret = json!([
|
||||
//! [
|
||||
//! {"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" : "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}
|
||||
//! ],
|
||||
//! {"color" : "red","price" : 19.95},
|
||||
//! assert_eq!(selector("$.store.book[*].author").unwrap(),
|
||||
//! vec![
|
||||
//! "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $.store..price
|
||||
//! //
|
||||
//! let json = selector("$.store..price").unwrap();
|
||||
//! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||
//! assert_eq!(ret, json);
|
||||
//! assert_eq!(selector("$..author").unwrap(),
|
||||
//! vec![
|
||||
//! "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
|
||||
//! ]);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[2]
|
||||
//! //
|
||||
//! let json = selector("$..book[2]").unwrap();
|
||||
//! let ret = json!([{
|
||||
//! assert_eq!(selector("$.store.*").unwrap(),
|
||||
//! vec![
|
||||
//! &json!([
|
||||
//! { "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": "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 }
|
||||
//! ]),
|
||||
//! &json!({ "color": "red", "price": 19.95 })
|
||||
//! ]);
|
||||
//!
|
||||
//! assert_eq!(selector("$.store..price").unwrap(),
|
||||
//! vec![
|
||||
//! 8.95, 12.99, 8.99, 22.99, 19.95
|
||||
//! ]);
|
||||
//!
|
||||
//! assert_eq!(selector("$..book[2]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({
|
||||
//! "category" : "fiction",
|
||||
//! "author" : "Herman Melville",
|
||||
//! "title" : "Moby Dick",
|
||||
//! "isbn" : "0-553-21311-3",
|
||||
//! "price" : 8.99
|
||||
//! }]);
|
||||
//! assert_eq!(ret, json);
|
||||
//! })
|
||||
//! ]);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[-2]
|
||||
//! //
|
||||
//! let json = selector("$..book[-2]").unwrap();
|
||||
//! let ret = json!([{
|
||||
//! assert_eq!(selector("$..book[-2]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({
|
||||
//! "category" : "fiction",
|
||||
//! "author" : "Herman Melville",
|
||||
//! "title" : "Moby Dick",
|
||||
//! "isbn" : "0-553-21311-3",
|
||||
//! "price" : 8.99
|
||||
//! }]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[0,1]
|
||||
//! //
|
||||
//! let json = selector("$..book[0,1]").unwrap();
|
||||
//! let ret = json!([
|
||||
//! {"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}
|
||||
//! })
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[:2]
|
||||
//! //
|
||||
//! let json = selector("$..book[:2]").unwrap();
|
||||
//! let ret = json!([
|
||||
//! {"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}
|
||||
//! assert_eq!(selector("$..book[0,1]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[2:]
|
||||
//! //
|
||||
//! let json = selector("$..book[2:]").unwrap();
|
||||
//! let ret = json!([
|
||||
//! {"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}
|
||||
//! assert_eq!(selector("$..book[:2]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $..book[?(@.isbn)]
|
||||
//! //
|
||||
//! let json = selector("$..book[?(@.isbn)]").unwrap();
|
||||
//! let ret = json!([
|
||||
//! {"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}
|
||||
//! assert_eq!(selector("$..book[:2]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
//! &json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//!
|
||||
//! //
|
||||
//! // $.store.book[?(@.price < 10)]
|
||||
//! //
|
||||
//! let json = selector("$.store.book[?(@.price < 10)]").unwrap();
|
||||
//! let ret = json!([
|
||||
//! {"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}
|
||||
//! assert_eq!(selector("$..book[?(@.isbn)]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}),
|
||||
//! &json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99})
|
||||
//! ]);
|
||||
//!
|
||||
//! assert_eq!(selector("$.store.book[?(@.price < 10)]").unwrap(),
|
||||
//! vec![
|
||||
//! &json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
//! &json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99})
|
||||
//! ]);
|
||||
//! assert_eq!(ret, json);
|
||||
//! ```
|
||||
|
||||
extern crate array_tool;
|
||||
extern crate core;
|
||||
extern crate env_logger;
|
||||
extern crate indexmap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
use core::borrow::BorrowMut;
|
||||
use std::result;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
pub use select::selector::Selector;
|
||||
#[doc(hidden)]
|
||||
mod parser;
|
||||
#[doc(hidden)]
|
||||
mod select;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod parser;
|
||||
#[doc(hidden)]
|
||||
pub mod filter;
|
||||
#[doc(hidden)]
|
||||
pub mod ref_value;
|
||||
#[doc(hidden)]
|
||||
pub mod select;
|
||||
pub use select::Selector;
|
||||
pub use select::JsonPathError;
|
||||
pub use parser::parser::Parser;
|
||||
|
||||
/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
|
||||
///
|
||||
@ -204,20 +163,22 @@ pub mod select;
|
||||
/// ]});
|
||||
///
|
||||
/// let json = template(&json_obj).unwrap();
|
||||
/// let ret = json!([
|
||||
/// {"name": "친구3", "age": 30},
|
||||
/// {"name": "친구1", "age": 20}
|
||||
///
|
||||
/// assert_eq!(json, vec![
|
||||
/// &json!({"name": "친구3", "age": 30}),
|
||||
/// &json!({"name": "친구1", "age": 20})
|
||||
/// ]);
|
||||
/// assert_eq!(json, ret);
|
||||
/// ```
|
||||
pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value, String> + 'a {
|
||||
let mut selector = Selector::new();
|
||||
let _ = selector.path(path);
|
||||
let mut selector = Box::new(selector);
|
||||
pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPathError> {
|
||||
let mut parser = Parser::new(path);
|
||||
let node = parser.compile();
|
||||
move |json| {
|
||||
let s: &mut Selector = selector.borrow_mut();
|
||||
let _ = s.value(&json);
|
||||
s.select_as_value()
|
||||
let mut selector = Selector::new();
|
||||
match &node {
|
||||
Ok(node) => selector.compiled_path(node.clone()),
|
||||
Err(e) => return Err(JsonPathError::Path(e.clone()))
|
||||
};
|
||||
selector.value(json).select()
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,26 +203,24 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value,
|
||||
/// let mut selector = jsonpath::selector(&json_obj);
|
||||
///
|
||||
/// let json = selector("$..friends[0]").unwrap();
|
||||
/// let ret = json!([
|
||||
/// {"name": "친구3", "age": 30},
|
||||
/// {"name": "친구1", "age": 20}
|
||||
///
|
||||
/// assert_eq!(json, vec![
|
||||
/// &json!({"name": "친구3", "age": 30}),
|
||||
/// &json!({"name": "친구1", "age": 20})
|
||||
/// ]);
|
||||
/// assert_eq!(json, ret);
|
||||
///
|
||||
/// let json = selector("$..friends[1]").unwrap();
|
||||
/// let ret = json!([
|
||||
/// {"name": "친구4"},
|
||||
/// {"name": "친구2", "age": 20}
|
||||
///
|
||||
/// assert_eq!(json, vec![
|
||||
/// &json!({"name": "친구4"}),
|
||||
/// &json!({"name": "친구2", "age": 20})
|
||||
/// ]);
|
||||
/// assert_eq!(json, ret);
|
||||
/// ```
|
||||
pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
|
||||
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError> {
|
||||
let mut selector = Selector::new();
|
||||
let _ = selector.value(json.into());
|
||||
let mut selector = Box::new(selector);
|
||||
move |path: &'a str| {
|
||||
let s: &mut Selector = selector.borrow_mut();
|
||||
s.path(path)?.select_as_value()
|
||||
let _ = selector.value(json);
|
||||
move |path: &str| {
|
||||
selector.path(path)?.reset_value().select()
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,15 +245,16 @@ pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value
|
||||
/// {"name": "친구4"}
|
||||
/// ]});
|
||||
///
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// #[derive(Deserialize, PartialEq, Debug)]
|
||||
/// struct Friend {
|
||||
/// name: String,
|
||||
/// age: Option<u8>,
|
||||
/// }
|
||||
///
|
||||
/// let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
|
||||
/// let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
|
||||
///
|
||||
/// let json = selector("$..friends[0]").unwrap();
|
||||
///
|
||||
/// let ret = vec!(
|
||||
/// Friend { name: "친구3".to_string(), age: Some(30) },
|
||||
/// Friend { name: "친구1".to_string(), age: Some(20) }
|
||||
@ -302,25 +262,22 @@ pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value
|
||||
/// assert_eq!(json, ret);
|
||||
///
|
||||
/// let json = selector("$..friends[1]").unwrap();
|
||||
///
|
||||
/// let ret = vec!(
|
||||
/// Friend { name: "친구4".to_string(), age: None },
|
||||
/// Friend { name: "친구2".to_string(), age: Some(20) }
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(json, ret);
|
||||
/// ```
|
||||
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> result::Result<T, String> {
|
||||
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
|
||||
let mut selector = Selector::new();
|
||||
let _ = selector.value(json.into());
|
||||
let _ = selector.value(json);
|
||||
move |path: &str| {
|
||||
selector.path(path)?.select_as()
|
||||
selector.path(path)?.reset_value().select_as()
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.4", note = "Please use the selector function instead")]
|
||||
pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
|
||||
selector(json)
|
||||
}
|
||||
|
||||
/// This function compile a jsonpath everytime and it convert `serde_json's Value` to `jsonpath's RefValue` everytime and then it return a `serde_json::value::Value`.
|
||||
///
|
||||
/// ```rust
|
||||
@ -341,25 +298,13 @@ pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value,
|
||||
///
|
||||
/// let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
|
||||
///
|
||||
/// let ret = json!([
|
||||
/// {"name": "친구3", "age": 30},
|
||||
/// {"name": "친구1", "age": 20}
|
||||
/// assert_eq!(json, vec![
|
||||
/// &json!({"name": "친구3", "age": 30}),
|
||||
/// &json!({"name": "친구1", "age": 20})
|
||||
/// ]);
|
||||
/// assert_eq!(json, ret);
|
||||
/// ```
|
||||
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
|
||||
let mut selector = Selector::new();
|
||||
selector.path(path)?.value(json)?.select_as_value()
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
|
||||
pub fn read(json: &Value, path: &str) -> result::Result<Value, String> {
|
||||
select(json, path)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.7", note = "Please use the select_as_str function instead")]
|
||||
pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
select_as_str(json, path)
|
||||
pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, JsonPathError> {
|
||||
Selector::new().path(path)?.value(json).select()
|
||||
}
|
||||
|
||||
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string.
|
||||
@ -385,11 +330,10 @@ pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
///
|
||||
/// assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
|
||||
/// ```
|
||||
pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
Selector::new()
|
||||
.path(path)?
|
||||
.value_from_str(json)?
|
||||
.select_as_str()
|
||||
pub fn select_as_str(json_str: &str, path: &str) -> Result<String, JsonPathError> {
|
||||
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
||||
let ret = Selector::new().path(path)?.value(&json).select()?;
|
||||
serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string()))
|
||||
}
|
||||
|
||||
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a deserialized-instance of type `T`.
|
||||
@ -408,7 +352,7 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
/// phones: Vec<String>,
|
||||
/// }
|
||||
///
|
||||
/// let ret: Person = jsonpath::select_as(r#"
|
||||
/// let ret: Vec<Person> = jsonpath::select_as(r#"
|
||||
/// {
|
||||
/// "person":
|
||||
/// {
|
||||
@ -428,11 +372,9 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
/// phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(person, ret);
|
||||
/// assert_eq!(ret[0], person);
|
||||
/// ```
|
||||
pub fn select_as<T: serde::de::DeserializeOwned>(json: &str, path: &str) -> result::Result<T, String> {
|
||||
Selector::new()
|
||||
.path(path)?
|
||||
.value_from_str(json)?
|
||||
.select_as()
|
||||
pub fn select_as<T: serde::de::DeserializeOwned>(json_str: &str, path: &str) -> Result<Vec<T>, JsonPathError> {
|
||||
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
||||
Selector::new().path(path)?.value(&json).select_as()
|
||||
}
|
@ -1,3 +1,525 @@
|
||||
mod path_reader;
|
||||
pub mod tokenizer;
|
||||
pub(crate) mod tokenizer;
|
||||
pub mod parser;
|
||||
|
||||
#[cfg(test)]
|
||||
mod parser_tests {
|
||||
use parser::parser::{ParseToken, Parser, NodeVisitor, FilterToken};
|
||||
|
||||
struct NodeVisitorTestImpl<'a> {
|
||||
input: &'a str,
|
||||
stack: Vec<ParseToken>,
|
||||
}
|
||||
|
||||
impl<'a> NodeVisitorTestImpl<'a> {
|
||||
fn new(input: &'a str) -> Self {
|
||||
NodeVisitorTestImpl { input, stack: Vec::new() }
|
||||
}
|
||||
|
||||
fn start(&mut self) -> Result<Vec<ParseToken>, String> {
|
||||
let mut parser = Parser::new(self.input);
|
||||
let node = parser.compile()?;
|
||||
self.visit(&node);
|
||||
Ok(self.stack.split_off(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> {
|
||||
fn visit_token(&mut self, token: &ParseToken) {
|
||||
self.stack.push(token.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
fn run(input: &str) -> Result<Vec<ParseToken>, String> {
|
||||
let mut interpreter = NodeVisitorTestImpl::new(input);
|
||||
interpreter.start()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_path() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$.aa"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("aa".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.00.a"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("00".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("a".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.00.韓창.seok"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("00".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("韓창".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("seok".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.*"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::All
|
||||
]));
|
||||
|
||||
assert_eq!(run("$..*"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Leaves,
|
||||
ParseToken::All
|
||||
]));
|
||||
|
||||
assert_eq!(run("$..[0]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Leaves,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(0.0),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$.") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$..") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$. a") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_array_sytax() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$.book[?(@.isbn)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("book".to_string()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Relative,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("isbn".to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
//
|
||||
// Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만
|
||||
//
|
||||
assert_eq!(run("$.[*]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[*]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[*].가"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::In, ParseToken::Key("가".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[0][1]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(0_f64),
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1_f64),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[1,2]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Union(vec![1, 2]),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[10:]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(Some(10), 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::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::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?(1>2)]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?($.b>3)]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?($.c>@.d && 1==2)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
|
||||
ParseToken::Filter(FilterToken::And),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?($.c>@.d&&(1==2||3>=4))]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
|
||||
ParseToken::Number(3_f64), ParseToken::Number(4_f64), ParseToken::Filter(FilterToken::GreaterOrEqual),
|
||||
ParseToken::Filter(FilterToken::Or),
|
||||
ParseToken::Filter(FilterToken::And),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?(@.a<@.b)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Little),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[*][*][*]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$['a']['bb']"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key("a".to_string()),
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key("bb".to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?(@.e==true)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("a".to_string()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Relative,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("e".to_string()),
|
||||
ParseToken::Bool(true),
|
||||
ParseToken::Filter(FilterToken::Equal),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$[") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[a]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?($.a)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(@.a > @.b]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(@.a < @.b&&(@.c < @.d)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_array_float() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$[?(1.1<2.1)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1.1), ParseToken::Number(2.1), ParseToken::Filter(FilterToken::Little),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$[1.1]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<.2)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.a)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tokenizer_tests {
|
||||
use parser::tokenizer::{Token, TokenError, Tokenizer, PreloadedTokenizer};
|
||||
|
||||
fn collect_token(input: &str) -> (Vec<Token>, Option<TokenError>) {
|
||||
let mut tokenizer = Tokenizer::new(input);
|
||||
let mut vec = vec![];
|
||||
loop {
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => vec.push(t),
|
||||
Err(e) => return (vec, Some(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(input: &str, expected: (Vec<Token>, Option<TokenError>)) {
|
||||
let (vec, err) = collect_token(input.clone());
|
||||
assert_eq!((vec, err), expected, "\"{}\"", input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek() {
|
||||
let mut tokenizer = PreloadedTokenizer::new("$.a");
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => assert_eq!(Token::Absolute(0), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(t) => assert_eq!(&Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(t) => assert_eq!(&Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => assert_eq!(Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token() {
|
||||
run("$.01.a",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Key(2, "01".to_string()),
|
||||
Token::Dot(4),
|
||||
Token::Key(5, "a".to_string())
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$. []",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Whitespace(2, 2),
|
||||
Token::OpenArray(5),
|
||||
Token::CloseArray(6)
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..ab",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
Token::Key(3, "ab".to_string())
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..가 [",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
Token::Key(3, "가".to_string()),
|
||||
Token::Whitespace(6, 0),
|
||||
Token::OpenArray(7),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("[-1, 2 ]",
|
||||
(
|
||||
vec![
|
||||
Token::OpenArray(0),
|
||||
Token::Key(1, "-1".to_string()),
|
||||
Token::Comma(3),
|
||||
Token::Whitespace(4, 0),
|
||||
Token::Key(5, "2".to_string()),
|
||||
Token::Whitespace(6, 0),
|
||||
Token::CloseArray(7),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("[ 1 2 , 3 \"abc\" : -10 ]",
|
||||
(
|
||||
vec![
|
||||
Token::OpenArray(0),
|
||||
Token::Whitespace(1, 0),
|
||||
Token::Key(2, "1".to_string()),
|
||||
Token::Whitespace(3, 0),
|
||||
Token::Key(4, "2".to_string()),
|
||||
Token::Whitespace(5, 0),
|
||||
Token::Comma(6),
|
||||
Token::Whitespace(7, 0),
|
||||
Token::Key(8, "3".to_string()),
|
||||
Token::Whitespace(9, 0),
|
||||
Token::DoubleQuoted(10, "abc".to_string()),
|
||||
Token::Whitespace(15, 0),
|
||||
Token::Split(16),
|
||||
Token::Whitespace(17, 0),
|
||||
Token::Key(18, "-10".to_string()),
|
||||
Token::Whitespace(21, 0),
|
||||
Token::CloseArray(22),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?(@.a가 <41.01)",
|
||||
(
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::At(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "a가".to_string()),
|
||||
Token::Whitespace(8, 0),
|
||||
Token::Little(9),
|
||||
Token::Key(10, "41".to_string()),
|
||||
Token::Dot(12),
|
||||
Token::Key(13, "01".to_string()),
|
||||
Token::CloseParenthesis(15),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?(@.a <4a.01)",
|
||||
(
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::At(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "a".to_string()),
|
||||
Token::Whitespace(5, 0),
|
||||
Token::Little(6),
|
||||
Token::Key(7, "4a".to_string()),
|
||||
Token::Dot(9),
|
||||
Token::Key(10, "01".to_string()),
|
||||
Token::CloseParenthesis(12),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?($.c>@.d)", (
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::Absolute(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "c".to_string()),
|
||||
Token::Greater(5),
|
||||
Token::At(6),
|
||||
Token::Dot(7),
|
||||
Token::Key(8, "d".to_string()),
|
||||
Token::CloseParenthesis(9)
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
use std::result::Result;
|
||||
|
||||
use super::tokenizer::*;
|
||||
|
||||
const DUMMY: usize = 0;
|
||||
@ -7,7 +5,6 @@ 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>() {
|
||||
@ -52,6 +49,8 @@ pub enum ParseToken {
|
||||
|
||||
Number(f64),
|
||||
|
||||
Bool(bool),
|
||||
|
||||
Eof,
|
||||
}
|
||||
|
||||
@ -87,12 +86,6 @@ impl<'a> Parser<'a> {
|
||||
Ok(self.json_path()?)
|
||||
}
|
||||
|
||||
pub fn parse<V: NodeVisitor>(&mut self, visitor: &mut V) -> ParseResult<()> {
|
||||
let node = self.json_path()?;
|
||||
visitor.visit(node);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn json_path(&mut self) -> ParseResult<Node> {
|
||||
debug!("#json_path");
|
||||
match self.tokenizer.next_token() {
|
||||
@ -235,6 +228,18 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn boolean(&mut self) -> ParseResult<Node> {
|
||||
debug!("#boolean");
|
||||
match self.tokenizer.next_token() {
|
||||
Ok(Token::Key(_, v)) => {
|
||||
Ok(self.node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
||||
}
|
||||
_ => {
|
||||
Err(self.tokenizer.err_msg())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array_quota_value(&mut self) -> ParseResult<Node> {
|
||||
debug!("#array_quota_value");
|
||||
match self.tokenizer.next_token() {
|
||||
@ -554,8 +559,14 @@ impl<'a> Parser<'a> {
|
||||
| Ok(Token::SingleQuoted(_, _)) => {
|
||||
self.array_quota_value()
|
||||
}
|
||||
Ok(Token::Key(_, _)) => {
|
||||
self.term_num()
|
||||
Ok(Token::Key(_, k)) => {
|
||||
match k.chars().next() {
|
||||
Some(ch) => match ch {
|
||||
'-' | '0'...'9' => self.term_num(),
|
||||
_ => self.boolean()
|
||||
}
|
||||
_ => Err(self.tokenizer.err_msg())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(self.tokenizer.err_msg())
|
||||
@ -629,49 +640,81 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
pub trait NodeVisitor {
|
||||
fn visit(&mut self, node: Node) {
|
||||
match node.token {
|
||||
fn visit(&mut self, node: &Node) {
|
||||
match &node.token {
|
||||
ParseToken::Absolute
|
||||
| ParseToken::Relative
|
||||
| ParseToken::All
|
||||
| ParseToken::Key(_) => {
|
||||
self.visit_token(node.token);
|
||||
| ParseToken::Key(_)
|
||||
| ParseToken::Range(_, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_)
|
||||
| ParseToken::Bool(_) => {
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::In
|
||||
| ParseToken::Leaves => {
|
||||
node.left.map(|n| self.visit(*n));
|
||||
self.visit_token(node.token);
|
||||
node.right.map(|n| self.visit(*n));
|
||||
}
|
||||
| ParseToken::Range(_, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_) => {
|
||||
self.visit_token(node.token);
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
| ParseToken::Array => {
|
||||
node.left.map(|n| self.visit(*n));
|
||||
self.visit_token(node.token);
|
||||
node.right.map(|n| self.visit(*n));
|
||||
self.visit_token(ParseToken::ArrayEof);
|
||||
self.visit_token(&node.token);
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ParseToken::Array => {
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
self.visit_token(&ParseToken::ArrayEof);
|
||||
}
|
||||
ParseToken::Filter(FilterToken::And)
|
||||
| ParseToken::Filter(FilterToken::Or) => {
|
||||
node.left.map(|n| self.visit(*n));
|
||||
node.right.map(|n| self.visit(*n));
|
||||
self.visit_token(node.token);
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::Filter(_) => {
|
||||
node.left.map(|n| self.visit(*n));
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
node.right.map(|n| self.visit(*n));
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
self.visit_token(node.token);
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_token(&mut self, token: ParseToken);
|
||||
fn visit_token(&mut self, token: &ParseToken);
|
||||
fn end_term(&mut self) {}
|
||||
}
|
1058
src/ref_value/de.rs
1058
src/ref_value/de.rs
File diff suppressed because it is too large
Load Diff
@ -1,4 +0,0 @@
|
||||
pub mod model;
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
pub mod serde_error;
|
@ -1,290 +0,0 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::map::IndexMap;
|
||||
use serde::ser::Serialize;
|
||||
use serde_json::{Number, Value};
|
||||
use std::fmt;
|
||||
|
||||
type TypeRefValue = Arc<RefCell<RefValue>>;
|
||||
|
||||
pub struct RefValueWrapper {
|
||||
data: TypeRefValue,
|
||||
}
|
||||
|
||||
impl fmt::Debug for RefValueWrapper {
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.deref().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl RefValueWrapper {
|
||||
pub fn ref_count(&self) -> usize {
|
||||
Arc::strong_count(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for RefValueWrapper {
|
||||
fn eq(&self, other: &RefValueWrapper) -> bool {
|
||||
Arc::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for RefValueWrapper {}
|
||||
|
||||
impl Deref for RefValueWrapper {
|
||||
type Target = RefValue;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.data.as_ptr().as_mut().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
//impl DerefMut for RefValueWrapper {
|
||||
// fn deref_mut(&mut self) -> &mut RefValue {
|
||||
// unsafe { self.data.as_ptr().as_mut().unwrap() }
|
||||
// }
|
||||
//}
|
||||
|
||||
impl Hash for RefValueWrapper {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.deref().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RefValueWrapper {
|
||||
fn clone(&self) -> Self {
|
||||
RefValueWrapper {
|
||||
data: self.data.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// serde_json::Value 참고
|
||||
///
|
||||
pub trait RefIndex {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper>;
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper>;
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper;
|
||||
}
|
||||
|
||||
impl RefIndex for usize {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Array(ref vec) => vec.get(*self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Array(ref mut vec) => vec.get_mut(*self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
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 RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Object(ref map) => map.get(self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Object(ref mut map) => map.get_mut(self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
if let RefValue::Null = *v {
|
||||
*v = RefValue::Object(IndexMap::new());
|
||||
}
|
||||
match *v {
|
||||
RefValue::Object(ref mut map) => {
|
||||
map.entry(self.to_owned()).or_insert(RefValue::Null.into())
|
||||
}
|
||||
_ => panic!("cannot access key {:?} in JSON {:?}", self, v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RefIndex for String {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> {
|
||||
self[..].index_into(v)
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
self[..].index_into_mut(v)
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
self[..].index_or_insert(v)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RefValue {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Number(Number),
|
||||
String(String),
|
||||
Array(Vec<RefValueWrapper>),
|
||||
Object(IndexMap<String, RefValueWrapper>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for RefValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for RefValue {
|
||||
fn eq(&self, other: &RefValue) -> bool {
|
||||
let mut hasher1 = DefaultHasher::new();
|
||||
let mut hasher2 = DefaultHasher::new();
|
||||
|
||||
self.hash(&mut hasher1);
|
||||
other.hash(&mut hasher2);
|
||||
|
||||
hasher1.finish() == hasher2.finish()
|
||||
}
|
||||
}
|
||||
|
||||
static REF_VALUE_NULL: &'static str = "$jsonpath::ref_value::model::RefValue::Null";
|
||||
|
||||
impl Hash for RefValue {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
|
||||
// println!("###hash - RefValue - {:?}", self);
|
||||
|
||||
match self {
|
||||
RefValue::Null => {
|
||||
REF_VALUE_NULL.hash(state)
|
||||
}
|
||||
RefValue::Bool(b) => {
|
||||
b.hash(state)
|
||||
}
|
||||
RefValue::Number(n) => {
|
||||
if n.is_f64() {
|
||||
n.as_f64().unwrap().to_string().hash(state)
|
||||
} else if n.is_i64() {
|
||||
n.as_i64().unwrap().hash(state);
|
||||
} else {
|
||||
n.as_u64().unwrap().hash(state);
|
||||
}
|
||||
}
|
||||
RefValue::String(s) => {
|
||||
s.hash(state)
|
||||
}
|
||||
RefValue::Object(map) => {
|
||||
for (k, v) in map {
|
||||
k.hash(state);
|
||||
v.hash(state);
|
||||
}
|
||||
}
|
||||
RefValue::Array(v) => {
|
||||
for i in v {
|
||||
i.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for RefValue {}
|
||||
|
||||
impl RefValue {
|
||||
pub fn get<I: RefIndex>(&self, index: I) -> Option<&RefValueWrapper> {
|
||||
index.index_into(self)
|
||||
}
|
||||
|
||||
pub fn is_object(&self) -> bool {
|
||||
match *self {
|
||||
RefValue::Object(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_array(&self) -> bool {
|
||||
match *self {
|
||||
RefValue::Array(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match &self {
|
||||
RefValue::Object(m) => m.len(),
|
||||
RefValue::Array(v) => v.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match &self {
|
||||
RefValue::Object(m) => m.is_empty(),
|
||||
RefValue::Array(v) => v.is_empty(),
|
||||
RefValue::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_null(&self) -> bool {
|
||||
match *self {
|
||||
RefValue::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RefValueWrapper> for RefValue {
|
||||
fn into(self) -> RefValueWrapper {
|
||||
RefValueWrapper {
|
||||
data: Arc::new(RefCell::new(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RefValue> for &Value {
|
||||
fn into(self) -> RefValue {
|
||||
match self.serialize(super::ser::RefValueSerializer) {
|
||||
Ok(v) => v,
|
||||
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RefValueWrapper> for &Value {
|
||||
fn into(self) -> RefValueWrapper {
|
||||
match self.serialize(super::ser::RefValueSerializer) {
|
||||
Ok(v) => v.into(),
|
||||
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Value> for &RefValueWrapper {
|
||||
fn into(self) -> Value {
|
||||
match serde_json::to_value(self.deref()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => panic!("Error RefValueWrapper into Value: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,624 +0,0 @@
|
||||
use std::result::Result;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use serde::{self, Serialize};
|
||||
use serde::ser::Impossible;
|
||||
|
||||
use ref_value::model::{RefValue, RefValueWrapper};
|
||||
|
||||
use super::serde_error::SerdeError;
|
||||
|
||||
///
|
||||
/// see `serde_json/value/ser.rs`
|
||||
///
|
||||
impl Serialize for RefValue {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ::serde::Serializer,
|
||||
{
|
||||
match *self {
|
||||
RefValue::Null => serializer.serialize_unit(),
|
||||
RefValue::Bool(b) => serializer.serialize_bool(b),
|
||||
RefValue::Number(ref n) => n.serialize(serializer),
|
||||
RefValue::String(ref s) => serializer.serialize_str(s),
|
||||
RefValue::Array(ref v) => {
|
||||
use std::ops::Deref;
|
||||
let v: Vec<&RefValue> = v.iter().map(|v| v.deref()).collect();
|
||||
v.serialize(serializer)
|
||||
}
|
||||
RefValue::Object(ref m) => {
|
||||
use serde::ser::SerializeMap;
|
||||
use std::ops::Deref;
|
||||
let mut map = try!(serializer.serialize_map(Some(m.len())));
|
||||
for (k, v) in m {
|
||||
try!(map.serialize_key(k));
|
||||
try!(map.serialize_value(v.deref()));
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RefValueSerializer;
|
||||
|
||||
impl serde::Serializer for RefValueSerializer {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
type SerializeSeq = SerializeVec;
|
||||
type SerializeTuple = SerializeVec;
|
||||
type SerializeTupleStruct = SerializeVec;
|
||||
type SerializeTupleVariant = SerializeTupleVariant;
|
||||
type SerializeMap = SerializeMap;
|
||||
type SerializeStruct = SerializeMap;
|
||||
type SerializeStructVariant = SerializeStructVariant;
|
||||
|
||||
#[inline]
|
||||
fn serialize_bool(self, value: bool) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::Bool(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i8(self, value: i8) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_i64(value as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i16(self, value: i16) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_i64(value as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i32(self, value: i32) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_i64(value as i64)
|
||||
}
|
||||
|
||||
fn serialize_i64(self, value: i64) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::Number(value.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u8(self, value: u8) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_u64(value as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u16(self, value: u16) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_u64(value as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u32(self, value: u32) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_u64(value as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u64(self, value: u64) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::Number(value.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f32(self, value: f32) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_f64(value as f64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f64(self, value: f64) -> Result<RefValue, Self::Error> {
|
||||
Ok(serde_json::Number::from_f64(value).map_or(RefValue::Null, RefValue::Number))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_char(self, value: char) -> Result<RefValue, Self::Error> {
|
||||
let mut s = String::new();
|
||||
s.push(value);
|
||||
self.serialize_str(&s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_str(self, value: &str) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::String(value.to_owned()))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, value: &[u8]) -> Result<RefValue, Self::Error> {
|
||||
let vec = value.iter().map(|&b| RefValue::Number(b.into()).into()).collect();
|
||||
Ok(RefValue::Array(vec))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit(self) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::Null)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_unit()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_str(variant)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<RefValue, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<RefValue, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut values: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
values.insert(String::from(variant), {
|
||||
value.serialize(RefValueSerializer)?.into()
|
||||
});
|
||||
Ok(RefValue::Object(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_none(self) -> Result<RefValue, Self::Error> {
|
||||
self.serialize_unit()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<RefValue, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Ok(SerializeVec {
|
||||
vec: Vec::with_capacity(len.unwrap_or(0)),
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
self.serialize_seq(Some(len))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
self.serialize_seq(Some(len))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Ok(SerializeTupleVariant {
|
||||
name: String::from(variant),
|
||||
vec: Vec::with_capacity(len),
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Ok(SerializeMap::Map {
|
||||
map: IndexMap::new(),
|
||||
next_key: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
match name {
|
||||
_ => self.serialize_map(Some(len)),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
Ok(SerializeStructVariant {
|
||||
name: String::from(variant),
|
||||
map: IndexMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SerializeVec {
|
||||
vec: Vec<RefValueWrapper>,
|
||||
}
|
||||
|
||||
pub struct SerializeTupleVariant {
|
||||
name: String,
|
||||
vec: Vec<RefValueWrapper>,
|
||||
}
|
||||
|
||||
pub enum SerializeMap {
|
||||
Map {
|
||||
map: IndexMap<String, RefValueWrapper>,
|
||||
next_key: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct SerializeStructVariant {
|
||||
name: String,
|
||||
map: IndexMap<String, RefValueWrapper>,
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeSeq for SerializeVec {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.vec.push({
|
||||
value.serialize(RefValueSerializer)?.into()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
Ok(RefValue::Array(self.vec))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeTuple for SerializeVec {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
serde::ser::SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
serde::ser::SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeTupleStruct for SerializeVec {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
serde::ser::SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
serde::ser::SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.vec.push({
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
let mut object: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
|
||||
object.insert(self.name, RefValue::Array(self.vec).into());
|
||||
|
||||
Ok(RefValue::Object(object))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeMap for SerializeMap {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
match *self {
|
||||
SerializeMap::Map {
|
||||
ref mut next_key, ..
|
||||
} => {
|
||||
*next_key = Some(key.serialize(MapKeySerializer)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
match *self {
|
||||
SerializeMap::Map {
|
||||
ref mut map,
|
||||
ref mut next_key,
|
||||
} => {
|
||||
let key = next_key.take();
|
||||
// Panic because this indicates a bug in the program rather than an
|
||||
// expected failure.
|
||||
let key = key.expect("serialize_value called before serialize_key");
|
||||
map.insert(key, {
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
match self {
|
||||
SerializeMap::Map { map, .. } => Ok(RefValue::Object(map)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MapKeySerializer;
|
||||
|
||||
fn key_must_be_a_string() -> SerdeError {
|
||||
SerdeError::from_str("key must be string")
|
||||
}
|
||||
|
||||
impl serde::Serializer for MapKeySerializer {
|
||||
type Ok = String;
|
||||
type Error = SerdeError;
|
||||
|
||||
type SerializeSeq = Impossible<String, Self::Error>;
|
||||
type SerializeTuple = Impossible<String, Self::Error>;
|
||||
type SerializeTupleStruct = Impossible<String, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<String, Self::Error>;
|
||||
type SerializeMap = Impossible<String, Self::Error>;
|
||||
type SerializeStruct = Impossible<String, Self::Error>;
|
||||
type SerializeStructVariant = Impossible<String, Self::Error>;
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(variant.to_owned())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
|
||||
Ok({
|
||||
let mut s = String::new();
|
||||
s.push(value);
|
||||
s
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(value.to_owned())
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
Err(key_must_be_a_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeStruct for SerializeMap {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
match *self {
|
||||
SerializeMap::Map { .. } => {
|
||||
serde::ser::SerializeMap::serialize_key(self, key)?;
|
||||
serde::ser::SerializeMap::serialize_value(self, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
match self {
|
||||
SerializeMap::Map { .. } => serde::ser::SerializeMap::end(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
||||
type Ok = RefValue;
|
||||
type Error = SerdeError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.map.insert(String::from(key), {
|
||||
let a: RefValue = value.serialize(RefValueSerializer)?;
|
||||
a.into()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<RefValue, Self::Error> {
|
||||
let mut object: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
|
||||
object.insert(self.name, RefValue::Object(self.map).into());
|
||||
|
||||
Ok(RefValue::Object(object))
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SerdeError {
|
||||
msg: String,
|
||||
}
|
||||
|
||||
impl<'a> SerdeError {
|
||||
pub fn new(msg: String) -> Self {
|
||||
SerdeError { msg: msg }
|
||||
}
|
||||
|
||||
pub fn from_str(msg: &str) -> Self {
|
||||
SerdeError { msg: msg.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for SerdeError {
|
||||
#[cold]
|
||||
fn custom<T: fmt::Display>(msg: T) -> SerdeError {
|
||||
SerdeError { msg: msg.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Error for SerdeError {
|
||||
#[cold]
|
||||
fn custom<T: fmt::Display>(msg: T) -> SerdeError {
|
||||
SerdeError { msg: msg.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SerdeError {}
|
||||
|
||||
impl fmt::Display for SerdeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.msg)
|
||||
}
|
||||
}
|
1004
src/select/mod.rs
1004
src/select/mod.rs
File diff suppressed because it is too large
Load Diff
@ -1,60 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
|
||||
use ref_value::model::{RefValue, RefValueWrapper};
|
||||
use Selector;
|
||||
|
||||
pub trait Modifiable {
|
||||
fn delete(&mut self) -> Result<&mut Self, String>;
|
||||
}
|
||||
|
||||
impl Modifiable for Selector {
|
||||
fn delete(&mut self) -> Result<&mut Self, String> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse(parent_path: String, v: &RefValueWrapper, buf: &mut HashMap<RefValueWrapper, String>, depth: usize, limit: usize) {
|
||||
if depth >= limit {
|
||||
return;
|
||||
}
|
||||
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
for (i, v) in vec.iter().enumerate() {
|
||||
buf.insert(v.clone(), format!("{}/{}", parent_path, i.to_string()));
|
||||
}
|
||||
for (i, v) in vec.iter().enumerate() {
|
||||
traverse(format!("{}/{}", parent_path, i.to_string()), v, buf, depth + 1, limit);
|
||||
}
|
||||
}
|
||||
RefValue::Object(map) => {
|
||||
for (k, v) in map.into_iter() {
|
||||
buf.insert(v.clone(), format!("{}/{}", parent_path, k.to_string()));
|
||||
}
|
||||
for (k, v) in map.into_iter() {
|
||||
traverse(format!("{}/{}", parent_path, k.to_string()), v, buf, depth + 1, limit);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
buf.insert(v.clone(), parent_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PathFinder {
|
||||
map: HashMap<RefValueWrapper, String>,
|
||||
}
|
||||
|
||||
impl PathFinder {
|
||||
pub fn new(v: RefValueWrapper) -> Self {
|
||||
let mut map = HashMap::new();
|
||||
traverse("/".to_string(), &v, &mut map, 0, 1);
|
||||
debug!("map: {:?}", map);
|
||||
PathFinder { map }
|
||||
}
|
||||
|
||||
pub fn get(&self, v: &RefValueWrapper) -> Option<&String> {
|
||||
self.map.get(v)
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
use std::{fmt, result};
|
||||
use std::ops::Deref;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use filter::value_filter::*;
|
||||
use parser::parser::*;
|
||||
use ref_value;
|
||||
use ref_value::model::*;
|
||||
|
||||
/// Utility. Functions like jsonpath::selector or jsonpath::compile are also implemented using this structure.
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate jsonpath_lib as jsonpath;
|
||||
/// extern crate serde;
|
||||
/// extern crate serde_json;
|
||||
///
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_json::Value;
|
||||
///
|
||||
/// use jsonpath::Selector;
|
||||
///
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct Person {
|
||||
/// name: String,
|
||||
/// age: Option<u8>,
|
||||
/// phone: String,
|
||||
/// }
|
||||
///
|
||||
/// fn input_str() -> &'static str {
|
||||
/// r#"[
|
||||
/// {
|
||||
/// "name": "이름1",
|
||||
/// "age": 40,
|
||||
/// "phone": "+33 12341234"
|
||||
/// },
|
||||
/// {
|
||||
/// "name": "이름2",
|
||||
/// "age": 42,
|
||||
/// "phone": "++44 12341234"
|
||||
/// }
|
||||
/// ]"#
|
||||
/// }
|
||||
///
|
||||
/// fn input_json() -> Value {
|
||||
/// serde_json::from_str(input_str()).unwrap()
|
||||
/// }
|
||||
///
|
||||
/// fn input_person() -> Vec<Person> {
|
||||
/// serde_json::from_str(input_str()).unwrap()
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// let mut selector = Selector::new();
|
||||
///
|
||||
/// let result = selector
|
||||
/// .path("$..[?(@.age > 40)]").unwrap()
|
||||
/// .value_from_str(input_str()).unwrap()
|
||||
/// .select_as_value().unwrap();
|
||||
/// assert_eq!(input_json()[1], result[0]);
|
||||
///
|
||||
/// let result = selector.select_as_str().unwrap();
|
||||
/// assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
|
||||
///
|
||||
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||
/// assert_eq!(input_person()[1], result[0]);
|
||||
///
|
||||
/// let _ = selector.path("$..[?(@.age == 40)]");
|
||||
///
|
||||
/// let result = selector.select_as_value().unwrap();
|
||||
/// assert_eq!(input_json()[0], result[0]);
|
||||
///
|
||||
/// let result = selector.select_as_str().unwrap();
|
||||
/// assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
||||
///
|
||||
/// let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||
/// assert_eq!(input_person()[0], result[0]);
|
||||
///
|
||||
/// selector.map(|v| {
|
||||
/// let r = match v {
|
||||
/// Value::Array(mut vec) => {
|
||||
/// for mut v in &mut vec {
|
||||
/// v.as_object_mut().unwrap().remove("age");
|
||||
/// }
|
||||
/// Value::Array(vec)
|
||||
/// }
|
||||
/// _ => Value::Null
|
||||
/// };
|
||||
/// Some(r)
|
||||
/// });
|
||||
/// assert_eq!(
|
||||
/// serde_json::from_str::<Value>(r#"[{ "name": "이름1", "phone": "+33 12341234"}]"#).unwrap(),
|
||||
/// selector.get().unwrap());
|
||||
///
|
||||
/// selector.value_from_str(input_str()).unwrap()
|
||||
/// .map_as(|mut v: Vec<Person>| {
|
||||
/// let mut p = v.pop().unwrap();
|
||||
/// p.name = "name1".to_string();
|
||||
/// p.age = None;
|
||||
/// Some(vec![p])
|
||||
/// });
|
||||
/// assert_eq!(
|
||||
/// vec![Person { name: "name1".to_string(), age: None, phone: "+33 12341234".to_string() }],
|
||||
/// selector.get_as::<Vec<Person>>().unwrap());
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Selector {
|
||||
pub(crate) node: Option<Node>,
|
||||
pub(crate) value: Option<RefValueWrapper>,
|
||||
}
|
||||
|
||||
impl Selector {
|
||||
pub fn new() -> Self {
|
||||
Selector { node: None, value: None }
|
||||
}
|
||||
|
||||
fn set_value(&mut self, value: RefValueWrapper) {
|
||||
// (*self.path_builder).borrow_mut().replace(&value);
|
||||
self.value = Some(value);
|
||||
}
|
||||
|
||||
pub fn path(&mut self, path: &str) -> result::Result<&mut Self, String> {
|
||||
let mut parser = Parser::new(path);
|
||||
self.node = Some(parser.compile()?);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn value(&mut self, value: &Value) -> result::Result<&mut Self, String> {
|
||||
self.set_value(value.into());
|
||||
// (*self.path_builder).borrow_mut().print();
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn value_from_ref_value(&mut self, value: RefValueWrapper) -> result::Result<&mut Self, String> {
|
||||
self.set_value(value);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn value_from(&mut self, serializable: &impl serde::ser::Serialize) -> result::Result<&mut Self, String> {
|
||||
let ref_value: RefValue = serializable
|
||||
.serialize(ref_value::ser::RefValueSerializer)
|
||||
.map_err(|e| e.to_string())?;
|
||||
self.set_value(ref_value.into());
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
|
||||
let value: RefValue = serde_json::from_str(json_str)
|
||||
.map_err(|e| e.to_string())?;
|
||||
self.set_value(value.into());
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn jf(&self) -> result::Result<JsonValueFilter, String> {
|
||||
match &self.value {
|
||||
Some(v) => Ok(JsonValueFilter::new(v.clone())),
|
||||
_ => return Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn select(&self) -> result::Result<RefValueWrapper, String> {
|
||||
let mut jf = self.jf()?;
|
||||
|
||||
match &self.node {
|
||||
Some(node) => {
|
||||
jf.visit(node.clone());
|
||||
Ok(jf.clone_value())
|
||||
}
|
||||
_ => Err(SelectorErrorMessage::EmptyPath.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.13", note = "Please use the select_as_str function instead")]
|
||||
pub fn select_to_str(&self) -> result::Result<String, String> {
|
||||
self.select_as_str()
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.13", note = "Please use the select_as_value function instead")]
|
||||
pub fn select_to_value(&self) -> result::Result<Value, String> {
|
||||
self.select_as_value()
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.1.13", note = "Please use the select_as function instead")]
|
||||
pub fn select_to<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||
self.select_as()
|
||||
}
|
||||
|
||||
pub fn select_as_str(&self) -> result::Result<String, String> {
|
||||
serde_json::to_string(self.select()?.deref()).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub fn select_as_value(&self) -> result::Result<Value, String> {
|
||||
Ok((&self.select()?).into())
|
||||
}
|
||||
|
||||
pub fn select_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||
T::deserialize(self.select()?.deref()).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub fn map<F>(&mut self, func: F) -> result::Result<&mut Self, String>
|
||||
where F: FnOnce(Value) -> Option<Value>
|
||||
{
|
||||
match func((&self.select()?).into()).map(|ref v| v.into()) {
|
||||
Some(value) => {
|
||||
self.set_value(value)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn map_as<F, D, S>(&mut self, func: F) -> result::Result<&mut Self, String>
|
||||
where F: FnOnce(D) -> Option<S>,
|
||||
D: serde::de::DeserializeOwned,
|
||||
S: serde::ser::Serialize
|
||||
{
|
||||
let ret = func(D::deserialize(self.select()?.deref()).map_err(|e| e.to_string())?)
|
||||
.map(|ref ser| ser.serialize(ref_value::ser::RefValueSerializer));
|
||||
|
||||
match ret {
|
||||
Some(ret) => match ret {
|
||||
Ok(v) => self.set_value(v.into()),
|
||||
Err(e) => return Err(e.to_string())
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn get(&self) -> result::Result<Value, String> {
|
||||
match &self.value {
|
||||
Some(value) => Ok(value.into()),
|
||||
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as<T: serde::de::DeserializeOwned>(&self) -> result::Result<T, String> {
|
||||
match &self.value {
|
||||
Some(value) => T::deserialize(value.deref()).map_err(|e| e.to_string()),
|
||||
_ => Err(SelectorErrorMessage::EmptyValue.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SelectorErrorMessage {
|
||||
EmptyValue,
|
||||
EmptyPath,
|
||||
}
|
||||
|
||||
impl fmt::Display for SelectorErrorMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
SelectorErrorMessage::EmptyValue => write!(f, "Empty value"),
|
||||
SelectorErrorMessage::EmptyPath => write!(f, "Empty path"),
|
||||
}
|
||||
}
|
||||
}
|
44
tests/common.rs
Normal file
44
tests/common.rs
Normal file
@ -0,0 +1,44 @@
|
||||
extern crate env_logger;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use self::jsonpath::Selector;
|
||||
|
||||
pub fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn read_json(path: &str) -> Value {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
serde_json::from_str(&contents).unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn read_contents(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path(path);
|
||||
let _ = s.value(&json);
|
||||
let result = serde_json::to_value(s.select().unwrap()).unwrap();
|
||||
assert_eq!(result, target, "{}", path);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn compare_result<'a>(result: Vec<&Value>, target: Value) {
|
||||
let result = serde_json::to_value(result).unwrap();
|
||||
assert_eq!(result, target);
|
||||
}
|
409
tests/filter.rs
409
tests/filter.rs
@ -1,223 +1,140 @@
|
||||
extern crate core;
|
||||
extern crate env_logger;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use jsonpath::Selector;
|
||||
use jsonpath::filter::value_filter::ValueFilter;
|
||||
use common::{read_json, select_and_then_compare, setup};
|
||||
|
||||
fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
fn new_value_filter(file: &str) -> ValueFilter {
|
||||
let string = read_json(file);
|
||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
ValueFilter::new((&json).into(), false, false)
|
||||
}
|
||||
|
||||
fn selector(path: &str, file: &str) -> Selector {
|
||||
let string = read_json(file);
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path(path);
|
||||
let _ = s.value_from_str(&string);
|
||||
s
|
||||
}
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn step_in() {
|
||||
setup();
|
||||
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
let current = jf.step_in_str("friends");
|
||||
assert_eq!(current.is_array(), true);
|
||||
}
|
||||
|
||||
let mut jf = new_value_filter("./benches/data_array.json");
|
||||
{
|
||||
let current = jf.step_in_num(&1.0);
|
||||
assert_eq!(current.get_val().is_object(), true);
|
||||
}
|
||||
{
|
||||
let current = jf.step_in_str("friends");
|
||||
assert_eq!(current.is_array(), true);
|
||||
}
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
jf.step_in_str("school");
|
||||
jf.step_in_str("friends");
|
||||
jf.step_in_all();
|
||||
let current = jf.step_in_str("name");
|
||||
let friends = json!([
|
||||
"Millicent Norman",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
|
||||
assert_eq!(friends, current.into_value());
|
||||
}
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
let current = jf.step_leaves_str("name");
|
||||
let names = json!([
|
||||
"Leonor Herman",
|
||||
"Millicent Norman",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry",
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
assert_eq!(names, current.into_value());
|
||||
}
|
||||
}
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
setup();
|
||||
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.school.friends[1, 2]", read_json("./benches/data_obj.json"), json!([
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]);
|
||||
]));
|
||||
|
||||
let s = selector("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$.school.friends[1: ]", read_json("./benches/data_obj.json"), json!([
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]));
|
||||
|
||||
let s = selector("$.school.friends[1:]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let s = selector("$.school.friends[:-2]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.school.friends[:-2]", read_json("./benches/data_obj.json"), json!([
|
||||
{"id": 0, "name": "Millicent Norman"}
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$..friends[2].name", "./benches/data_obj.json");
|
||||
let friends = json!(["Gray Berry", "Gray Berry"]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$..friends[2].name", read_json("./benches/data_obj.json"), json!([
|
||||
"Gray Berry", "Gray Berry"
|
||||
]));
|
||||
|
||||
let s = selector("$..friends[*].name", "./benches/data_obj.json");
|
||||
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$..friends[*].name", read_json("./benches/data_obj.json"), json!([
|
||||
"Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"
|
||||
]));
|
||||
|
||||
let s = selector("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
||||
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$['school']['friends'][*].['name']", read_json("./benches/data_obj.json"), json!([
|
||||
"Millicent Norman","Vincent Cannon","Gray Berry"
|
||||
]));
|
||||
|
||||
let s = selector("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
||||
let friends = json!("Millicent Norman");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$['school']['friends'][0].['name']", read_json("./benches/data_obj.json"), json!([
|
||||
"Millicent Norman"
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_type() {
|
||||
setup();
|
||||
|
||||
let friends = json!({
|
||||
select_and_then_compare("$.school", read_json("./benches/data_obj.json"), json!([{
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]
|
||||
});
|
||||
}]));
|
||||
|
||||
let s = selector("$.school", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let s = selector("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let s = selector("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, s.select_as_value().unwrap());
|
||||
|
||||
let s = selector("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
|
||||
let s = selector("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.school[?(@.friends[0])]", read_json("./benches/data_obj.json"), json!([{
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]
|
||||
}]));
|
||||
|
||||
select_and_then_compare("$.school[?(@.friends[10])]", read_json("./benches/data_obj.json"), json!([{
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]
|
||||
}]));
|
||||
|
||||
select_and_then_compare("$.school[?(1==1)]", read_json("./benches/data_obj.json"), json!([{
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]
|
||||
}]));
|
||||
|
||||
select_and_then_compare("$.school.friends[?(1==1)]", read_json("./benches/data_obj.json"), json!([[
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_default() {
|
||||
setup();
|
||||
|
||||
let s = selector("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json");
|
||||
let friends = json!({
|
||||
select_and_then_compare("$.school[?(@.friends == @.friends)]", read_json("./benches/data_obj.json"), json!([{
|
||||
"friends": [
|
||||
{"id": 0, "name": "Millicent Norman"},
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]
|
||||
});
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
}]));
|
||||
|
||||
let s = selector("$.friends[?(@.name)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.friends[?(@.name)]", read_json("./benches/data_obj.json"), json!([
|
||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
||||
{ "id" : 2, "name" : "Gray Berry" }
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.friends[?(@.id >= 2)]", read_json("./benches/data_obj.json"), json!([
|
||||
{ "id" : 2, "name" : "Gray Berry" }
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
select_and_then_compare("$.friends[?(@.id >= 2 || @.id == 1)]", read_json("./benches/data_obj.json"), json!([
|
||||
{ "id" : 2, "name" : "Gray Berry" },
|
||||
{ "id" : 1, "name" : "Vincent Cannon" }
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", read_json("./benches/data_obj.json"), json!([
|
||||
Value::Null
|
||||
]));
|
||||
|
||||
let s = selector("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
||||
let friends = json!([0, 0]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$..friends[?(@.id == $.index)].id", read_json("./benches/data_obj.json"), json!([
|
||||
0, 0
|
||||
]));
|
||||
|
||||
let s = selector("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
||||
let friends = json!([22.99]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$..book[?($.store.bicycle.price < @.price)].price", read_json("./benches/example.json"), json!([
|
||||
22.99
|
||||
]));
|
||||
|
||||
let s = selector("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
||||
let friends = json!([12.99]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
select_and_then_compare("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", read_json("./benches/example.json"), json!([
|
||||
12.99
|
||||
]));
|
||||
|
||||
let ref value = json!([
|
||||
select_and_then_compare("$..[?(@.age > 40)]", json!([
|
||||
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
||||
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
||||
]);
|
||||
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path("$..[?(@.age > 40)]");
|
||||
let _ = s.value(value);
|
||||
let friends = json!([
|
||||
]), json!([
|
||||
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
||||
]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let ref value = json!({
|
||||
select_and_then_compare("$..[?(@.age >= 30)]", json!({
|
||||
"school": {
|
||||
"friends": [
|
||||
{"name": "친구1", "age": 20},
|
||||
@ -227,103 +144,82 @@ fn op_default() {
|
||||
"friends": [
|
||||
{"name": "친구3", "age": 30},
|
||||
{"name": "친구4"}
|
||||
]});
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path("$..[?(@.age >= 30)]");
|
||||
let _ = s.value(value);
|
||||
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
|
||||
assert_eq!(friends, s.select_as_value().unwrap());
|
||||
]}), json!([
|
||||
{ "name" : "친구3", "age" : 30 }
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_number() {
|
||||
setup();
|
||||
|
||||
let json = json!({ "a": 1 });
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a == 1)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a != 2)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a < 2)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a <= 1)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a > 0)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, "$.[?(@.a >= 0)]").unwrap();
|
||||
assert_eq!(json, ret);
|
||||
select_and_then_compare("$.[?(@.a == 1)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
select_and_then_compare("$.[?(@.a != 2)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
select_and_then_compare("$.[?(@.a < 2)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
select_and_then_compare("$.[?(@.a <= 1)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
select_and_then_compare("$.[?(@.a > 0)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
select_and_then_compare("$.[?(@.a >= 0)]", json!({ "a": 1 }), json!([{ "a": 1 }]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_string() {
|
||||
setup();
|
||||
|
||||
let json = json!({ "a": "b" });
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a == "b")]"#).unwrap();
|
||||
assert_eq!(json!({ "a": "b" }), ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a != "c")]"#).unwrap();
|
||||
assert_eq!(json!({ "a": "b" }), ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a < "b")]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a <= "b")]"#).unwrap();
|
||||
assert_eq!(json!({ "a": "b" }), ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a > "b")]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a >= "b")]"#).unwrap();
|
||||
assert_eq!(json!({ "a": "b" }), ret);
|
||||
select_and_then_compare(r#"$.[?(@.a == "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]));
|
||||
select_and_then_compare(r#"$.[?(@.a != "c")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]));
|
||||
select_and_then_compare(r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a <= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]));
|
||||
select_and_then_compare(r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a >= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_object() {
|
||||
setup();
|
||||
|
||||
let json = json!({
|
||||
"a": { "1": 1 },
|
||||
"b": { "2": 2 },
|
||||
"c": { "1": 1 },
|
||||
});
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a == @.c)]"#).unwrap();
|
||||
assert_eq!(json, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a != @.c)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a < @.c)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a <= @.c)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a > @.c)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a >= @.c)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
select_and_then_compare(r#"$.[?(@.a == @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([{"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}]));
|
||||
select_and_then_compare(r#"$.[?(@.a != @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a < @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a <= @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a > @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a >= @.c)]"#,
|
||||
json!({"a": { "1": 1 }, "b": { "2": 2 }, "c": { "1": 1 }}),
|
||||
json!([Value::Null]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_complex() {
|
||||
setup();
|
||||
|
||||
let json = json!({ "a": { "b": 1 } });
|
||||
let ret = jsonpath::select(&json, r#"$.[?(1 == @.a)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?("1" != @.a)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a <= 1)]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
let ret = jsonpath::select(&json, r#"$.[?(@.a > "1")]"#).unwrap();
|
||||
assert_eq!(Value::Null, ret);
|
||||
select_and_then_compare(r#"$.[?(1 == @.a)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?("1" != @.a)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a <= 1)]"#, json!({ "a": { "b": 1 } }), json!([Value::Null]));
|
||||
select_and_then_compare(r#"$.[?(@.a > "1")]"#, json!({ "a": { "b": 1 } }), json!([Value::Null]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
setup();
|
||||
|
||||
let s = selector("$.store.book[*].author", "./benches/example.json");
|
||||
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
select_and_then_compare(r#"$.store.book[*].author"#, read_json("./benches/example.json"), json!([
|
||||
"Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"
|
||||
]));
|
||||
|
||||
let s = selector("$..author", "./benches/example.json");
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
select_and_then_compare(r#"$..author"#, read_json("./benches/example.json"), json!([
|
||||
"Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"
|
||||
]));
|
||||
|
||||
let s = selector("$.store.*", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$.store.*"#, read_json("./benches/example.json"), json!([
|
||||
[
|
||||
{"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},
|
||||
@ -331,35 +227,33 @@ fn example() {
|
||||
{"category" : "fiction", "author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
|
||||
],
|
||||
{"color" : "red","price" : 19.95},
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$.store..price", "./benches/example.json");
|
||||
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
select_and_then_compare(r#"$.store..price"#, read_json("./benches/example.json"), json!([
|
||||
8.95, 12.99, 8.99, 22.99, 19.95
|
||||
]));
|
||||
|
||||
let s = selector("$..book[2]", "./benches/example.json");
|
||||
let ret = json!([{
|
||||
select_and_then_compare(r#"$..book[2]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
"title" : "Moby Dick",
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
}
|
||||
]));
|
||||
|
||||
let s = selector("$..book[-2]", "./benches/example.json");
|
||||
let ret = json!([{
|
||||
select_and_then_compare(r#"$..book[-2]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
"title" : "Moby Dick",
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
}
|
||||
]));
|
||||
|
||||
let s = selector("$..book[0,1]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$..book[0, 1]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "reference",
|
||||
"author" : "Nigel Rees",
|
||||
@ -372,11 +266,9 @@ fn example() {
|
||||
"title" : "Sword of Honour",
|
||||
"price" : 12.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$..book[:2]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$..book[:2]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "reference",
|
||||
"author" : "Nigel Rees",
|
||||
@ -389,11 +281,9 @@ fn example() {
|
||||
"title" : "Sword of Honour",
|
||||
"price" : 12.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$..book[2:]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$..book[2:]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
@ -408,11 +298,9 @@ fn example() {
|
||||
"isbn" : "0-395-19395-8",
|
||||
"price" : 22.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$..book[?(@.isbn)]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$..book[?(@.isbn)]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
@ -427,11 +315,9 @@ fn example() {
|
||||
"isbn" : "0-395-19395-8",
|
||||
"price" : 22.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
select_and_then_compare(r#"$.store.book[?(@.price < 10)]"#, read_json("./benches/example.json"), json!([
|
||||
{
|
||||
"category" : "reference",
|
||||
"author" : "Nigel Rees",
|
||||
@ -445,28 +331,21 @@ fn example() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, s.select_as_value().unwrap());
|
||||
]));
|
||||
|
||||
let s = selector("$..*", "./benches/example.json");
|
||||
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
|
||||
assert_eq!(json, s.select_as_value().unwrap());
|
||||
select_and_then_compare(r#"$..*"#, read_json("./benches/example.json"),
|
||||
read_json("./benches/giveme_every_thing_result.json"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filer_same_obj() {
|
||||
setup();
|
||||
|
||||
let mut s = Selector::new();
|
||||
let _ = s.path("$..[?(@.a == 1)]");
|
||||
let _ = s.value_from_str(r#"
|
||||
{
|
||||
select_and_then_compare(r#"$..[?(@.a == 1)]"#, json!({
|
||||
"a": 1,
|
||||
"b" : {"a": 1},
|
||||
"c" : {"a": 1}
|
||||
}
|
||||
"#);
|
||||
assert_eq!(s.select_as_value().unwrap(), json!([
|
||||
}), json!([
|
||||
{"a": 1},
|
||||
{"a": 1}
|
||||
]));
|
||||
|
47
tests/lib.rs
47
tests/lib.rs
@ -1,31 +1,19 @@
|
||||
extern crate env_logger;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate log;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
fn read_json(path: &str) -> Value {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
serde_json::from_str(contents.as_str()).unwrap()
|
||||
}
|
||||
use common::{compare_result, read_contents, read_json, setup};
|
||||
|
||||
fn read_contents(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
fn compile() {
|
||||
setup();
|
||||
|
||||
let mut template = jsonpath::compile("$..friends[2]");
|
||||
let json_obj = read_json("./benches/data_obj.json");
|
||||
let json = template(&json_obj).unwrap();
|
||||
@ -33,7 +21,7 @@ fn compile() {
|
||||
{"id": 2,"name": "Gray Berry"},
|
||||
{"id": 2,"name": "Gray Berry"}
|
||||
]);
|
||||
assert_eq!(json, ret);
|
||||
compare_result(json, ret);
|
||||
|
||||
let json_obj = read_json("./benches/data_array.json");
|
||||
let json = template(&json_obj).unwrap();
|
||||
@ -41,11 +29,13 @@ fn compile() {
|
||||
{"id": 2,"name": "Gray Berry"},
|
||||
{"id": 2,"name": "Rosetta Erickson"}
|
||||
]);
|
||||
assert_eq!(json, ret);
|
||||
compare_result(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector() {
|
||||
setup();
|
||||
|
||||
let json_obj = read_json("./benches/data_obj.json");
|
||||
let mut reader = jsonpath::selector(&json_obj);
|
||||
let json = reader("$..friends[2]").unwrap();
|
||||
@ -53,27 +43,26 @@ fn selector() {
|
||||
{"id": 2,"name": "Gray Berry"},
|
||||
{"id": 2,"name": "Gray Berry"}
|
||||
]);
|
||||
assert_eq!(json, ret);
|
||||
compare_result(json, ret);
|
||||
|
||||
let json = reader("$..friends[0]").unwrap();
|
||||
let ret = json!([
|
||||
{"id": 0},
|
||||
{"id": 0,"name": "Millicent Norman"}
|
||||
]);
|
||||
assert_eq!(json, ret);
|
||||
compare_result(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_as() {
|
||||
let json_obj = read_json("./benches/data_obj.json");
|
||||
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct Friend {
|
||||
id: u8,
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
let json_obj = read_json("./benches/data_obj.json");
|
||||
let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
|
||||
let json = selector("$..friends[2]").unwrap();
|
||||
|
||||
let ret = vec!(
|
||||
@ -101,7 +90,7 @@ fn select() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(json, ret);
|
||||
compare_result(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -121,14 +110,14 @@ fn select_str() {
|
||||
|
||||
#[test]
|
||||
fn test_to_struct() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
phones: Vec<String>,
|
||||
}
|
||||
|
||||
let ret: Person = jsonpath::select_as(r#"
|
||||
let ret: Vec<Person> = jsonpath::select_as(r#"
|
||||
{
|
||||
"person":
|
||||
{
|
||||
@ -148,5 +137,5 @@ fn test_to_struct() {
|
||||
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
|
||||
};
|
||||
|
||||
assert_eq!(person, ret);
|
||||
assert_eq!(vec![person], ret);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
//extern crate indexmap;
|
||||
//extern crate jsonpath_lib;
|
||||
//#[macro_use]
|
||||
//extern crate serde_json;
|
||||
//
|
||||
//use std::io::Read;
|
||||
//
|
||||
//use serde_json::Value;
|
||||
//
|
||||
//use jsonpath_lib::filter::value_filter::JsonValueFilter;
|
||||
//use jsonpath_lib::parser::parser::Parser;
|
||||
//use jsonpath_lib::ref_value::model::RefValue;
|
||||
//
|
||||
//fn setup() {
|
||||
// let _ = env_logger::try_init();
|
||||
//}
|
||||
//
|
||||
//fn do_filter(path: &str, file: &str) -> JsonValueFilter {
|
||||
// let string = read_json(file);
|
||||
// let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
|
||||
// let mut parser = Parser::new(path);
|
||||
// parser.parse(&mut jf).unwrap();
|
||||
// jf
|
||||
//}
|
||||
//
|
||||
//fn read_json(path: &str) -> String {
|
||||
// let mut f = std::fs::File::open(path).unwrap();
|
||||
// let mut contents = String::new();
|
||||
// f.read_to_string(&mut contents).unwrap();
|
||||
// contents
|
||||
//}
|
312
tests/parser.rs
312
tests/parser.rs
@ -1,312 +0,0 @@
|
||||
extern crate env_logger;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
|
||||
use std::result;
|
||||
use jsonpath::parser::parser::{Parser, ParseToken, NodeVisitor, FilterToken};
|
||||
|
||||
struct NodeVisitorTestImpl<'a> {
|
||||
input: &'a str,
|
||||
stack: Vec<ParseToken>,
|
||||
}
|
||||
|
||||
impl<'a> NodeVisitorTestImpl<'a> {
|
||||
fn new(input: &'a str) -> Self {
|
||||
NodeVisitorTestImpl { input, stack: Vec::new() }
|
||||
}
|
||||
|
||||
fn visit(&mut self) -> result::Result<Vec<ParseToken>, String> {
|
||||
let mut parser = Parser::new(self.input);
|
||||
parser.parse(self)?;
|
||||
Ok(self.stack.split_off(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> {
|
||||
fn visit_token(&mut self, token: ParseToken) {
|
||||
self.stack.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup() {
|
||||
let _ = env_logger::try_init();
|
||||
}
|
||||
|
||||
fn run(input: &str) -> result::Result<Vec<ParseToken>, String> {
|
||||
let mut interpreter = NodeVisitorTestImpl::new(input);
|
||||
interpreter.visit()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_path() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$.aa"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("aa".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.00.a"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("00".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("a".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.00.韓창.seok"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("00".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("韓창".to_owned()),
|
||||
ParseToken::In,
|
||||
ParseToken::Key("seok".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.*"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::All
|
||||
]));
|
||||
|
||||
assert_eq!(run("$..*"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Leaves,
|
||||
ParseToken::All
|
||||
]));
|
||||
|
||||
assert_eq!(run("$..[0]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Leaves,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(0.0),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$.") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$..") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$. a") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_array_sytax() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$.book[?(@.isbn)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("book".to_string()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Relative,
|
||||
ParseToken::In,
|
||||
ParseToken::Key("isbn".to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
//
|
||||
// Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만
|
||||
//
|
||||
assert_eq!(run("$.[*]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[*]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[*].가"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::In, ParseToken::Key("가".to_owned())
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[0][1]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(0_f64),
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1_f64),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[1,2]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Union(vec![1, 2]),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[10:]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Range(Some(10), 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::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::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?(1>2)]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$.a[?($.b>3)]"), Ok(vec![
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?($.c>@.d && 1==2)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
|
||||
ParseToken::Filter(FilterToken::And),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?($.c>@.d&&(1==2||3>=4))]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Greater),
|
||||
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
|
||||
ParseToken::Number(3_f64), ParseToken::Number(4_f64), ParseToken::Filter(FilterToken::GreaterOrEqual),
|
||||
ParseToken::Filter(FilterToken::Or),
|
||||
ParseToken::Filter(FilterToken::And),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[?(@.a<@.b)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()),
|
||||
ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned()),
|
||||
ParseToken::Filter(FilterToken::Little),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$[*][*][*]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::All,
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
assert_eq!(run("$['a']['bb']"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key("a".to_string()),
|
||||
ParseToken::ArrayEof,
|
||||
ParseToken::Array,
|
||||
ParseToken::Key("bb".to_string()),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$[") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[a]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?($.a)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(@.a > @.b]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(@.a < @.b&&(@.c < @.d)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_array_float() {
|
||||
setup();
|
||||
|
||||
assert_eq!(run("$[?(1.1<2.1)]"), Ok(vec![
|
||||
ParseToken::Absolute,
|
||||
ParseToken::Array,
|
||||
ParseToken::Number(1.1), ParseToken::Number(2.1), ParseToken::Filter(FilterToken::Little),
|
||||
ParseToken::ArrayEof
|
||||
]));
|
||||
|
||||
match run("$[1.1]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<.2)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.a)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
199
tests/readme.rs
199
tests/readme.rs
@ -3,14 +3,134 @@ extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use serde::Deserialize;
|
||||
|
||||
use jsonpath::Selector;
|
||||
|
||||
#[test]
|
||||
fn readme() {
|
||||
let json_obj = json!({
|
||||
"store": {
|
||||
"book": [
|
||||
{
|
||||
"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": "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
|
||||
}
|
||||
],
|
||||
"bicycle": {
|
||||
"color": "red",
|
||||
"price": 19.95
|
||||
}
|
||||
},
|
||||
"expensive": 10
|
||||
});
|
||||
|
||||
let mut selector = jsonpath::selector(&json_obj);
|
||||
|
||||
assert_eq!(selector("$.store.book[*].author").unwrap(),
|
||||
vec![
|
||||
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..author").unwrap(),
|
||||
vec![
|
||||
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$.store.*").unwrap(),
|
||||
vec![
|
||||
&json!([
|
||||
{ "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": "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 }
|
||||
]),
|
||||
&json!({ "color": "red", "price": 19.95 })
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$.store..price").unwrap(),
|
||||
vec![
|
||||
8.95, 12.99, 8.99, 22.99, 19.95
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[2]").unwrap(),
|
||||
vec![
|
||||
&json!({
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
"title" : "Moby Dick",
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[-2]").unwrap(),
|
||||
vec![
|
||||
&json!({
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
"title" : "Moby Dick",
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[0,1]").unwrap(),
|
||||
vec![
|
||||
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[:2]").unwrap(),
|
||||
vec![
|
||||
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[:2]").unwrap(),
|
||||
vec![
|
||||
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$..book[?(@.isbn)]").unwrap(),
|
||||
vec![
|
||||
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}),
|
||||
&json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99})
|
||||
]);
|
||||
|
||||
assert_eq!(selector("$.store.book[?(@.price < 10)]").unwrap(),
|
||||
vec![
|
||||
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
|
||||
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99})
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn readme_selector() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct Friend {
|
||||
name: String,
|
||||
age: Option<u8>,
|
||||
@ -32,42 +152,16 @@ fn readme_selector() {
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age >= 30)]").unwrap()
|
||||
// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap()
|
||||
// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap()
|
||||
.value(&json_obj /*serde_json::value::Value*/).unwrap()
|
||||
.select_as_value().unwrap();
|
||||
.value(&json_obj)
|
||||
.select().unwrap();
|
||||
|
||||
assert_eq!(json!([{"name": "친구3", "age": 30}]), result);
|
||||
assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result);
|
||||
|
||||
let result = selector.select_as_str().unwrap();
|
||||
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
|
||||
|
||||
let result = selector.select_as::<Vec<Friend>>().unwrap();
|
||||
let result = selector.select_as::<Friend>().unwrap();
|
||||
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
|
||||
|
||||
let _ = selector.map(|v| {
|
||||
let r = match v {
|
||||
Value::Array(mut vec) => {
|
||||
for v in &mut vec {
|
||||
v.as_object_mut().unwrap().remove("age");
|
||||
}
|
||||
Value::Array(vec)
|
||||
}
|
||||
_ => Value::Null
|
||||
};
|
||||
Some(r)
|
||||
});
|
||||
assert_eq!(json!([{ "name": "친구3"}]), selector.get().unwrap());
|
||||
|
||||
let _ = selector.value(&json_obj).unwrap()
|
||||
.map_as(|mut v: Vec<Friend>| {
|
||||
let mut f = v.pop().unwrap();
|
||||
f.name = "friend3".to_string();
|
||||
f.age = None;
|
||||
Some(vec![f])
|
||||
});
|
||||
assert_eq!(vec![Friend { name: "friend3".to_string(), age: None }],
|
||||
selector.get_as::<Vec<Friend>>().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -86,11 +180,10 @@ fn readme_select() {
|
||||
|
||||
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
|
||||
|
||||
let ret = json!([
|
||||
{"name": "친구3", "age": 30},
|
||||
{"name": "친구1", "age": 20}
|
||||
assert_eq!(json, vec![
|
||||
&json!({"name": "친구3", "age": 30}),
|
||||
&json!({"name": "친구1", "age": 20})
|
||||
]);
|
||||
assert_eq!(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -122,7 +215,7 @@ fn readme_select_as() {
|
||||
phones: Vec<String>,
|
||||
}
|
||||
|
||||
let ret: Person = jsonpath::select_as(r#"
|
||||
let ret: Vec<Person> = jsonpath::select_as(r#"
|
||||
{
|
||||
"person":
|
||||
{
|
||||
@ -142,7 +235,7 @@ fn readme_select_as() {
|
||||
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
|
||||
};
|
||||
|
||||
assert_eq!(person, ret);
|
||||
assert_eq!(ret[0], person);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -163,12 +256,10 @@ fn readme_compile() {
|
||||
|
||||
let json = template(&json_obj).unwrap();
|
||||
|
||||
let ret = json!([
|
||||
{"name": "친구3", "age": 30},
|
||||
{"name": "친구1", "age": 20}
|
||||
assert_eq!(json, vec![
|
||||
&json!({"name": "친구3", "age": 30}),
|
||||
&json!({"name": "친구1", "age": 20})
|
||||
]);
|
||||
|
||||
assert_eq!(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -189,21 +280,17 @@ fn readme_selector_fn() {
|
||||
|
||||
let json = selector("$..friends[0]").unwrap();
|
||||
|
||||
let ret = json!([
|
||||
{"name": "친구3", "age": 30},
|
||||
{"name": "친구1", "age": 20}
|
||||
assert_eq!(json, vec![
|
||||
&json!({"name": "친구3", "age": 30}),
|
||||
&json!({"name": "친구1", "age": 20})
|
||||
]);
|
||||
|
||||
assert_eq!(json, ret);
|
||||
|
||||
let json = selector("$..friends[1]").unwrap();
|
||||
|
||||
let ret = json!([
|
||||
{"name": "친구4"},
|
||||
{"name": "친구2", "age": 20}
|
||||
assert_eq!(json, vec![
|
||||
&json!({"name": "친구4"}),
|
||||
&json!({"name": "친구2", "age": 20})
|
||||
]);
|
||||
|
||||
assert_eq!(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -220,13 +307,13 @@ fn readme_selector_as() {
|
||||
{"name": "친구4"}
|
||||
]});
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct Friend {
|
||||
name: String,
|
||||
age: Option<u8>,
|
||||
}
|
||||
|
||||
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
|
||||
let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
|
||||
|
||||
let json = selector("$..friends[0]").unwrap();
|
||||
|
||||
|
@ -1,209 +0,0 @@
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use jsonpath::Selector;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
phone: String,
|
||||
}
|
||||
|
||||
fn input_str() -> &'static str {
|
||||
r#"[
|
||||
{
|
||||
"name": "이름1",
|
||||
"age": 40,
|
||||
"phone": "+33 12341234"
|
||||
},
|
||||
{
|
||||
"name": "이름2",
|
||||
"age": 42,
|
||||
"phone": "++44 12341234"
|
||||
},
|
||||
{
|
||||
"name": "이름3",
|
||||
"age": 50,
|
||||
"phone": "++55 111111"
|
||||
},
|
||||
{
|
||||
"name": "이름4",
|
||||
"age": 51,
|
||||
"phone": "++55 12341234"
|
||||
}
|
||||
]"#
|
||||
}
|
||||
|
||||
fn input_json() -> Value {
|
||||
serde_json::from_str(input_str()).unwrap()
|
||||
}
|
||||
|
||||
fn input_person() -> Vec<Person> {
|
||||
serde_json::from_str(input_str()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_value_from() {
|
||||
let result = Selector::new()
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from(&input_person()).unwrap()
|
||||
.select_as::<Vec<Person>>().unwrap();
|
||||
assert_eq!(input_person()[1], result[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_value() {
|
||||
let result = Selector::new()
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value((&input_json()).into()).unwrap()
|
||||
.select_as_value().unwrap();
|
||||
assert_eq!(input_json()[1], result[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_value_from_str() {
|
||||
let result = Selector::new()
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.select_as_value().unwrap();
|
||||
assert_eq!(input_json()[1], result[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_select_to() {
|
||||
let mut selector = Selector::new();
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.select_as_value().unwrap();
|
||||
assert_eq!(input_json()[1], result[0]);
|
||||
|
||||
let result = selector.select_as_str().unwrap();
|
||||
let value: Value = serde_json::from_str(&result).unwrap();
|
||||
assert_eq!(input_json()[1], value[0]);
|
||||
|
||||
let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||
assert_eq!(input_person()[1], result[0]);
|
||||
|
||||
let _ = selector.path("$..[?(@.age == 40)]");
|
||||
|
||||
let result = selector.select_as_value().unwrap();
|
||||
assert_eq!(input_json()[0], result[0]);
|
||||
|
||||
let result = selector.select_as_str().unwrap();
|
||||
assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
||||
|
||||
let result = selector.select_as::<Vec<Person>>().unwrap();
|
||||
assert_eq!(input_person()[0], result[0]);
|
||||
}
|
||||
|
||||
fn _remove_name(v: Value) -> Option<Value> {
|
||||
let r = match v {
|
||||
Value::Array(mut vec) => {
|
||||
for v in &mut vec {
|
||||
v.as_object_mut().unwrap().remove("name");
|
||||
}
|
||||
Value::Array(vec)
|
||||
}
|
||||
_ => Value::Null
|
||||
};
|
||||
Some(r)
|
||||
}
|
||||
|
||||
fn _change_phone_number(v: Value) -> Option<Value> {
|
||||
let r = match v {
|
||||
Value::Array(mut vec) => {
|
||||
let mut v = vec.pop().unwrap();
|
||||
v.as_object_mut().unwrap()
|
||||
.insert("phone".to_string(), Value::String("1234".to_string()));
|
||||
v
|
||||
}
|
||||
_ => Value::Null
|
||||
};
|
||||
Some(r)
|
||||
}
|
||||
|
||||
fn _rejuvenate(mut vec: Vec<Person>) -> Option<Vec<Person>> {
|
||||
for p in &mut vec {
|
||||
p.age = p.age - 10;
|
||||
}
|
||||
Some(vec)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_map_basic() {
|
||||
let mut selector = Selector::new();
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.map(_remove_name).unwrap()
|
||||
.get().unwrap();
|
||||
|
||||
assert_eq!(result, json!([
|
||||
{"phone": "++44 12341234", "age": 42},
|
||||
{"phone": "++55 111111", "age": 50},
|
||||
{"phone": "++55 12341234", "age": 51},
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_map() {
|
||||
let mut selector = Selector::new();
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.map(_remove_name).unwrap()
|
||||
.path("$..[?(@.age == 50)]").unwrap()
|
||||
.map(_change_phone_number).unwrap()
|
||||
.get().unwrap();
|
||||
|
||||
assert_eq!(result, json!({
|
||||
"phone": "1234",
|
||||
"age": 50,
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_map_as_basic() {
|
||||
let mut selector = Selector::new();
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.map_as(_rejuvenate).unwrap()
|
||||
.get().unwrap();
|
||||
|
||||
assert_eq!(result, json!([
|
||||
{"name": "이름2", "phone": "++44 12341234", "age": 32},
|
||||
{"name": "이름3", "phone": "++55 111111", "age": 40},
|
||||
{"name": "이름4", "phone": "++55 12341234", "age": 41},
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_map_as() {
|
||||
let mut selector = Selector::new();
|
||||
|
||||
let result = selector
|
||||
.path("$..[?(@.age > 40)]").unwrap()
|
||||
.value_from_str(input_str()).unwrap()
|
||||
.map_as(_rejuvenate).unwrap()
|
||||
.path("$..[?(@.age == 40)]").unwrap()
|
||||
.map(_change_phone_number).unwrap()
|
||||
.get().unwrap();
|
||||
|
||||
assert_eq!(result, json!({
|
||||
"name": "이름3",
|
||||
"phone": "1234",
|
||||
"age": 40,
|
||||
}));
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde_json::Value;
|
||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn de() {
|
||||
let json_str = read_json("./benches/example.json");
|
||||
// RefValue -> Value
|
||||
let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let ref value_wrapper: RefValueWrapper = ref_value.into();
|
||||
let value: Value = value_wrapper.into();
|
||||
|
||||
// Value
|
||||
let json: Value = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
assert_eq!(value, json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ser() {
|
||||
let json_str = read_json("./benches/example.json");
|
||||
let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let ref_value_str = serde_json::to_string(&ref_value).unwrap();
|
||||
|
||||
let json: Value = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let json_str = serde_json::to_string(&json).unwrap();
|
||||
assert_eq!(ref_value_str, json_str);
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
|
||||
use jsonpath::parser::tokenizer::{Tokenizer, Token, TokenError, PreloadedTokenizer};
|
||||
|
||||
fn collect_token(input: &str) -> (Vec<Token>, Option<TokenError>) {
|
||||
let mut tokenizer = Tokenizer::new(input);
|
||||
let mut vec = vec![];
|
||||
loop {
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => vec.push(t),
|
||||
Err(e) => return (vec, Some(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(input: &str, expected: (Vec<Token>, Option<TokenError>)) {
|
||||
let (vec, err) = collect_token(input.clone());
|
||||
assert_eq!((vec, err), expected, "\"{}\"", input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek() {
|
||||
let mut tokenizer = PreloadedTokenizer::new("$.a");
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => assert_eq!(Token::Absolute(0), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(t) => assert_eq!(&Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(t) => assert_eq!(&Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(t) => assert_eq!(Token::Dot(1), t),
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token() {
|
||||
run("$.01.a",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Key(2, "01".to_string()),
|
||||
Token::Dot(4),
|
||||
Token::Key(5, "a".to_string())
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$. []",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Whitespace(2, 2),
|
||||
Token::OpenArray(5),
|
||||
Token::CloseArray(6)
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..ab",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
Token::Key(3, "ab".to_string())
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("$..가 [",
|
||||
(
|
||||
vec![
|
||||
Token::Absolute(0),
|
||||
Token::Dot(1),
|
||||
Token::Dot(2),
|
||||
Token::Key(3, "가".to_string()),
|
||||
Token::Whitespace(6, 0),
|
||||
Token::OpenArray(7),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("[-1, 2 ]",
|
||||
(
|
||||
vec![
|
||||
Token::OpenArray(0),
|
||||
Token::Key(1, "-1".to_string()),
|
||||
Token::Comma(3),
|
||||
Token::Whitespace(4, 0),
|
||||
Token::Key(5, "2".to_string()),
|
||||
Token::Whitespace(6, 0),
|
||||
Token::CloseArray(7),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("[ 1 2 , 3 \"abc\" : -10 ]",
|
||||
(
|
||||
vec![
|
||||
Token::OpenArray(0),
|
||||
Token::Whitespace(1, 0),
|
||||
Token::Key(2, "1".to_string()),
|
||||
Token::Whitespace(3, 0),
|
||||
Token::Key(4, "2".to_string()),
|
||||
Token::Whitespace(5, 0),
|
||||
Token::Comma(6),
|
||||
Token::Whitespace(7, 0),
|
||||
Token::Key(8, "3".to_string()),
|
||||
Token::Whitespace(9, 0),
|
||||
Token::DoubleQuoted(10, "abc".to_string()),
|
||||
Token::Whitespace(15, 0),
|
||||
Token::Split(16),
|
||||
Token::Whitespace(17, 0),
|
||||
Token::Key(18, "-10".to_string()),
|
||||
Token::Whitespace(21, 0),
|
||||
Token::CloseArray(22),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?(@.a가 <41.01)",
|
||||
(
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::At(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "a가".to_string()),
|
||||
Token::Whitespace(8, 0),
|
||||
Token::Little(9),
|
||||
Token::Key(10, "41".to_string()),
|
||||
Token::Dot(12),
|
||||
Token::Key(13, "01".to_string()),
|
||||
Token::CloseParenthesis(15),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?(@.a <4a.01)",
|
||||
(
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::At(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "a".to_string()),
|
||||
Token::Whitespace(5, 0),
|
||||
Token::Little(6),
|
||||
Token::Key(7, "4a".to_string()),
|
||||
Token::Dot(9),
|
||||
Token::Key(10, "01".to_string()),
|
||||
Token::CloseParenthesis(12),
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
|
||||
run("?($.c>@.d)", (
|
||||
vec![
|
||||
Token::Question(0),
|
||||
Token::OpenParenthesis(1),
|
||||
Token::Absolute(2),
|
||||
Token::Dot(3),
|
||||
Token::Key(4, "c".to_string()),
|
||||
Token::Greater(5),
|
||||
Token::At(6),
|
||||
Token::Dot(7),
|
||||
Token::Key(8, "d".to_string()),
|
||||
Token::CloseParenthesis(9)
|
||||
]
|
||||
, Some(TokenError::Eof)
|
||||
));
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-wasm"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
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"]
|
||||
|
182
wasm/src/lib.rs
182
wasm/src/lib.rs
@ -1,4 +1,5 @@
|
||||
extern crate cfg_if;
|
||||
extern crate core;
|
||||
extern crate js_sys;
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde;
|
||||
@ -6,19 +7,12 @@ extern crate serde_json;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::result;
|
||||
use std::result::Result;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use jsonpath::filter::value_filter::JsonValueFilter;
|
||||
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
|
||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||
use jsonpath::{JsonPathError, Parser};
|
||||
use jsonpath::Selector as _Selector;
|
||||
use serde_json::Value;
|
||||
use wasm_bindgen::*;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::console;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "wee_alloc")] {
|
||||
@ -38,16 +32,6 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||
let mut jf = JsonValueFilter::new(json);
|
||||
jf.visit(node);
|
||||
let taken = &jf.clone_value();
|
||||
match JsValue::from_serde(taken.deref()) {
|
||||
Ok(js_value) => js_value,
|
||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
|
||||
where D: for<'a> serde::de::Deserialize<'a>
|
||||
{
|
||||
@ -64,26 +48,27 @@ fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
|
||||
}
|
||||
}
|
||||
|
||||
fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue {
|
||||
let result: result::Result<RefValue, String> = into_serde_json::<RefValue>(js_value);
|
||||
match result {
|
||||
Ok(json) => filter_ref_value(json.into(), node),
|
||||
Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ref_value(js_value: JsValue, node: Node) -> JsValue {
|
||||
into_ref_value(&js_value, node)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn compile(path: &str) -> JsValue {
|
||||
let mut parser = Parser::new(path);
|
||||
let node = parser.compile();
|
||||
|
||||
let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
|
||||
let mut selector = _Selector::new();
|
||||
match &node {
|
||||
Ok(node) => get_ref_value(js_value, node.clone()),
|
||||
Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e))
|
||||
Ok(node) => selector.compiled_path(node.clone()),
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone())))
|
||||
};
|
||||
let json = match into_serde_json(&js_value) {
|
||||
Ok(json) => json,
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
|
||||
};
|
||||
match selector.value(&json).select() {
|
||||
Ok(ret) => match JsValue::from_serde(&ret) {
|
||||
Ok(ret) => ret,
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
|
||||
},
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", e))
|
||||
}
|
||||
}) as Box<Fn(JsValue) -> JsValue>);
|
||||
|
||||
@ -94,16 +79,26 @@ pub fn compile(path: &str) -> JsValue {
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn selector(js_value: JsValue) -> JsValue {
|
||||
let json: RefValueWrapper = match into_serde_json::<RefValue>(&js_value) {
|
||||
Ok(json) => json.into(),
|
||||
Err(e) => return JsValue::from_str(e.as_str())
|
||||
let json: Value = match JsValue::into_serde(&js_value) {
|
||||
Ok(json) => json,
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
|
||||
};
|
||||
|
||||
let cb = Closure::wrap(Box::new(move |path: String| {
|
||||
let mut parser = Parser::new(path.as_str());
|
||||
match parser.compile() {
|
||||
Ok(node) => filter_ref_value(json.clone(), node),
|
||||
Err(e) => return JsValue::from_str(e.as_str())
|
||||
Ok(node) => {
|
||||
let mut selector = _Selector::new();
|
||||
let _ = selector.compiled_path(node);
|
||||
match selector.value(&json).select() {
|
||||
Ok(ret) => match JsValue::from_serde(&ret) {
|
||||
Ok(ret) => ret,
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
|
||||
},
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e)))
|
||||
}
|
||||
}) as Box<Fn(String) -> JsValue>);
|
||||
|
||||
@ -114,105 +109,76 @@ pub fn selector(js_value: JsValue) -> JsValue {
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn select(js_value: JsValue, path: &str) -> JsValue {
|
||||
let mut parser = Parser::new(path);
|
||||
match parser.compile() {
|
||||
Ok(node) => get_ref_value(js_value, node),
|
||||
Err(e) => return JsValue::from_str(e.as_str())
|
||||
let mut selector = _Selector::new();
|
||||
let _ = selector.path(path);
|
||||
|
||||
let json = match into_serde_json(&js_value) {
|
||||
Ok(json) => json,
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
|
||||
};
|
||||
|
||||
match selector.value(&json).select() {
|
||||
Ok(ret) => match JsValue::from_serde(&ret) {
|
||||
Ok(ret) => ret,
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
|
||||
},
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
|
||||
/// lifetime 제약으로 Selector를 사용 할 수 없다.
|
||||
///
|
||||
#[wasm_bindgen]
|
||||
pub struct Selector {
|
||||
selector: _Selector
|
||||
path: Option<String>,
|
||||
value: Option<Value>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Selector {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Selector { selector: _Selector::new() }
|
||||
Selector { path: None, value: None }
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn path(&mut self, path: &str) -> result::Result<(), JsValue> {
|
||||
let _ = self.selector.path(path)?;
|
||||
pub fn path(&mut self, path: &str) -> Result<(), JsValue> {
|
||||
self.path = Some(path.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn value(&mut self, value: JsValue) -> result::Result<(), JsValue> {
|
||||
let ref ref_value = into_serde_json(&value)?;
|
||||
let _ = self.selector.value(ref_value)?;
|
||||
pub fn value(&mut self, value: JsValue) -> Result<(), JsValue> {
|
||||
let json = into_serde_json(&value)
|
||||
.map_err(|e| JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))))?;
|
||||
self.value = Some(json);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch, js_name = selectToStr)]
|
||||
pub fn select_to_str(&mut self) -> result::Result<JsValue, JsValue> {
|
||||
self.select_as_str()
|
||||
#[wasm_bindgen(catch, js_name = select)]
|
||||
pub fn select(&mut self) -> Result<JsValue, JsValue> {
|
||||
let mut selector = _Selector::new();
|
||||
|
||||
if let Some(path) = &self.path {
|
||||
let _ = selector.path(&path).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
|
||||
} else {
|
||||
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath)));
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch, js_name = selectAsStr)]
|
||||
pub fn select_as_str(&mut self) -> result::Result<JsValue, JsValue> {
|
||||
let json_str = self.selector.select_as_str()?;
|
||||
Ok(JsValue::from_str(&json_str))
|
||||
if let Some(value) = &self.value {
|
||||
let _ = selector.value(value);
|
||||
} else {
|
||||
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue)));
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch, js_name = selectTo)]
|
||||
pub fn select_to(&mut self) -> result::Result<JsValue, JsValue> {
|
||||
self.select_as()
|
||||
match selector.select() {
|
||||
Ok(ret) => match JsValue::from_serde(&ret) {
|
||||
Ok(ret) => Ok(ret),
|
||||
Err(e) => Err(JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))))
|
||||
},
|
||||
Err(e) => Err(JsValue::from_str(&format!("{:?}", e)))
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch, js_name = selectAs)]
|
||||
pub fn select_as(&mut self) -> result::Result<JsValue, JsValue> {
|
||||
let ref_value = self.selector.select_as::<RefValue>()
|
||||
.map_err(|e| JsValue::from_str(&e))?;
|
||||
Ok(JsValue::from_serde(&ref_value)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn map(&mut self, func: JsValue) -> result::Result<(), JsValue> {
|
||||
if !func.is_function() {
|
||||
return Err(JsValue::from_str("Not a function argument"));
|
||||
}
|
||||
|
||||
let cb: &js_sys::Function = JsCast::unchecked_ref(func.as_ref());
|
||||
|
||||
self.selector.map(|v| {
|
||||
let str_value = match JsValue::from_serde(&v) {
|
||||
Ok(str_value) => str_value,
|
||||
Err(e) => return {
|
||||
console::error_1(&JsValue::from_str(&e.to_string()));
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match cb.call1(&func, &str_value) {
|
||||
Ok(ret) => {
|
||||
match into_serde_json::<Value>(&ret) {
|
||||
Ok(value) => Some(value),
|
||||
Err(e) => {
|
||||
console::error_1(&JsValue::from_str(&e.to_string()));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
console::error_1(&e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}).map_err(|e| JsValue::from_str(&e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn get(&mut self) -> result::Result<JsValue, JsValue> {
|
||||
let v = self.selector.get().map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
JsValue::from_serde(&v).map_err(|e| JsValue::from_str(&e.to_string()))
|
||||
}
|
||||
}
|
@ -359,7 +359,7 @@ describe('compile test', () => {
|
||||
it('basic', (done) => {
|
||||
let template = jsonpath.compile('$.a');
|
||||
let result = template({'a': 1});
|
||||
if (result === 1) {
|
||||
if (result[0] === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
@ -369,7 +369,7 @@ describe('selector test', () => {
|
||||
it('basic', (done) => {
|
||||
let selector = jsonpath.selector({'a': 1});
|
||||
let result = selector('$.a');
|
||||
if (result === 1) {
|
||||
if (result[0] === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
@ -378,7 +378,7 @@ describe('selector test', () => {
|
||||
describe('select test', () => {
|
||||
it('basic', (done) => {
|
||||
let result = jsonpath.select({'a': 1}, '$.a');
|
||||
if (result === 1) {
|
||||
if (result[0] === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
@ -407,7 +407,7 @@ describe('filter test', () => {
|
||||
"b" : {"a": 1},
|
||||
"c" : {"a": 1}
|
||||
});
|
||||
let result = selector.selectAs();
|
||||
let result = selector.select();
|
||||
if (JSON.stringify(result) === JSON.stringify([ {"a": 1}, {"a": 1} ])) {
|
||||
done();
|
||||
}
|
||||
@ -415,32 +415,12 @@ describe('filter test', () => {
|
||||
});
|
||||
|
||||
describe('Selector test', () => {
|
||||
it('basic selectTo', (done) => {
|
||||
let selector = new jsonpath.Selector();
|
||||
selector.path('$.a');
|
||||
selector.value({'a': 1});
|
||||
let result = selector.selectAs();
|
||||
if (result === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('basic selectToStr', (done) => {
|
||||
let selector = new jsonpath.Selector();
|
||||
selector.path('$.a');
|
||||
selector.value({'a': 1});
|
||||
let result = selector.selectToStr();
|
||||
if (result === '1') {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('select', (done) => {
|
||||
let selector = new jsonpath.Selector();
|
||||
selector.value(jsonObj);
|
||||
for(var i in list) {
|
||||
selector.path(i);
|
||||
if(JSON.stringify(list[i]) !== selector.selectAsStr()) {
|
||||
if(JSON.stringify(list[i]) !== JSON.stringify(selector.select())) {
|
||||
throw `fail: ${i}`;
|
||||
}
|
||||
}
|
||||
@ -468,7 +448,7 @@ describe('README test', () => {
|
||||
|
||||
{
|
||||
selector.path('$..[?(@.age >= 30)]');
|
||||
let jsonObj = selector.selectAs();
|
||||
let jsonObj = selector.select();
|
||||
let resultObj = [{"name": "친구3", "age": 30}];
|
||||
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||
throw 'jsonpath.Selector: $..[?(@.age >= 30)]';
|
||||
@ -477,7 +457,7 @@ describe('README test', () => {
|
||||
|
||||
{
|
||||
selector.path('$..[?(@.age == 20)]');
|
||||
let jsonObj = selector.selectAs();
|
||||
let jsonObj = selector.select();
|
||||
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
|
||||
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||
throw 'jsonpath.Selector: $..[?(@.age >= 20)]';
|
||||
@ -486,35 +466,13 @@ describe('README test', () => {
|
||||
|
||||
{
|
||||
selector.value({"friends": [ {"name": "친구5", "age": 20} ]});
|
||||
let jsonObj = selector.selectAs();
|
||||
let jsonObj = selector.select();
|
||||
let resultObj = [{"name": "친구5", "age": 20}];
|
||||
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||
throw 'jsonpath.Selector: change value';
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
selector.value(jsonObj);
|
||||
selector.map(function(v) {
|
||||
let f1 = v[0];
|
||||
f1.age = 30;
|
||||
return v;
|
||||
})
|
||||
let jsonObj1 = selector.get();
|
||||
|
||||
let resultObj1 = [{"name": "친구1", "age": 30}, {"name": "친구2", "age": 20}];
|
||||
if(JSON.stringify(jsonObj1) !== JSON.stringify(resultObj1)) {
|
||||
throw 'jsonpath.Selector.map';
|
||||
}
|
||||
|
||||
selector.path('$..[?(@.age == 20)]');
|
||||
let jsonObj2 = selector.selectAs();
|
||||
let resultObj2 = [{"name": "친구2", "age": 20}];
|
||||
if(JSON.stringify(jsonObj2) !== JSON.stringify(resultObj2)) {
|
||||
throw 'jsonpath.Selector.map and then select';
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
|
@ -73,8 +73,4 @@ run('jsonpath', iterCount, function() { jp.query(json, path) })
|
||||
.then(function() {
|
||||
return run('jsonpath-wasm- select', iterCount, function() { jpw.select(json, path) });
|
||||
})
|
||||
.finally(function() {
|
||||
if(!jpw.deallocJson(ptr)) {
|
||||
console.error('fail to dealloc');
|
||||
}
|
||||
});
|
||||
.finally(function() {});
|
||||
|
Reference in New Issue
Block a user