#![allow(warnings)]
use std::collections::BTreeSet;
use pest_consume::Parser;
use crate::sql::expression::function::Function;
use crate::sql::expression::operator::comparison::ComparisonOperator;
use crate::sql::expression::parser::{ExpressionParser, Result, Rule};
use crate::sql::expression::todo_field::TodoField;
use crate::sql::expression::value::Value;
use crate::todo::Todo;
mod function;
mod operator;
mod parser;
pub mod todo_field;
mod value;
#[derive(Eq, PartialEq, Debug)]
pub enum Expression {
Identifier(TodoField),
Value(Value),
Negated(Box<Expression>),
Function(Function),
Between {
expr: Box<Expression>,
negated: bool,
low: Box<Expression>,
high: Box<Expression>,
},
InSet {
expr: Box<Expression>,
negated: bool,
set: Value,
},
Is {
negated: bool,
left: Box<Expression>,
right: Value,
},
ComparisonOp {
left: Box<Expression>,
op: ComparisonOperator,
right: Box<Expression>,
},
And {
left: Box<Expression>,
right: Box<Expression>,
},
Or {
left: Box<Expression>,
right: Box<Expression>,
},
Nested(Box<Expression>),
}
impl Expression {
pub fn eval(&self, t: &Todo) -> Value {
match self {
Expression::Identifier(todo_field) => todo_field.get_value(t),
Expression::Nested(expr) => expr.eval(t),
Expression::Value(v) => v.clone(),
Expression::ComparisonOp { left, op, right } => op.apply(&left.eval(t), &right.eval(t)),
Expression::Is {
left,
negated,
right: Value::Null,
} => {
let is_null = left.eval(t).is_null();
let b = if *negated { !is_null } else { is_null };
Value::Boolean(b)
}
Expression::Is {
left,
negated,
right,
} => {
let left = left.eval(t);
let is = match (&left, right) {
(Value::Null, Value::Null) => true,
_ => left == *right,
};
let b = if *negated { !is } else { is };
Value::Boolean(b)
}
Expression::Function(f) => f.apply(),
Expression::And { left, right } => {
let left = left.eval(t);
if left.is_null() {
Value::Null
} else if left.is_true() {
right.eval(t)
} else if left.is_false() {
left
} else {
unreachable!("{:#?} {:#?}", left, right)
}
}
Expression::Or { left, right } => {
let left = left.eval(t);
if left.is_null() {
Value::Null
} else if left.is_true() {
left
} else if left.is_false() {
right.eval(t)
} else {
unreachable!("{:#?} {:#?}", left, right)
}
}
_ => unimplemented!("{:#?}", self),
}
}
pub fn parse(input: &str) -> Result<Expression> {
let nodes = ExpressionParser::parse(Rule::expression, input)?;
let node = nodes.single()?;
let e = ExpressionParser::expression(node)?;
Ok(e)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn evaling_is_expressions() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("null is null").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("true is true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("false is false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("null is not null").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("null is not false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("null is not true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
}
#[test]
fn evaling_expressions() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("date('2020-12-30')").unwrap();
assert_eq!(e.eval(&t), Value::Date(time::date!(2020 - 12 - 30)));
}
#[test]
fn evaling_and_expressions() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("null and true").unwrap();
assert_eq!(e.eval(&t), Value::Null);
let e = Expression::parse("true and null").unwrap();
assert_eq!(e.eval(&t), Value::Null);
let e = Expression::parse("false and null").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("true and ('a' == 'a')").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("true and null and true").unwrap();
assert_eq!(e.eval(&t), Value::Null);
let e = Expression::parse("true and true and true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("true and true and false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("true and true and null").unwrap();
assert_eq!(e.eval(&t), Value::Null);
}
#[test]
fn evaling_or_expressions() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("null or true").unwrap();
assert_eq!(e.eval(&t), Value::Null);
let e = Expression::parse("false or null").unwrap();
assert_eq!(e.eval(&t), Value::Null);
let e = Expression::parse("false or true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("false or false or true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("false or false or true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("false or false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("false or ('a' == 'a')").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
}
#[test]
fn matching_todos_with_expressions() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("priority = 'A'").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("priority = 'B'").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("is_completed = true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("completion_date is null").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("creation_date = date('2020-12-25')").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("creation_date = date('2020-12-31')").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
let e = Expression::parse("threshold_date = date('2020-12-30')").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("is_hidden = false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
}
#[test]
fn matching_todos_with_and_search_clauses() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("is_hidden = false and is_completed = true").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("is_hidden = false and is_completed = false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
}
#[test]
fn matching_todos_with_or_search_clauses() {
let t = Todo::parse("x (A) 2020-12-25 ma vai t:2020-12-30").unwrap();
let e = Expression::parse("is_completed = false or creation_date = date('2020-12-25')")
.unwrap();
assert_eq!(e.eval(&t), Value::Boolean(true));
let e = Expression::parse("is_hidden = true or is_completed = false").unwrap();
assert_eq!(e.eval(&t), Value::Boolean(false));
}
}