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 ad45744..ac639ea 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,12 +1,18 @@ 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 @@ -17,454 +23,6 @@ fn to_f64(n: &Number) -> f64 { } } -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()) - } -} - -fn walk_all_with_num<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) { - walk(vec, tmp, &|v| if v.is_array() { - if let Some(item) = v.get(index as usize) { - Some(vec![item]) - } else { - None - } - } else { - None - }); -} - -fn walk_all_with_str<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { - if is_filter { - walk(vec, tmp, &|v| match v { - Value::Object(map) if map.contains_key(key) => Some(vec![v]), - _ => None, - }); - } else { - walk(vec, tmp, &|v| match v { - Value::Object(map) => match map.get(key) { - Some(v) => Some(vec![v]), - _ => None, - }, - _ => None, - }); - } -} - -fn walk_all<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>) { - walk(vec, tmp, &|v| match v { - Value::Array(vec) => Some(vec.iter().collect()), - Value::Object(map) => { - let mut tmp = Vec::new(); - for (_, v) in map { - tmp.push(v); - } - Some(tmp) - } - _ => None, - }); -} - -fn walk<'a, F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F) - where - F: Fn(&Value) -> Option>, -{ - fn _walk<'a, F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) - where - F: Fn(&Value) -> Option>, - { - if let Some(mut ret) = fun(v) { - tmp.append(&mut ret); - } - - match v { - Value::Array(vec) => { - for v in vec { - _walk(v, tmp, fun); - } - } - Value::Object(map) => { - for (_, v) in map { - _walk(&v, tmp, fun); - } - } - _ => {} - } - } - - for v in vec { - _walk(v, tmp, fun); - } -} - fn abs_index(n: isize, len: usize) -> usize { if n < 0_isize { (n + len as isize).max(0) as usize @@ -503,20 +61,284 @@ impl fmt::Display for JsonPathError { } } +#[derive(Debug, Default)] +struct FilterTerms<'a>(Vec>>); + +impl<'a> FilterTerms<'a> { + fn new_filter_context(&mut self) { + self.0.push(None); + debug!("new_filter_context: {:?}", self.0); + } + + fn is_term_empty(&self) -> bool { + self.0.is_empty() + } + + fn push_term(&mut self, term: Option>) { + self.0.push(term); + } + + #[allow(clippy::option_option)] + fn pop_term(&mut self) -> Option>> { + self.0.pop() + } + + fn filter_json_term, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>( + &mut self, + e: ExprTerm<'a>, + fun: F, + ) { + debug!("filter_json_term: {:?}", e); + + if let ExprTerm::Json(rel, fk, vec) = e { + let mut tmp = Vec::new(); + let mut not_matched = HashSet::new(); + let filter_key = if let Some(FilterKey::String(key)) = fk { + let key_contained = &vec.iter().map(|v| match v { + Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(), + _ => v, + }).collect(); + fun(key_contained, &mut tmp, &mut not_matched) + } else { + fun(&vec, &mut tmp, &mut not_matched) + }; + + if rel.is_some() { + self.0.push(Some(ExprTerm::Json(rel, Some(filter_key), tmp))); + } else { + let filtered: Vec<&Value> = vec.iter().enumerate() + .filter( + |(idx, _)| !not_matched.contains(idx) + ) + .map(|(_, v)| *v) + .collect(); + + self.0.push(Some(ExprTerm::Json(Some(filtered), Some(filter_key), tmp))); + } + } else { + unreachable!("unexpected: ExprTerm: {:?}", e); + } + } + + fn push_json_term, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>( + &mut self, + current: &Option>, + fun: F, + ) { + debug!("push_json_term: {:?}", ¤t); + + if let Some(current) = ¤t { + let mut tmp = Vec::new(); + let mut not_matched = HashSet::new(); + let filter_key = fun(current, &mut tmp, &mut not_matched); + self.0.push(Some(ExprTerm::Json(None, Some(filter_key), tmp))); + } + } + + fn filter, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>( + &mut self, + current: &Option>, + fun: F, + ) { + if let Some(peek) = self.0.pop() { + if let Some(e) = peek { + self.filter_json_term(e, fun); + } else { + self.push_json_term(current, fun); + } + } + } + + fn filter_all_with_str(&mut self, current: &Option>, key: &str) { + self.filter(current, |vec, tmp, _| { + ValueWalker::all_with_str(&vec, tmp, key, true); + FilterKey::All + }); + + debug!("filter_all_with_str : {}, {:?}", key, self.0); + } + + fn filter_next_with_str(&mut self, current: &Option>, key: &str) { + self.filter(current, |vec, tmp, not_matched| { + let mut visited = HashSet::new(); + for (idx, v) in vec.iter().enumerate() { + match v { + Value::Object(map) => { + if map.contains_key(key) { + let ptr = *v as *const Value; + if !visited.contains(&ptr) { + visited.insert(ptr); + tmp.push(v) + } + } else { + not_matched.insert(idx); + } + } + Value::Array(vec) => { + not_matched.insert(idx); + for v in vec { + ValueWalker::walk_dedup(v, tmp, key, &mut visited); + } + } + _ => { + not_matched.insert(idx); + } + } + } + + FilterKey::String(key.to_owned()) + }); + + debug!("filter_next_with_str : {}, {:?}", key, self.0); + } + + fn collect_next_with_num(&mut self, current: &Option>, index: f64) -> Option> { + fn _collect<'a>(tmp: &mut Vec<&'a Value>, vec: &'a [Value], index: f64) { + let index = abs_index(index as isize, vec.len()); + if let Some(v) = vec.get(index) { + tmp.push(v); + } + } + + if let Some(current) = current { + let mut tmp = Vec::new(); + for c in current { + match c { + Value::Object(map) => { + for k in map.keys() { + if let Some(Value::Array(vec)) = map.get(k) { + _collect(&mut tmp, vec, index); + } + } + } + Value::Array(vec) => { + _collect(&mut tmp, vec, index); + } + _ => {} + } + } + + if tmp.is_empty() { + self.0.pop(); + return Some(vec![&Value::Null]); + } else { + return Some(tmp); + } + } + + debug!( + "collect_next_with_num : {:?}, {:?}", + &index, ¤t + ); + + None + } + + fn collect_next_all(&mut self, current: &Option>) -> Option> { + if let Some(current) = current { + let mut tmp = Vec::new(); + for c in current { + match c { + Value::Object(map) => { + for (_, v) in map { + tmp.push(v) + } + } + Value::Array(vec) => { + for v in vec { + tmp.push(v); + } + } + _ => {} + } + } + return Some(tmp); + } + + debug!("collect_next_all : {:?}", ¤t); + + None + } + + fn collect_next_with_str(&mut self, current: &Option>, keys: &[String]) -> Option> { + if let Some(current) = current { + let mut tmp = Vec::new(); + for c in current { + if let Value::Object(map) = c { + for key in keys { + if let Some(v) = map.get(key) { + tmp.push(v) + } + } + } + } + + if tmp.is_empty() { + self.0.pop(); + return Some(vec![&Value::Null]); + } else { + return Some(tmp); + } + } + + debug!( + "collect_next_with_str : {:?}, {:?}", + keys, ¤t + ); + + None + } + + fn collect_all(&mut self, current: &Option>) -> Option> { + if let Some(current) = current { + let mut tmp = Vec::new(); + ValueWalker::all(¤t, &mut tmp); + return Some(tmp); + } + debug!("collect_all: {:?}", ¤t); + + None + } + + fn collect_all_with_str(&mut self, current: &Option>, key: &str) -> Option> { + if let Some(current) = current { + let mut tmp = Vec::new(); + ValueWalker::all_with_str(¤t, &mut tmp, key, false); + return Some(tmp); + } + + debug!("collect_all_with_str: {}, {:?}", key, ¤t); + + None + } + + fn collect_all_with_num(&mut self, current: &Option>, index: f64) -> Option> { + if let Some(current) = current { + let mut tmp = Vec::new(); + ValueWalker::all_with_num(¤t, &mut tmp, index); + return Some(tmp); + } + + debug!("collect_all_with_num: {}, {:?}", index, ¤t); + + None + } +} + #[derive(Debug, Default)] pub struct Selector<'a, 'b> { node: Option, node_ref: Option<&'b Node>, value: Option<&'a Value>, tokens: Vec, - terms: Vec>>, current: Option>, selectors: Vec>, + selector_filter: FilterTerms<'a>, } impl<'a, 'b> Selector<'a, 'b> { pub fn new() -> Self { - Selector::default() + Self::default() } pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { @@ -610,251 +432,6 @@ impl<'a, 'b> Selector<'a, 'b> { } } - fn new_filter_context(&mut self) { - self.terms.push(None); - debug!("new_filter_context: {:?}", self.terms); - } - - fn in_filter, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>(&mut self, fun: F) { - fn get_parent<'a>(prev: Option>, current_value: &[&'a Value], not_matched: HashSet) -> Option> { - if prev.is_some() { - return prev; - } - - let filtered: Vec<&Value> = current_value.iter().enumerate().filter(|(idx, _)| !not_matched.contains(idx)) - .map(|(_, v)| *v) - .collect(); - - Some(filtered) - } - - - if let Some(peek) = self.terms.pop() { - match peek { - Some(v) => { - debug!("in_filter 1.: {:?}", v); - - match v { - ExprTerm::Json(rel, fk, vec) => { - let mut tmp = Vec::new(); - let mut not_matched = HashSet::new(); - let filter_key = if let Some(FilterKey::String(key)) = fk { - let key_contained = &vec.iter().map(|v| match v { - Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(), - _ => v, - }).collect(); - fun(key_contained, &mut tmp, &mut not_matched) - } else { - fun(&vec, &mut tmp, &mut not_matched) - }; - - let parent = get_parent(rel, &vec, not_matched); - self.terms.push(Some(ExprTerm::Json(parent, Some(filter_key), tmp))); - } - _ => unreachable!(), - }; - } - _ => { - debug!("in_filter 2.: {:?}", &self.current); - - if let Some(current) = &self.current { - let mut tmp = Vec::new(); - let mut not_matched = HashSet::new(); - let filter_key = fun(current, &mut tmp, &mut not_matched); - self.terms.push(Some(ExprTerm::Json(None, Some(filter_key), tmp))); - } - } - } - } - } - - fn all_in_filter_with_str(&mut self, key: &str) { - self.in_filter(|vec, tmp, _| { - walk_all_with_str(&vec, tmp, key, true); - FilterKey::All - }); - - debug!("all_in_filter_with_str : {}, {:?}", key, self.terms); - } - - fn next_in_filter_with_str(&mut self, key: &str) { - fn _collect<'a>( - v: &'a Value, - tmp: &mut Vec<&'a Value>, - key: &str, - visited: &mut HashSet<*const Value>, - not_matched: &mut HashSet, - ) { - match v { - Value::Object(map) => { - if map.contains_key(key) { - let ptr = v as *const Value; - if !visited.contains(&ptr) { - visited.insert(ptr); - tmp.push(v) - } - } - } - Value::Array(vec) => { - for v in vec { - _collect(v, tmp, key, visited, not_matched); - } - } - _ => {} - } - } - - self.in_filter(|vec, tmp, not_matched| { - let mut visited = HashSet::new(); - for (idx, v) in vec.iter().enumerate() { - match v { - Value::Object(map) => { - if map.contains_key(key) { - let ptr = *v as *const Value; - if !visited.contains(&ptr) { - visited.insert(ptr); - tmp.push(v) - } - } else { - not_matched.insert(idx); - } - } - Value::Array(vec) => { - not_matched.insert(idx); - for v in vec { - _collect(v, tmp, key, &mut visited, not_matched); - } - } - _ => { - not_matched.insert(idx); - } - } - } - - FilterKey::String(key.to_owned()) - }); - - debug!("next_in_filter_with_str : {}, {:?}", key, self.terms); - } - - fn next_from_current_with_num(&mut self, index: f64) { - fn _collect<'a>(tmp: &mut Vec<&'a Value>, vec: &'a [Value], index: f64) { - let index = abs_index(index as isize, vec.len()); - if let Some(v) = vec.get(index) { - tmp.push(v); - } - } - - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - for c in current { - match c { - Value::Object(map) => { - for k in map.keys() { - if let Some(Value::Array(vec)) = map.get(k) { - _collect(&mut tmp, vec, index); - } - } - } - Value::Array(vec) => { - _collect(&mut tmp, vec, index); - } - _ => {} - } - } - - if tmp.is_empty() { - self.terms.pop(); - self.current = Some(vec![&Value::Null]); - } else { - self.current = Some(tmp); - } - } - - debug!( - "next_from_current_with_num : {:?}, {:?}", - &index, self.current - ); - } - - fn next_all_from_current(&mut self) { - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - for c in current { - match c { - Value::Object(map) => { - for (_, v) in map { - tmp.push(v) - } - } - Value::Array(vec) => { - for v in vec { - tmp.push(v); - } - } - _ => {} - } - } - self.current = Some(tmp); - } - - debug!("next_all_from_current : {:?}", self.current); - } - - fn next_from_current_with_str(&mut self, keys: &[String]) { - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - for c in current { - if let Value::Object(map) = c { - for key in keys { - if let Some(v) = map.get(key) { - tmp.push(v) - } - } - } - } - - if tmp.is_empty() { - self.current = Some(vec![&Value::Null]); - } else { - self.current = Some(tmp); - } - } - - debug!( - "next_from_current_with_str : {:?}, {:?}", - keys, self.current - ); - } - - fn all_from_current(&mut self) { - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - walk_all(¤t, &mut tmp); - self.current = Some(tmp); - } - debug!("all_from_current: {:?}", self.current); - } - - fn all_from_current_with_str(&mut self, key: &str) { - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - walk_all_with_str(¤t, &mut tmp, key, false); - self.current = Some(tmp); - } - debug!("all_from_current_with_str: {}, {:?}", key, self.current); - } - - fn all_from_current_with_num(&mut self, index: f64) { - if let Some(current) = self.current.take() { - let mut tmp = Vec::new(); - - walk_all_with_num(¤t, &mut tmp, index); - self.current = Some(tmp); - } - debug!("all_from_current_with_num: {}, {:?}", index, self.current); - } - fn compute_absolute_path_filter(&mut self, token: &ParseToken) -> bool { if !self.selectors.is_empty() { match token { @@ -865,9 +442,9 @@ impl<'a, 'b> Selector<'a, 'b> { let term = current.into(); if let Some(s) = self.selectors.last_mut() { - s.terms.push(Some(term)); + s.selector_filter.push_term(Some(term)); } else { - self.terms.push(Some(term)); + self.selector_filter.push_term(Some(term)); } } else { unreachable!() @@ -909,47 +486,47 @@ impl<'a, 'b> Selector<'a, 'b> { let array_token = self.tokens.pop(); if let Some(ParseToken::Leaves) = self.tokens.last() { self.tokens.pop(); - self.all_from_current(); + self.current = self.selector_filter.collect_all(&self.current); } self.tokens.push(array_token.unwrap()); } - self.new_filter_context(); + self.selector_filter.new_filter_context(); } fn visit_array_eof(&mut self) { if self.is_last_before_token_match(ParseToken::Array) { - if let Some(Some(e)) = self.terms.pop() { + if let Some(Some(e)) = self.selector_filter.pop_term() { if let ExprTerm::String(key) = e { - self.next_in_filter_with_str(&key); + self.selector_filter.filter_next_with_str(&self.current, &key); self.tokens.pop(); return; } - self.terms.push(Some(e)); + self.selector_filter.push_term(Some(e)); } } if self.is_last_before_token_match(ParseToken::Leaves) { self.tokens.pop(); self.tokens.pop(); - if let Some(Some(e)) = self.terms.pop() { + if let Some(Some(e)) = self.selector_filter.pop_term() { if let ExprTerm::Number(n) = &e { - self.all_from_current_with_num(to_f64(n)); - self.terms.pop(); + self.current = self.selector_filter.collect_all_with_num(&self.current, to_f64(n)); + self.selector_filter.pop_term(); return; } - self.terms.push(Some(e)); + self.selector_filter.push_term(Some(e)); } } - if let Some(Some(e)) = self.terms.pop() { + if let Some(Some(e)) = self.selector_filter.pop_term() { match e { ExprTerm::Number(n) => { - self.next_from_current_with_num(to_f64(&n)); + self.current = self.selector_filter.collect_next_with_num(&self.current, to_f64(&n)); } ExprTerm::String(key) => { - self.next_from_current_with_str(&[key]); + self.current = self.selector_filter.collect_next_with_str(&self.current, &[key]); } ExprTerm::Json(rel, _, v) => { if v.is_empty() { @@ -986,38 +563,42 @@ impl<'a, 'b> Selector<'a, 'b> { match self.tokens.last() { Some(ParseToken::Leaves) => { self.tokens.pop(); - self.all_from_current(); + self.current = self.selector_filter.collect_all(&self.current); } Some(ParseToken::In) => { self.tokens.pop(); - self.next_all_from_current(); + self.current = self.selector_filter.collect_next_all(&self.current); } _ => { - self.next_all_from_current(); + self.current = self.selector_filter.collect_next_all(&self.current); } } } fn visit_key(&mut self, key: &str) { if let Some(ParseToken::Array) = self.tokens.last() { - self.terms.push(Some(ExprTerm::String(key.to_string()))); + self.selector_filter.push_term(Some(ExprTerm::String(key.to_string()))); return; } if let Some(t) = self.tokens.pop() { - if self.terms.is_empty() { + if self.selector_filter.is_term_empty() { match t { - ParseToken::Leaves => self.all_from_current_with_str(key), - ParseToken::In => self.next_from_current_with_str(&[key.to_string()]), + ParseToken::Leaves => { + self.current = self.selector_filter.collect_all_with_str(&self.current, key) + } + ParseToken::In => { + self.current = self.selector_filter.collect_next_with_str(&self.current, &[key.to_string()]) + } _ => {} } } else { match t { ParseToken::Leaves => { - self.all_in_filter_with_str(key); + self.selector_filter.filter_all_with_str(&self.current, key); } ParseToken::In => { - self.next_in_filter_with_str(key); + self.selector_filter.filter_next_with_str(&self.current, key); } _ => {} } @@ -1026,19 +607,19 @@ impl<'a, 'b> Selector<'a, 'b> { } fn visit_keys(&mut self, keys: &[String]) { - if !self.terms.is_empty() { + if !self.selector_filter.is_term_empty() { unimplemented!("keys in filter"); } if let Some(ParseToken::Array) = self.tokens.pop() { - self.next_from_current_with_str(keys); + self.current = self.selector_filter.collect_next_with_str(&self.current, keys); } else { unreachable!(); } } fn visit_filter(&mut self, ft: &FilterToken) { - let right = match self.terms.pop() { + let right = match self.selector_filter.pop_term() { Some(Some(right)) => right, Some(None) => ExprTerm::Json( None, @@ -1051,7 +632,7 @@ impl<'a, 'b> Selector<'a, 'b> { _ => panic!("empty term right"), }; - let left = match self.terms.pop() { + let left = match self.selector_filter.pop_term() { Some(Some(left)) => left, Some(None) => ExprTerm::Json( None, @@ -1077,12 +658,12 @@ impl<'a, 'b> Selector<'a, 'b> { }; if let Some(e) = ret { - self.terms.push(Some(e)); + self.selector_filter.push_term(Some(e)); } } fn visit_range(&mut self, from: &Option, to: &Option, step: &Option) { - if !self.terms.is_empty() { + if !self.selector_filter.is_term_empty() { unimplemented!("range syntax in filter"); } @@ -1121,7 +702,7 @@ impl<'a, 'b> Selector<'a, 'b> { } fn visit_union(&mut self, indices: &[isize]) { - if !self.terms.is_empty() { + if !self.selector_filter.is_term_empty() { unimplemented!("union syntax in filter"); } @@ -1163,13 +744,12 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> { ParseToken::ArrayEof => self.visit_array_eof(), ParseToken::All => self.visit_all(), ParseToken::Bool(b) => { - self.terms.push(Some(ExprTerm::Bool(*b))); + self.selector_filter.push_term(Some(ExprTerm::Bool(*b))); } ParseToken::Key(key) => self.visit_key(key), ParseToken::Keys(keys) => self.visit_keys(keys), ParseToken::Number(v) => { - self.terms - .push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); + self.selector_filter.push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); } ParseToken::Filter(ref ft) => self.visit_filter(ft), ParseToken::Range(from, to, step) => self.visit_range(from, to, step), @@ -1368,11 +948,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() { @@ -1406,173 +985,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 new file mode 100644 index 0000000..e7b4de0 --- /dev/null +++ b/src/select/value_walker.rs @@ -0,0 +1,99 @@ +use serde_json::Value; +use std::collections::HashSet; + +pub(super) struct ValueWalker; + +impl<'a> ValueWalker { + pub fn all_with_num(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) { + Self::walk(vec, tmp, &|v| if v.is_array() { + if let Some(item) = v.get(index as usize) { + Some(vec![item]) + } else { + None + } + } else { + None + }); + } + + pub fn all_with_str(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, key: &str, is_filter: bool) { + if is_filter { + Self::walk(vec, tmp, &|v| match v { + Value::Object(map) if map.contains_key(key) => Some(vec![v]), + _ => None, + }); + } else { + Self::walk(vec, tmp, &|v| match v { + Value::Object(map) => match map.get(key) { + Some(v) => Some(vec![v]), + _ => None, + }, + _ => None, + }); + } + } + + pub fn all(vec: &[&'a Value], tmp: &mut Vec<&'a Value>) { + Self::walk(vec, tmp, &|v| match v { + Value::Array(vec) => Some(vec.iter().collect()), + Value::Object(map) => { + let mut tmp = Vec::new(); + for (_, v) in map { + tmp.push(v); + } + Some(tmp) + } + _ => None, + }); + } + + fn walk(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option> { + for v in vec { + Self::_walk(v, tmp, fun); + } + } + + fn _walk(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option> { + if let Some(mut ret) = fun(v) { + tmp.append(&mut ret); + } + + match v { + Value::Array(vec) => { + for v in vec { + Self::_walk(v, tmp, fun); + } + } + Value::Object(map) => { + for (_, v) in map { + Self::_walk(&v, tmp, fun); + } + } + _ => {} + } + } + + pub fn walk_dedup(v: &'a Value, + tmp: &mut Vec<&'a Value>, + key: &str, + visited: &mut HashSet<*const Value>, ) { + match v { + Value::Object(map) => { + if map.contains_key(key) { + let ptr = v as *const Value; + if !visited.contains(&ptr) { + visited.insert(ptr); + tmp.push(v) + } + } + } + Value::Array(vec) => { + for v in vec { + Self::walk_dedup(v, tmp, key, visited); + } + } + _ => {} + } + } +} +