use fnv::FnvHashSet;
use crate::Result;
use crate::expr::{Predicate, PredicateOperator, Reference};
use crate::spec::Datum;
pub trait PredicateVisitor {
type T;
fn always_true(&mut self) -> Result<Self::T>;
fn always_false(&mut self) -> Result<Self::T>;
fn and(&mut self, lhs: Self::T, rhs: Self::T) -> Result<Self::T>;
fn or(&mut self, lhs: Self::T, rhs: Self::T) -> Result<Self::T>;
fn not(&mut self, inner: Self::T) -> Result<Self::T>;
fn is_null(&mut self, reference: &Reference, predicate: &Predicate) -> Result<Self::T>;
fn not_null(&mut self, reference: &Reference, predicate: &Predicate) -> Result<Self::T>;
fn is_nan(&mut self, reference: &Reference, predicate: &Predicate) -> Result<Self::T>;
fn not_nan(&mut self, reference: &Reference, predicate: &Predicate) -> Result<Self::T>;
fn less_than(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn less_than_or_eq(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn greater_than(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn greater_than_or_eq(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn eq(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn not_eq(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn starts_with(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn not_starts_with(
&mut self,
reference: &Reference,
literal: &Datum,
predicate: &Predicate,
) -> Result<Self::T>;
fn r#in(
&mut self,
reference: &Reference,
literals: &FnvHashSet<Datum>,
predicate: &Predicate,
) -> Result<Self::T>;
fn not_in(
&mut self,
reference: &Reference,
literals: &FnvHashSet<Datum>,
predicate: &Predicate,
) -> Result<Self::T>;
}
pub(crate) fn visit<V: PredicateVisitor>(visitor: &mut V, predicate: &Predicate) -> Result<V::T> {
match predicate {
Predicate::AlwaysTrue => visitor.always_true(),
Predicate::AlwaysFalse => visitor.always_false(),
Predicate::And(expr) => {
let [left_pred, right_pred] = expr.inputs();
let left_result = visit(visitor, left_pred)?;
let right_result = visit(visitor, right_pred)?;
visitor.and(left_result, right_result)
}
Predicate::Or(expr) => {
let [left_pred, right_pred] = expr.inputs();
let left_result = visit(visitor, left_pred)?;
let right_result = visit(visitor, right_pred)?;
visitor.or(left_result, right_result)
}
Predicate::Not(expr) => {
let [inner_pred] = expr.inputs();
let inner_result = visit(visitor, inner_pred)?;
visitor.not(inner_result)
}
Predicate::Unary(expr) => match expr.op() {
PredicateOperator::IsNull => visitor.is_null(expr.term(), predicate),
PredicateOperator::NotNull => visitor.not_null(expr.term(), predicate),
PredicateOperator::IsNan => visitor.is_nan(expr.term(), predicate),
PredicateOperator::NotNan => visitor.not_nan(expr.term(), predicate),
op => {
panic!("Unexpected op for unary predicate: {}", &op)
}
},
Predicate::Binary(expr) => {
let reference = expr.term();
let literal = expr.literal();
match expr.op() {
PredicateOperator::LessThan => visitor.less_than(reference, literal, predicate),
PredicateOperator::LessThanOrEq => {
visitor.less_than_or_eq(reference, literal, predicate)
}
PredicateOperator::GreaterThan => {
visitor.greater_than(reference, literal, predicate)
}
PredicateOperator::GreaterThanOrEq => {
visitor.greater_than_or_eq(reference, literal, predicate)
}
PredicateOperator::Eq => visitor.eq(reference, literal, predicate),
PredicateOperator::NotEq => visitor.not_eq(reference, literal, predicate),
PredicateOperator::StartsWith => visitor.starts_with(reference, literal, predicate),
PredicateOperator::NotStartsWith => {
visitor.not_starts_with(reference, literal, predicate)
}
op => {
panic!("Unexpected op for binary predicate: {}", &op)
}
}
}
Predicate::Set(expr) => {
let reference = expr.term();
let literals = expr.literals();
match expr.op() {
PredicateOperator::In => visitor.r#in(reference, literals, predicate),
PredicateOperator::NotIn => visitor.not_in(reference, literals, predicate),
op => {
panic!("Unexpected op for set predicate: {}", &op)
}
}
}
}
}
#[cfg(test)]
mod tests {
use std::ops::Not;
use fnv::FnvHashSet;
use crate::expr::visitors::predicate_visitor::{PredicateVisitor, visit};
use crate::expr::{
BinaryExpression, Predicate, PredicateOperator, Reference, SetExpression, UnaryExpression,
};
use crate::spec::Datum;
struct TestEvaluator {}
impl PredicateVisitor for TestEvaluator {
type T = bool;
fn always_true(&mut self) -> crate::Result<Self::T> {
Ok(true)
}
fn always_false(&mut self) -> crate::Result<Self::T> {
Ok(false)
}
fn and(&mut self, lhs: Self::T, rhs: Self::T) -> crate::Result<Self::T> {
Ok(lhs && rhs)
}
fn or(&mut self, lhs: Self::T, rhs: Self::T) -> crate::Result<Self::T> {
Ok(lhs || rhs)
}
fn not(&mut self, inner: Self::T) -> crate::Result<Self::T> {
Ok(!inner)
}
fn is_null(
&mut self,
_reference: &Reference,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn not_null(
&mut self,
_reference: &Reference,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn is_nan(
&mut self,
_reference: &Reference,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn not_nan(
&mut self,
_reference: &Reference,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn less_than(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn less_than_or_eq(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn greater_than(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn greater_than_or_eq(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn eq(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn not_eq(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn starts_with(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn not_starts_with(
&mut self,
_reference: &Reference,
_literal: &Datum,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
fn r#in(
&mut self,
_reference: &Reference,
_literals: &FnvHashSet<Datum>,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(true)
}
fn not_in(
&mut self,
_reference: &Reference,
_literals: &FnvHashSet<Datum>,
_predicate: &Predicate,
) -> crate::Result<bool> {
Ok(false)
}
}
#[test]
fn test_always_true() {
let predicate = Predicate::AlwaysTrue;
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_always_false() {
let predicate = Predicate::AlwaysFalse;
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_logical_and() {
let predicate = Predicate::AlwaysTrue.and(Predicate::AlwaysFalse);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
let predicate = Predicate::AlwaysFalse.and(Predicate::AlwaysFalse);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
let predicate = Predicate::AlwaysTrue.and(Predicate::AlwaysTrue);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_logical_or() {
let predicate = Predicate::AlwaysTrue.or(Predicate::AlwaysFalse);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
let predicate = Predicate::AlwaysFalse.or(Predicate::AlwaysFalse);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
let predicate = Predicate::AlwaysTrue.or(Predicate::AlwaysTrue);
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not() {
let predicate = Predicate::AlwaysFalse.not();
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
let predicate = Predicate::AlwaysTrue.not();
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_is_null() {
let predicate = Predicate::Unary(UnaryExpression::new(
PredicateOperator::IsNull,
Reference::new("c"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not_null() {
let predicate = Predicate::Unary(UnaryExpression::new(
PredicateOperator::NotNull,
Reference::new("a"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_is_nan() {
let predicate = Predicate::Unary(UnaryExpression::new(
PredicateOperator::IsNan,
Reference::new("b"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not_nan() {
let predicate = Predicate::Unary(UnaryExpression::new(
PredicateOperator::NotNan,
Reference::new("b"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_less_than() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::LessThan,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_less_than_or_eq() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::LessThanOrEq,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_greater_than() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::GreaterThan,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_greater_than_or_eq() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::GreaterThanOrEq,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_eq() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::Eq,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not_eq() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::NotEq,
Reference::new("a"),
Datum::int(10),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_starts_with() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::StartsWith,
Reference::new("a"),
Datum::string("test"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not_starts_with() {
let predicate = Predicate::Binary(BinaryExpression::new(
PredicateOperator::NotStartsWith,
Reference::new("a"),
Datum::string("test"),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
#[test]
fn test_in() {
let predicate = Predicate::Set(SetExpression::new(
PredicateOperator::In,
Reference::new("a"),
FnvHashSet::from_iter(vec![Datum::int(1)]),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(result.unwrap());
}
#[test]
fn test_not_in() {
let predicate = Predicate::Set(SetExpression::new(
PredicateOperator::NotIn,
Reference::new("a"),
FnvHashSet::from_iter(vec![Datum::int(1)]),
));
let mut test_evaluator = TestEvaluator {};
let result = visit(&mut test_evaluator, &predicate);
assert!(!result.unwrap());
}
}