diff --git a/src/select/cmp.rs b/src/select/cmp.rs new file mode 100644 index 0000000..209e672 --- /dev/null +++ b/src/select/cmp.rs @@ -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)] + ); + } +} diff --git a/src/select/expr_term.rs b/src/select/expr_term.rs new file mode 100644 index 0000000..ddbf64e --- /dev/null +++ b/src/select/expr_term.rs @@ -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>, Option, Vec<&'a Value>), +} + +impl<'a> ExprTerm<'a> { + fn 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>) { + 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>) { + 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>) { + 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>) { + 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>) { + 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>) { + 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>) { + 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>) { + debug!("or - {:?} : {:?}", &self, &other); + let _ = ret.take(); + let tmp = self.cmp(other, &CmpOr, &CmpOr); + debug!("or = {:?}", tmp); + *ret = Some(tmp); + } +} + +impl<'a> Into> 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())); + } +} diff --git a/src/select/mod.rs b/src/select/mod.rs index 7cd576a..b1758af 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,15 +1,18 @@ -mod value_walker; - use std::collections::HashSet; use std::fmt; -use array_tool::vec::{Intersect, Union}; use serde_json::{Number, Value}; use serde_json::map::Entry; use parser::*; + +use self::expr_term::*; use self::value_walker::ValueWalker; +mod cmp; +mod expr_term; +mod value_walker; + fn to_f64(n: &Number) -> f64 { if n.is_i64() { 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>, Option, Vec<&'a Value>), -} - -impl<'a> ExprTerm<'a> { - fn 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>) { - 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>) { - 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>) { - 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>) { - 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>) { - 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>) { - 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>) { - 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>) { - debug!("or - {:?} : {:?}", &self, &other); - let _ = ret.take(); - let tmp = self.cmp(other, &CmpOr, &CmpOr); - debug!("or = {:?}", tmp); - *ret = Some(tmp); - } -} - -impl<'a> Into> 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)] enum FilterKey { String(String), @@ -1295,11 +925,10 @@ impl SelectorMut { } } + #[cfg(test)] mod select_inner_tests { - use serde_json::{Number, Value}; - - use select::{Cmp, CmpAnd, CmpEq, CmpGe, CmpGt, CmpLe, CmpLt, CmpNe, CmpOr, ExprTerm}; + use serde_json::Value; #[test] fn to_f64_i64() { @@ -1333,173 +962,4 @@ mod select_inner_tests { 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())); - } -} +} \ No newline at end of file diff --git a/src/select/value_walker.rs b/src/select/value_walker.rs index 34779b6..55f3852 100644 --- a/src/select/value_walker.rs +++ b/src/select/value_walker.rs @@ -78,3 +78,4 @@ impl<'a> ValueWalker { } } } +