use std::any::Any;
use rustc_hash::FxHashMap;
use super::Expression;
use crate::core::{Result, Row, Schema};
#[derive(Debug, Clone)]
pub struct AndExpr {
expressions: Vec<Box<dyn Expression>>,
is_prepared: bool,
}
impl AndExpr {
pub fn new(expressions: Vec<Box<dyn Expression>>) -> Self {
Self {
expressions,
is_prepared: false,
}
}
pub fn and(left: Box<dyn Expression>, right: Box<dyn Expression>) -> Self {
Self::new(vec![left, right])
}
pub fn push(&mut self, expr: Box<dyn Expression>) {
self.expressions.push(expr);
self.is_prepared = false;
}
pub fn len(&self) -> usize {
self.expressions.len()
}
pub fn is_empty(&self) -> bool {
self.expressions.is_empty()
}
}
impl Expression for AndExpr {
fn evaluate(&self, row: &Row) -> Result<bool> {
for expr in &self.expressions {
if !expr.evaluate(row)? {
return Ok(false); }
}
Ok(true) }
fn evaluate_fast(&self, row: &Row) -> bool {
for expr in &self.expressions {
if !expr.evaluate_fast(row) {
return false; }
}
true }
fn with_aliases(&self, aliases: &FxHashMap<String, String>) -> Box<dyn Expression> {
let aliased_exprs: Vec<Box<dyn Expression>> = self
.expressions
.iter()
.map(|e| e.with_aliases(aliases))
.collect();
Box::new(AndExpr::new(aliased_exprs))
}
fn prepare_for_schema(&mut self, schema: &Schema) {
if self.is_prepared {
return;
}
for expr in &mut self.expressions {
expr.prepare_for_schema(schema);
}
self.is_prepared = true;
}
fn is_prepared(&self) -> bool {
self.is_prepared
}
fn get_and_operands(&self) -> Option<&[Box<dyn Expression>]> {
Some(&self.expressions)
}
fn is_conjunctive_simple(&self) -> bool {
self.expressions.iter().all(|e| e.is_conjunctive_simple())
}
fn clone_box(&self) -> Box<dyn Expression> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug, Clone)]
pub struct OrExpr {
expressions: Vec<Box<dyn Expression>>,
is_prepared: bool,
}
impl OrExpr {
pub fn new(expressions: Vec<Box<dyn Expression>>) -> Self {
Self {
expressions,
is_prepared: false,
}
}
pub fn or(left: Box<dyn Expression>, right: Box<dyn Expression>) -> Self {
Self::new(vec![left, right])
}
pub fn push(&mut self, expr: Box<dyn Expression>) {
self.expressions.push(expr);
self.is_prepared = false;
}
pub fn len(&self) -> usize {
self.expressions.len()
}
pub fn is_empty(&self) -> bool {
self.expressions.is_empty()
}
}
impl Expression for OrExpr {
fn evaluate(&self, row: &Row) -> Result<bool> {
for expr in &self.expressions {
match expr.evaluate(row) {
Ok(true) => return Ok(true), Ok(false) => continue,
Err(_) => continue, }
}
Ok(false) }
fn evaluate_fast(&self, row: &Row) -> bool {
for expr in &self.expressions {
if expr.evaluate_fast(row) {
return true; }
}
false }
fn with_aliases(&self, aliases: &FxHashMap<String, String>) -> Box<dyn Expression> {
let aliased_exprs: Vec<Box<dyn Expression>> = self
.expressions
.iter()
.map(|e| e.with_aliases(aliases))
.collect();
Box::new(OrExpr::new(aliased_exprs))
}
fn prepare_for_schema(&mut self, schema: &Schema) {
if self.is_prepared {
return;
}
for expr in &mut self.expressions {
expr.prepare_for_schema(schema);
}
self.is_prepared = true;
}
fn is_prepared(&self) -> bool {
self.is_prepared
}
fn get_or_operands(&self) -> Option<&[Box<dyn Expression>]> {
Some(&self.expressions)
}
fn clone_box(&self) -> Box<dyn Expression> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug, Clone)]
pub struct NotExpr {
inner: Box<dyn Expression>,
is_prepared: bool,
}
impl NotExpr {
pub fn new(inner: Box<dyn Expression>) -> Self {
Self {
inner,
is_prepared: false,
}
}
pub fn not(expr: Box<dyn Expression>) -> Self {
Self::new(expr)
}
pub fn get_inner(&self) -> Option<&dyn Expression> {
Some(self.inner.as_ref())
}
}
impl Expression for NotExpr {
fn evaluate(&self, row: &Row) -> Result<bool> {
if self.inner.is_unknown_due_to_null(row) {
return Ok(false);
}
Ok(!self.inner.evaluate(row)?)
}
fn evaluate_fast(&self, row: &Row) -> bool {
if self.inner.is_unknown_due_to_null(row) {
return false;
}
!self.inner.evaluate_fast(row)
}
fn with_aliases(&self, aliases: &FxHashMap<String, String>) -> Box<dyn Expression> {
Box::new(NotExpr::new(self.inner.with_aliases(aliases)))
}
fn prepare_for_schema(&mut self, schema: &Schema) {
if self.is_prepared {
return;
}
self.inner.prepare_for_schema(schema);
self.is_prepared = true;
}
fn is_prepared(&self) -> bool {
self.is_prepared
}
fn clone_box(&self) -> Box<dyn Expression> {
Box::new(self.clone())
}
fn is_unknown_due_to_null(&self, row: &Row) -> bool {
self.inner.is_unknown_due_to_null(row)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug, Clone)]
pub struct ConstBoolExpr {
value: bool,
}
impl ConstBoolExpr {
pub fn new(value: bool) -> Self {
Self { value }
}
pub fn true_expr() -> Self {
Self::new(true)
}
pub fn false_expr() -> Self {
Self::new(false)
}
pub fn value(&self) -> bool {
self.value
}
}
impl Expression for ConstBoolExpr {
fn evaluate(&self, _row: &Row) -> Result<bool> {
Ok(self.value)
}
fn evaluate_fast(&self, _row: &Row) -> bool {
self.value
}
fn with_aliases(&self, _aliases: &FxHashMap<String, String>) -> Box<dyn Expression> {
Box::new(self.clone())
}
fn prepare_for_schema(&mut self, _schema: &Schema) {
}
fn is_prepared(&self) -> bool {
true }
fn clone_box(&self) -> Box<dyn Expression> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{DataType, SchemaBuilder, Value};
use crate::storage::expression::ComparisonExpr;
fn test_schema() -> Schema {
SchemaBuilder::new("test")
.add_primary_key("id", DataType::Integer)
.add("name", DataType::Text)
.add("age", DataType::Integer)
.build()
}
fn test_row() -> Row {
Row::from_values(vec![
Value::integer(1),
Value::text("Alice"),
Value::integer(30),
])
}
#[test]
fn test_and_all_true() {
let schema = test_schema();
let row = test_row();
let mut expr = AndExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(1))),
Box::new(ComparisonExpr::eq("name", Value::text("Alice"))),
Box::new(ComparisonExpr::eq("age", Value::integer(30))),
]);
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
assert!(expr.evaluate_fast(&row));
}
#[test]
fn test_and_one_false() {
let schema = test_schema();
let row = test_row();
let mut expr = AndExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(1))),
Box::new(ComparisonExpr::eq("name", Value::text("Bob"))), Box::new(ComparisonExpr::eq("age", Value::integer(30))),
]);
expr.prepare_for_schema(&schema);
assert!(!expr.evaluate(&row).unwrap());
assert!(!expr.evaluate_fast(&row));
}
#[test]
fn test_and_short_circuit() {
let schema = test_schema();
let row = test_row();
let mut expr = AndExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(999))), Box::new(ComparisonExpr::eq("name", Value::text("Alice"))),
]);
expr.prepare_for_schema(&schema);
assert!(!expr.evaluate(&row).unwrap());
}
#[test]
fn test_or_one_true() {
let schema = test_schema();
let row = test_row();
let mut expr = OrExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(999))), Box::new(ComparisonExpr::eq("name", Value::text("Alice"))), ]);
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
assert!(expr.evaluate_fast(&row));
}
#[test]
fn test_or_all_false() {
let schema = test_schema();
let row = test_row();
let mut expr = OrExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(999))),
Box::new(ComparisonExpr::eq("name", Value::text("Bob"))),
]);
expr.prepare_for_schema(&schema);
assert!(!expr.evaluate(&row).unwrap());
assert!(!expr.evaluate_fast(&row));
}
#[test]
fn test_or_short_circuit() {
let schema = test_schema();
let row = test_row();
let mut expr = OrExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(1))), Box::new(ComparisonExpr::eq("name", Value::text("Bob"))),
]);
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
}
#[test]
fn test_not_true() {
let schema = test_schema();
let row = test_row();
let mut expr = NotExpr::new(Box::new(ComparisonExpr::eq("id", Value::integer(999))));
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
assert!(expr.evaluate_fast(&row));
}
#[test]
fn test_not_false() {
let schema = test_schema();
let row = test_row();
let mut expr = NotExpr::new(Box::new(ComparisonExpr::eq("id", Value::integer(1))));
expr.prepare_for_schema(&schema);
assert!(!expr.evaluate(&row).unwrap());
assert!(!expr.evaluate_fast(&row));
}
#[test]
fn test_complex_expression() {
let schema = test_schema();
let row = test_row();
let mut expr = OrExpr::new(vec![
Box::new(AndExpr::new(vec![
Box::new(ComparisonExpr::eq("id", Value::integer(1))),
Box::new(ComparisonExpr::eq("name", Value::text("Alice"))),
])),
Box::new(ComparisonExpr::gt("age", Value::integer(40))),
]);
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
}
#[test]
fn test_nested_not() {
let schema = test_schema();
let row = test_row();
let mut expr = NotExpr::new(Box::new(NotExpr::new(Box::new(ComparisonExpr::eq(
"id",
Value::integer(1),
)))));
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
}
#[test]
fn test_empty_and() {
let row = test_row();
let expr = AndExpr::new(vec![]);
assert!(expr.evaluate(&row).unwrap());
}
#[test]
fn test_empty_or() {
let row = test_row();
let expr = OrExpr::new(vec![]);
assert!(!expr.evaluate(&row).unwrap());
}
#[test]
fn test_and_push() {
let schema = test_schema();
let row = test_row();
let mut expr = AndExpr::new(vec![Box::new(ComparisonExpr::eq("id", Value::integer(1)))]);
expr.push(Box::new(ComparisonExpr::eq("name", Value::text("Alice"))));
expr.prepare_for_schema(&schema);
assert!(expr.evaluate(&row).unwrap());
assert_eq!(expr.len(), 2);
}
#[test]
fn test_with_aliases() {
let schema = test_schema();
let row = test_row();
let mut aliases = FxHashMap::default();
aliases.insert("i".to_string(), "id".to_string());
aliases.insert("n".to_string(), "name".to_string());
let expr = AndExpr::new(vec![
Box::new(ComparisonExpr::eq("i", Value::integer(1))),
Box::new(ComparisonExpr::eq("n", Value::text("Alice"))),
]);
let mut aliased = expr.with_aliases(&aliases);
aliased.prepare_for_schema(&schema);
assert!(aliased.evaluate(&row).unwrap());
}
}