mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-06-20 19:36:37 +00:00
cmp, expr_term 분리
This commit is contained in:
335
src/select/cmp.rs
Normal file
335
src/select/cmp.rs
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
use array_tool::vec::{Intersect, Union};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
pub(super) trait Cmp {
|
||||||
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool;
|
||||||
|
|
||||||
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool;
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool;
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value>;
|
||||||
|
|
||||||
|
fn default(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpEq;
|
||||||
|
|
||||||
|
impl Cmp for CmpEq {
|
||||||
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
v1 == v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
|
(v1 - v2).abs() == 0_f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
|
v1 == v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
v1.to_vec().intersect(v2.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpNe;
|
||||||
|
|
||||||
|
impl Cmp for CmpNe {
|
||||||
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
v1 != v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
||||||
|
(v1 - v2).abs() != 0_f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
|
v1 != v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
v1.to_vec().intersect_if(v2.to_vec(), |a, b| a != b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpGt;
|
||||||
|
|
||||||
|
impl Cmp 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: &str, v2: &str) -> bool {
|
||||||
|
v1 > v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpGe;
|
||||||
|
|
||||||
|
impl Cmp 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: &str, v2: &str) -> bool {
|
||||||
|
v1 >= v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpLt;
|
||||||
|
|
||||||
|
impl Cmp 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: &str, v2: &str) -> bool {
|
||||||
|
v1 < v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpLe;
|
||||||
|
|
||||||
|
impl Cmp 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: &str, v2: &str) -> bool {
|
||||||
|
v1 <= v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpAnd;
|
||||||
|
|
||||||
|
impl Cmp for CmpAnd {
|
||||||
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
v1 && v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
|
!v1.is_empty() && !v2.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
v1.to_vec().intersect(v2.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CmpOr;
|
||||||
|
|
||||||
|
impl Cmp for CmpOr {
|
||||||
|
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
||||||
|
v1 || v2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
||||||
|
!v1.is_empty() || !v2.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
||||||
|
v1.to_vec().union(v2.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod cmp_inner_tests {
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use select::cmp::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_eq() {
|
||||||
|
let cmp_fn = CmpEq;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_ne() {
|
||||||
|
let cmp_fn = CmpNe;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "1"), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_gt() {
|
||||||
|
let cmp_fn = CmpGt;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("b", "a"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_ge() {
|
||||||
|
let cmp_fn = CmpGe;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("ab", "a"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_lt() {
|
||||||
|
let cmp_fn = CmpLt;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_le() {
|
||||||
|
let cmp_fn = CmpLe;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, false), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("abd", "abc"), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_and() {
|
||||||
|
let cmp_fn = CmpAnd;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, true), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_or() {
|
||||||
|
let cmp_fn = CmpOr;
|
||||||
|
assert_eq!(cmp_fn.default(), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
||||||
|
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
|
||||||
|
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_json() {
|
||||||
|
let v1 = Value::Bool(true);
|
||||||
|
let v2 = Value::String("1".to_string());
|
||||||
|
let left = [&v1, &v2];
|
||||||
|
let right = [&v1, &v2];
|
||||||
|
let empty: Vec<&Value> = Vec::new();
|
||||||
|
|
||||||
|
assert_eq!(CmpEq.cmp_json(&left, &right), left.to_vec());
|
||||||
|
assert_eq!(CmpNe.cmp_json(&left, &right), left.to_vec());
|
||||||
|
assert_eq!(CmpGt.cmp_json(&left, &right), empty);
|
||||||
|
assert_eq!(CmpGe.cmp_json(&left, &right), empty);
|
||||||
|
assert_eq!(CmpLt.cmp_json(&left, &right), empty);
|
||||||
|
assert_eq!(CmpLe.cmp_json(&left, &right), empty);
|
||||||
|
assert_eq!(CmpAnd.cmp_json(&left, &right), left.to_vec());
|
||||||
|
assert_eq!(CmpOr.cmp_json(&left, &right), left.to_vec());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
||||||
|
vec![&Value::Bool(true)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
|
||||||
|
empty
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CmpNe.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
||||||
|
empty
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CmpNe.cmp_json(&[&Value::Bool(false)], &[&Value::Bool(true)]),
|
||||||
|
vec![&Value::Bool(false)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CmpAnd.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
||||||
|
vec![&Value::Bool(true)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CmpOr.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
|
||||||
|
vec![&Value::Bool(true), &Value::Bool(false)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
227
src/select/expr_term.rs
Normal file
227
src/select/expr_term.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
use serde_json::{Number, Value};
|
||||||
|
use select::cmp::*;
|
||||||
|
use select::{FilterKey, to_f64};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub(super) enum ExprTerm<'a> {
|
||||||
|
String(String),
|
||||||
|
Number(Number),
|
||||||
|
Bool(bool),
|
||||||
|
Json(Option<Vec<&'a Value>>, Option<FilterKey>, Vec<&'a Value>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExprTerm<'a> {
|
||||||
|
fn cmp<C1: Cmp, C2: Cmp>(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
cmp_fn: &C1,
|
||||||
|
reverse_cmp_fn: &C2,
|
||||||
|
) -> ExprTerm<'a> {
|
||||||
|
match &self {
|
||||||
|
ExprTerm::String(s1) => match &other {
|
||||||
|
ExprTerm::String(s2) => ExprTerm::Bool(cmp_fn.cmp_string(s1, s2)),
|
||||||
|
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
||||||
|
_ => ExprTerm::Bool(cmp_fn.default()),
|
||||||
|
},
|
||||||
|
ExprTerm::Number(n1) => match &other {
|
||||||
|
ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(to_f64(n1), to_f64(n2))),
|
||||||
|
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
||||||
|
_ => ExprTerm::Bool(cmp_fn.default()),
|
||||||
|
},
|
||||||
|
ExprTerm::Bool(b1) => match &other {
|
||||||
|
ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(*b1, *b2)),
|
||||||
|
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
||||||
|
_ => ExprTerm::Bool(cmp_fn.default()),
|
||||||
|
},
|
||||||
|
ExprTerm::Json(rel, fk1, vec1) => {
|
||||||
|
let ret: Vec<&Value> = match &other {
|
||||||
|
ExprTerm::String(s2) => vec1
|
||||||
|
.iter()
|
||||||
|
.filter(|v1| match v1 {
|
||||||
|
Value::String(s1) => cmp_fn.cmp_string(s1, s2),
|
||||||
|
Value::Object(map1) => {
|
||||||
|
if let Some(FilterKey::String(k)) = fk1 {
|
||||||
|
if let Some(Value::String(s1)) = map1.get(k) {
|
||||||
|
return cmp_fn.cmp_string(s1, s2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_fn.default()
|
||||||
|
}
|
||||||
|
_ => cmp_fn.default(),
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
ExprTerm::Number(n2) => vec1
|
||||||
|
.iter()
|
||||||
|
.filter(|v1| match v1 {
|
||||||
|
Value::Number(n1) => cmp_fn.cmp_f64(to_f64(n1), to_f64(n2)),
|
||||||
|
Value::Object(map1) => {
|
||||||
|
if let Some(FilterKey::String(k)) = fk1 {
|
||||||
|
if let Some(Value::Number(n1)) = map1.get(k) {
|
||||||
|
return cmp_fn.cmp_f64(to_f64(n1), to_f64(n2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_fn.default()
|
||||||
|
}
|
||||||
|
_ => cmp_fn.default(),
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
ExprTerm::Bool(b2) => vec1
|
||||||
|
.iter()
|
||||||
|
.filter(|v1| match v1 {
|
||||||
|
Value::Bool(b1) => cmp_fn.cmp_bool(*b1, *b2),
|
||||||
|
Value::Object(map1) => {
|
||||||
|
if let Some(FilterKey::String(k)) = fk1 {
|
||||||
|
if let Some(Value::Bool(b1)) = map1.get(k) {
|
||||||
|
return cmp_fn.cmp_bool(*b1, *b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_fn.default()
|
||||||
|
}
|
||||||
|
_ => cmp_fn.default(),
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
ExprTerm::Json(parent, _, vec2) => {
|
||||||
|
if let Some(vec1) = rel {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
} else if let Some(vec2) = parent {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
} else {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ret.is_empty() {
|
||||||
|
ExprTerm::Bool(cmp_fn.default())
|
||||||
|
} else if let Some(rel) = rel {
|
||||||
|
if let ExprTerm::Json(_, _, _) = &other {
|
||||||
|
ExprTerm::Json(Some(rel.to_vec()), None, ret)
|
||||||
|
} else {
|
||||||
|
let mut tmp = Vec::new();
|
||||||
|
for rel_value in rel {
|
||||||
|
if let Value::Object(map) = rel_value {
|
||||||
|
for map_value in map.values() {
|
||||||
|
for result_value in &ret {
|
||||||
|
if map_value.eq(*result_value) {
|
||||||
|
tmp.push(*rel_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprTerm::Json(Some(tmp), None, ret)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ExprTerm::Json(None, None, ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("eq - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpEq, &CmpEq);
|
||||||
|
debug!("eq = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ne(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("ne - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpNe, &CmpNe);
|
||||||
|
debug!("ne = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gt(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("gt - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpGt, &CmpLt);
|
||||||
|
debug!("gt = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ge(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("ge - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpGe, &CmpLe);
|
||||||
|
debug!("ge = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lt(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("lt - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpLt, &CmpGt);
|
||||||
|
debug!("lt = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn le(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("le - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpLe, &CmpGe);
|
||||||
|
debug!("le = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("and - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpAnd, &CmpAnd);
|
||||||
|
debug!("and = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
||||||
|
debug!("or - {:?} : {:?}", &self, &other);
|
||||||
|
let _ = ret.take();
|
||||||
|
let tmp = self.cmp(other, &CmpOr, &CmpOr);
|
||||||
|
debug!("or = {:?}", tmp);
|
||||||
|
*ret = Some(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Into<ExprTerm<'a>> for &Vec<&'a Value> {
|
||||||
|
fn into(self) -> ExprTerm<'a> {
|
||||||
|
if self.len() == 1 {
|
||||||
|
match &self[0] {
|
||||||
|
Value::Number(v) => return ExprTerm::Number(v.clone()),
|
||||||
|
Value::String(v) => return ExprTerm::String(v.clone()),
|
||||||
|
Value::Bool(v) => return ExprTerm::Bool(*v),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprTerm::Json(None, None, self.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod expr_term_inner_tests {
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
use select::expr_term::ExprTerm;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_vec_into() {
|
||||||
|
let v = Value::Bool(true);
|
||||||
|
let vec = &vec![&v];
|
||||||
|
let term: ExprTerm = vec.into();
|
||||||
|
assert_eq!(term, ExprTerm::Bool(true));
|
||||||
|
|
||||||
|
let v = Value::String("a".to_string());
|
||||||
|
let vec = &vec![&v];
|
||||||
|
let term: ExprTerm = vec.into();
|
||||||
|
assert_eq!(term, ExprTerm::String("a".to_string()));
|
||||||
|
|
||||||
|
let v = serde_json::from_str("1.0").unwrap();
|
||||||
|
let vec = &vec![&v];
|
||||||
|
let term: ExprTerm = vec.into();
|
||||||
|
assert_eq!(term, ExprTerm::Number(Number::from_f64(1.0).unwrap()));
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
mod value_walker;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use array_tool::vec::{Intersect, Union};
|
|
||||||
use serde_json::{Number, Value};
|
use serde_json::{Number, Value};
|
||||||
use serde_json::map::Entry;
|
use serde_json::map::Entry;
|
||||||
|
|
||||||
use parser::*;
|
use parser::*;
|
||||||
|
|
||||||
|
use self::expr_term::*;
|
||||||
use self::value_walker::ValueWalker;
|
use self::value_walker::ValueWalker;
|
||||||
|
|
||||||
|
mod cmp;
|
||||||
|
mod expr_term;
|
||||||
|
mod value_walker;
|
||||||
|
|
||||||
fn to_f64(n: &Number) -> f64 {
|
fn to_f64(n: &Number) -> f64 {
|
||||||
if n.is_i64() {
|
if n.is_i64() {
|
||||||
n.as_i64().unwrap() as f64
|
n.as_i64().unwrap() as f64
|
||||||
@ -28,379 +31,6 @@ fn abs_index(n: isize, len: usize) -> usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Cmp {
|
|
||||||
fn cmp_bool(&self, v1: bool, v2: bool) -> bool;
|
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: f64, v2: f64) -> bool;
|
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &str, v2: &str) -> bool;
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value>;
|
|
||||||
|
|
||||||
fn default(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpEq;
|
|
||||||
|
|
||||||
impl Cmp for CmpEq {
|
|
||||||
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
|
||||||
v1 == v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
|
||||||
(v1 - v2).abs() == 0_f64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
|
||||||
v1 == v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
v1.to_vec().intersect(v2.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpNe;
|
|
||||||
|
|
||||||
impl Cmp for CmpNe {
|
|
||||||
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
|
||||||
v1 != v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
|
|
||||||
(v1 - v2).abs() != 0_f64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
|
||||||
v1 != v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
v1.to_vec().intersect_if(v2.to_vec(), |a, b| a != b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpGt;
|
|
||||||
|
|
||||||
impl Cmp 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: &str, v2: &str) -> bool {
|
|
||||||
v1 > v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpGe;
|
|
||||||
|
|
||||||
impl Cmp 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: &str, v2: &str) -> bool {
|
|
||||||
v1 >= v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpLt;
|
|
||||||
|
|
||||||
impl Cmp 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: &str, v2: &str) -> bool {
|
|
||||||
v1 < v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpLe;
|
|
||||||
|
|
||||||
impl Cmp 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: &str, v2: &str) -> bool {
|
|
||||||
v1 <= v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, _: &[&'a Value], _: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpAnd;
|
|
||||||
|
|
||||||
impl Cmp for CmpAnd {
|
|
||||||
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
|
||||||
v1 && v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
|
||||||
!v1.is_empty() && !v2.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
v1.to_vec().intersect(v2.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CmpOr;
|
|
||||||
|
|
||||||
impl Cmp for CmpOr {
|
|
||||||
fn cmp_bool(&self, v1: bool, v2: bool) -> bool {
|
|
||||||
v1 || v2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
|
|
||||||
!v1.is_empty() || !v2.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp_json<'a>(&self, v1: &[&'a Value], v2: &[&'a Value]) -> Vec<&'a Value> {
|
|
||||||
v1.to_vec().union(v2.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum ExprTerm<'a> {
|
|
||||||
String(String),
|
|
||||||
Number(Number),
|
|
||||||
Bool(bool),
|
|
||||||
Json(Option<Vec<&'a Value>>, Option<FilterKey>, Vec<&'a Value>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ExprTerm<'a> {
|
|
||||||
fn cmp<C1: Cmp, C2: Cmp>(
|
|
||||||
&self,
|
|
||||||
other: &Self,
|
|
||||||
cmp_fn: &C1,
|
|
||||||
reverse_cmp_fn: &C2,
|
|
||||||
) -> ExprTerm<'a> {
|
|
||||||
match &self {
|
|
||||||
ExprTerm::String(s1) => match &other {
|
|
||||||
ExprTerm::String(s2) => ExprTerm::Bool(cmp_fn.cmp_string(s1, s2)),
|
|
||||||
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
|
||||||
_ => ExprTerm::Bool(cmp_fn.default()),
|
|
||||||
},
|
|
||||||
ExprTerm::Number(n1) => match &other {
|
|
||||||
ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(to_f64(n1), to_f64(n2))),
|
|
||||||
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
|
||||||
_ => ExprTerm::Bool(cmp_fn.default()),
|
|
||||||
},
|
|
||||||
ExprTerm::Bool(b1) => match &other {
|
|
||||||
ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(*b1, *b2)),
|
|
||||||
ExprTerm::Json(_, _, _) => other.cmp(&self, reverse_cmp_fn, cmp_fn),
|
|
||||||
_ => ExprTerm::Bool(cmp_fn.default()),
|
|
||||||
},
|
|
||||||
ExprTerm::Json(rel, fk1, vec1) => {
|
|
||||||
let ret: Vec<&Value> = match &other {
|
|
||||||
ExprTerm::String(s2) => vec1
|
|
||||||
.iter()
|
|
||||||
.filter(|v1| match v1 {
|
|
||||||
Value::String(s1) => cmp_fn.cmp_string(s1, s2),
|
|
||||||
Value::Object(map1) => {
|
|
||||||
if let Some(FilterKey::String(k)) = fk1 {
|
|
||||||
if let Some(Value::String(s1)) = map1.get(k) {
|
|
||||||
return cmp_fn.cmp_string(s1, s2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmp_fn.default()
|
|
||||||
}
|
|
||||||
_ => cmp_fn.default(),
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect(),
|
|
||||||
ExprTerm::Number(n2) => vec1
|
|
||||||
.iter()
|
|
||||||
.filter(|v1| match v1 {
|
|
||||||
Value::Number(n1) => cmp_fn.cmp_f64(to_f64(n1), to_f64(n2)),
|
|
||||||
Value::Object(map1) => {
|
|
||||||
if let Some(FilterKey::String(k)) = fk1 {
|
|
||||||
if let Some(Value::Number(n1)) = map1.get(k) {
|
|
||||||
return cmp_fn.cmp_f64(to_f64(n1), to_f64(n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmp_fn.default()
|
|
||||||
}
|
|
||||||
_ => cmp_fn.default(),
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect(),
|
|
||||||
ExprTerm::Bool(b2) => vec1
|
|
||||||
.iter()
|
|
||||||
.filter(|v1| match v1 {
|
|
||||||
Value::Bool(b1) => cmp_fn.cmp_bool(*b1, *b2),
|
|
||||||
Value::Object(map1) => {
|
|
||||||
if let Some(FilterKey::String(k)) = fk1 {
|
|
||||||
if let Some(Value::Bool(b1)) = map1.get(k) {
|
|
||||||
return cmp_fn.cmp_bool(*b1, *b2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmp_fn.default()
|
|
||||||
}
|
|
||||||
_ => cmp_fn.default(),
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect(),
|
|
||||||
ExprTerm::Json(parent, _, vec2) => {
|
|
||||||
if let Some(vec1) = rel {
|
|
||||||
cmp_fn.cmp_json(vec1, vec2)
|
|
||||||
} else if let Some(vec2) = parent {
|
|
||||||
cmp_fn.cmp_json(vec1, vec2)
|
|
||||||
} else {
|
|
||||||
cmp_fn.cmp_json(vec1, vec2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ret.is_empty() {
|
|
||||||
ExprTerm::Bool(cmp_fn.default())
|
|
||||||
} else if let Some(rel) = rel {
|
|
||||||
if let ExprTerm::Json(_, _, _) = &other {
|
|
||||||
ExprTerm::Json(Some(rel.to_vec()), None, ret)
|
|
||||||
} else {
|
|
||||||
let mut tmp = Vec::new();
|
|
||||||
for rel_value in rel {
|
|
||||||
if let Value::Object(map) = rel_value {
|
|
||||||
for map_value in map.values() {
|
|
||||||
for result_value in &ret {
|
|
||||||
if map_value.eq(*result_value) {
|
|
||||||
tmp.push(*rel_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprTerm::Json(Some(tmp), None, ret)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ExprTerm::Json(None, None, ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eq(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("eq - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpEq, &CmpEq);
|
|
||||||
debug!("eq = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ne(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("ne - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpNe, &CmpNe);
|
|
||||||
debug!("ne = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gt(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("gt - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpGt, &CmpLt);
|
|
||||||
debug!("gt = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ge(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("ge - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpGe, &CmpLe);
|
|
||||||
debug!("ge = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lt(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("lt - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpLt, &CmpGt);
|
|
||||||
debug!("lt = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn le(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("le - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpLe, &CmpGe);
|
|
||||||
debug!("le = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn and(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("and - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpAnd, &CmpAnd);
|
|
||||||
debug!("and = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn or(&self, other: &Self, ret: &mut Option<ExprTerm<'a>>) {
|
|
||||||
debug!("or - {:?} : {:?}", &self, &other);
|
|
||||||
let _ = ret.take();
|
|
||||||
let tmp = self.cmp(other, &CmpOr, &CmpOr);
|
|
||||||
debug!("or = {:?}", tmp);
|
|
||||||
*ret = Some(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Into<ExprTerm<'a>> for &Vec<&'a Value> {
|
|
||||||
fn into(self) -> ExprTerm<'a> {
|
|
||||||
if self.len() == 1 {
|
|
||||||
match &self[0] {
|
|
||||||
Value::Number(v) => return ExprTerm::Number(v.clone()),
|
|
||||||
Value::String(v) => return ExprTerm::String(v.clone()),
|
|
||||||
Value::Bool(v) => return ExprTerm::Bool(*v),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprTerm::Json(None, None, self.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum FilterKey {
|
enum FilterKey {
|
||||||
String(String),
|
String(String),
|
||||||
@ -1295,11 +925,10 @@ impl SelectorMut {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod select_inner_tests {
|
mod select_inner_tests {
|
||||||
use serde_json::{Number, Value};
|
use serde_json::Value;
|
||||||
|
|
||||||
use select::{Cmp, CmpAnd, CmpEq, CmpGe, CmpGt, CmpLe, CmpLt, CmpNe, CmpOr, ExprTerm};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_f64_i64() {
|
fn to_f64_i64() {
|
||||||
@ -1333,173 +962,4 @@ mod select_inner_tests {
|
|||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_eq() {
|
|
||||||
let cmp_fn = CmpEq;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_ne() {
|
|
||||||
let cmp_fn = CmpNe;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "1"), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_gt() {
|
|
||||||
let cmp_fn = CmpGt;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("b", "a"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_ge() {
|
|
||||||
let cmp_fn = CmpGe;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("ab", "a"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_lt() {
|
|
||||||
let cmp_fn = CmpLt;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_le() {
|
|
||||||
let cmp_fn = CmpLe;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, false), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("abd", "abc"), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_and() {
|
|
||||||
let cmp_fn = CmpAnd;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, true), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_or() {
|
|
||||||
let cmp_fn = CmpOr;
|
|
||||||
assert_eq!(cmp_fn.default(), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, false), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(true, true), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_bool(false, false), false);
|
|
||||||
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
|
|
||||||
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cmp_json() {
|
|
||||||
let v1 = Value::Bool(true);
|
|
||||||
let v2 = Value::String("1".to_string());
|
|
||||||
let left = [&v1, &v2];
|
|
||||||
let right = [&v1, &v2];
|
|
||||||
let empty: Vec<&Value> = Vec::new();
|
|
||||||
|
|
||||||
assert_eq!(CmpEq.cmp_json(&left, &right), left.to_vec());
|
|
||||||
assert_eq!(CmpNe.cmp_json(&left, &right), left.to_vec());
|
|
||||||
assert_eq!(CmpGt.cmp_json(&left, &right), empty);
|
|
||||||
assert_eq!(CmpGe.cmp_json(&left, &right), empty);
|
|
||||||
assert_eq!(CmpLt.cmp_json(&left, &right), empty);
|
|
||||||
assert_eq!(CmpLe.cmp_json(&left, &right), empty);
|
|
||||||
assert_eq!(CmpAnd.cmp_json(&left, &right), left.to_vec());
|
|
||||||
assert_eq!(CmpOr.cmp_json(&left, &right), left.to_vec());
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
|
||||||
vec![&Value::Bool(true)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
|
|
||||||
empty
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CmpNe.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
|
||||||
empty
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CmpNe.cmp_json(&[&Value::Bool(false)], &[&Value::Bool(true)]),
|
|
||||||
vec![&Value::Bool(false)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CmpAnd.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
|
|
||||||
vec![&Value::Bool(true)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CmpOr.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
|
|
||||||
vec![&Value::Bool(true), &Value::Bool(false)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn value_vec_into() {
|
|
||||||
let v = Value::Bool(true);
|
|
||||||
let vec = &vec![&v];
|
|
||||||
let term: ExprTerm = vec.into();
|
|
||||||
assert_eq!(term, ExprTerm::Bool(true));
|
|
||||||
|
|
||||||
let v = Value::String("a".to_string());
|
|
||||||
let vec = &vec![&v];
|
|
||||||
let term: ExprTerm = vec.into();
|
|
||||||
assert_eq!(term, ExprTerm::String("a".to_string()));
|
|
||||||
|
|
||||||
let v = serde_json::from_str("1.0").unwrap();
|
|
||||||
let vec = &vec![&v];
|
|
||||||
let term: ExprTerm = vec.into();
|
|
||||||
assert_eq!(term, ExprTerm::Number(Number::from_f64(1.0).unwrap()));
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -78,3 +78,4 @@ impl<'a> ValueWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user