mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-05-04 05:32:14 +00:00
Fix bug: eq, hash. Bump up 0.1.6
This commit is contained in:
parent
b24a8c18a9
commit
8e1a0f84e1
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
|
||||
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-rs"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
description = "JsonPath engine for NodeJs with Rust native implementation."
|
||||
keywords = ["library", "jsonpath", "json"]
|
||||
|
@ -14,9 +14,11 @@ impl TermContext {
|
||||
TermContext::Constants(et) => {
|
||||
match other {
|
||||
TermContext::Constants(oet) => {
|
||||
trace!("const-const");
|
||||
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default)))
|
||||
}
|
||||
TermContext::Json(key, v) => {
|
||||
trace!("const-json");
|
||||
TermContext::Json(None, v.take_with(key, et, cmp_fn, true))
|
||||
}
|
||||
}
|
||||
@ -24,6 +26,7 @@ impl TermContext {
|
||||
TermContext::Json(key, v) => {
|
||||
match other {
|
||||
TermContext::Json(key_other, ov) => {
|
||||
trace!("json-json");
|
||||
|
||||
fn is_json(t: &TermContext) -> bool {
|
||||
match t {
|
||||
@ -32,18 +35,16 @@ impl TermContext {
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = v.filter(key);
|
||||
let mut ov = ov.filter(key_other);
|
||||
let mut c = v.into_term(key);
|
||||
let mut oc = ov.into_term(key_other);
|
||||
|
||||
if is_json(&c) && is_json(&oc) {
|
||||
v.cmp(&mut ov, cmp_fn.into_type())
|
||||
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.take_with(key, et, cmp_fn, false))
|
||||
}
|
||||
}
|
||||
@ -87,26 +88,32 @@ impl TermContext {
|
||||
}
|
||||
|
||||
pub fn eq(&self, other: &TermContext) -> TermContext {
|
||||
trace!("eq");
|
||||
self.cmp(other, CmpEq, false)
|
||||
}
|
||||
|
||||
pub fn ne(&self, other: &TermContext) -> TermContext {
|
||||
trace!("ne");
|
||||
self.cmp(other, CmpNe, true)
|
||||
}
|
||||
|
||||
pub fn gt(&self, other: &TermContext) -> TermContext {
|
||||
trace!("gt");
|
||||
self.cmp(other, CmpGt, false)
|
||||
}
|
||||
|
||||
pub fn ge(&self, other: &TermContext) -> TermContext {
|
||||
trace!("ge");
|
||||
self.cmp(other, CmpGe, false)
|
||||
}
|
||||
|
||||
pub fn lt(&self, other: &TermContext) -> TermContext {
|
||||
trace!("lt");
|
||||
self.cmp(other, CmpLt, false)
|
||||
}
|
||||
|
||||
pub fn le(&self, other: &TermContext) -> TermContext {
|
||||
trace!("le");
|
||||
self.cmp(other, CmpLe, false)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::error::Error;
|
||||
use std::result::Result;
|
||||
use std::ops::Deref;
|
||||
use std::result::Result;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
@ -324,6 +324,8 @@ impl JsonValueFilter {
|
||||
vf.vw.set_leaves(is_leaves);
|
||||
if v.is_null() {
|
||||
vf.vw.replace(v);
|
||||
} else if v.is_array() && v.as_array().unwrap().is_empty() {
|
||||
vf.vw.replace(RefValue::Null.into());
|
||||
} else if vf.vw.is_array() {
|
||||
vf.vw.replace(v);
|
||||
}
|
||||
@ -480,6 +482,9 @@ impl JsonValueFilter {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some(TermContext::Constants(ExprTerm::Bool(false))) => {
|
||||
self.replace_filter_stack(RefValue::Null.into(), false);
|
||||
}
|
||||
Some(TermContext::Json(_, vw)) => {
|
||||
self.replace_filter_stack(vw.get_val().clone(), vw.is_leaves());
|
||||
}
|
||||
|
@ -155,6 +155,7 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
fn into_hashset(&self) -> IndexSet<RefValueWrapper> {
|
||||
trace!("into_hashset");
|
||||
let mut hashset = IndexSet::new();
|
||||
match self.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
@ -170,9 +171,10 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
pub fn except(&self, other: &Self) -> Self {
|
||||
trace!("except");
|
||||
let hashset = self.into_hashset();
|
||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||
match &(*other.val) {
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
if !hashset.contains(v) {
|
||||
@ -192,6 +194,7 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -214,6 +217,7 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
pub fn union(&self, other: &Self) -> Self {
|
||||
trace!("union");
|
||||
let mut hashset = self.into_hashset();
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
@ -249,6 +253,7 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -14,37 +14,38 @@ impl<'de> Deserialize<'de> for RefValue {
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(RefValueVisitor {})
|
||||
}
|
||||
}
|
||||
|
||||
struct RefValueVisitor {}
|
||||
struct RefValueVisitor {}
|
||||
|
||||
impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
type Value = RefValue;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("any valid JSON value")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error, {
|
||||
Ok(RefValue::Bool(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Number(v.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Number(v.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
@ -56,35 +57,41 @@ impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
self.visit_string(String::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::String(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Null)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where
|
||||
D: Deserializer<'de>, {
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Null)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>, {
|
||||
@ -99,6 +106,7 @@ impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
Ok(RefValue::Array(vec))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>, {
|
||||
@ -116,4 +124,8 @@ impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
_ => Ok(RefValue::Object(IndexMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(RefValueVisitor {})
|
||||
}
|
||||
}
|
@ -124,11 +124,17 @@ pub enum RefValue {
|
||||
Object(IndexMap<String, RefValueWrapper>),
|
||||
}
|
||||
|
||||
static REF_VALUE_NULL: &'static str = "$jsonpath::ref_value::model::RefValue::Null";
|
||||
|
||||
impl Hash for RefValue {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
RefValue::Null => RefValue::Null.hash(state),
|
||||
RefValue::Bool(b) => b.hash(state),
|
||||
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)
|
||||
@ -138,7 +144,9 @@ impl Hash for RefValue {
|
||||
n.as_u64().unwrap().hash(state);
|
||||
}
|
||||
}
|
||||
RefValue::String(s) => s.hash(state),
|
||||
RefValue::String(s) => {
|
||||
s.hash(state)
|
||||
},
|
||||
RefValue::Object(map) => {
|
||||
for (_, v) in map {
|
||||
v.hash(state);
|
||||
|
@ -1,52 +0,0 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
||||
const MAX_ONE_B: u32 = 0x80;
|
||||
const MAX_TWO_B: u32 = 0x800;
|
||||
const MAX_THREE_B: u32 = 0x10000;
|
||||
|
||||
#[inline]
|
||||
pub fn encode(c: char) -> Encode {
|
||||
let code = c as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
Encode { buf: buf, pos: pos }
|
||||
}
|
||||
|
||||
pub struct Encode {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Encode {
|
||||
pub fn as_str(&self) -> &str {
|
||||
std::str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
@ -154,7 +154,7 @@ fn return_type() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op() {
|
||||
fn op_default() {
|
||||
setup();
|
||||
|
||||
let jf = do_filter("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json");
|
||||
@ -203,6 +203,81 @@ fn op() {
|
||||
assert_eq!(friends, jf.into_value());
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
#[test]
|
||||
fn example() {
|
||||
setup();
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-wasm"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
||||
keywords = ["library", "jsonpath", "json", "webassembly"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user