pub mod between;
pub mod cast;
pub mod comparison;
pub mod compiled;
pub mod function;
pub mod in_list;
pub mod like;
pub mod logical;
pub mod null_check;
pub mod range;
use std::any::Any;
use std::fmt::Debug;
use rustc_hash::FxHashMap;
use crate::core::{Operator, Result, Row, Schema, Value};
pub use between::BetweenExpr;
pub use cast::{CastExpr, CompoundExpr};
pub use comparison::ComparisonExpr;
pub use compiled::{clear_regex_cache, CompiledFilter, CompiledPattern};
pub use function::{EvalExpr, FunctionArg, FunctionExpr};
pub use in_list::InListExpr;
pub use like::{clear_like_regex_cache, LikeExpr};
pub use logical::{AndExpr, ConstBoolExpr, NotExpr, OrExpr};
pub use null_check::NullCheckExpr;
pub use range::RangeExpr;
pub trait Expression: Send + Sync + Debug {
fn evaluate(&self, row: &Row) -> Result<bool>;
fn evaluate_fast(&self, row: &Row) -> bool;
fn with_aliases(&self, aliases: &FxHashMap<String, String>) -> Box<dyn Expression>;
fn prepare_for_schema(&mut self, schema: &Schema);
fn is_prepared(&self) -> bool;
fn get_column_name(&self) -> Option<&str> {
None
}
fn collect_column_indices(&self, out: &mut Vec<usize>) -> bool {
if let Some(children) = self.get_and_operands() {
return children.iter().all(|c| c.collect_column_indices(out));
}
if let Some(children) = self.get_or_operands() {
return children.iter().all(|c| c.collect_column_indices(out));
}
false }
fn can_use_index(&self) -> bool {
false
}
fn get_comparison_info(&self) -> Option<(&str, Operator, &Value)> {
None
}
fn get_and_operands(&self) -> Option<&[Box<dyn Expression>]> {
None
}
fn get_or_operands(&self) -> Option<&[Box<dyn Expression>]> {
None
}
fn get_like_prefix_info(&self) -> Option<(&str, String, bool)> {
None
}
fn collect_comparisons(&self) -> Vec<(&str, Operator, &Value)> {
if let Some(info) = self.get_comparison_info() {
vec![info]
} else if let Some(children) = self.get_and_operands() {
let mut result = Vec::new();
for child in children {
result.extend(child.collect_comparisons());
}
result
} else {
vec![]
}
}
fn is_conjunctive_simple(&self) -> bool {
false
}
fn clone_box(&self) -> Box<dyn Expression>;
fn is_unknown_due_to_null(&self, _row: &Row) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
panic!("as_any not implemented for this expression type")
}
}
impl Clone for Box<dyn Expression> {
fn clone(&self) -> Self {
self.clone_box()
}
}
pub(crate) fn find_column_index(schema: &Schema, column: &str) -> Option<usize> {
schema
.column_index_map()
.get(&column.to_lowercase())
.copied()
}
pub(crate) fn resolve_alias<'a>(
column: &'a str,
aliases: &'a FxHashMap<String, String>,
) -> &'a str {
aliases.get(column).map(|s| s.as_str()).unwrap_or(column)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{DataType, SchemaBuilder};
fn test_schema() -> Schema {
SchemaBuilder::new("test")
.add_primary_key("id", DataType::Integer)
.add("name", DataType::Text)
.add("age", DataType::Integer)
.add_nullable("email", DataType::Text)
.build()
}
#[test]
fn test_find_column_index() {
let schema = test_schema();
assert_eq!(find_column_index(&schema, "id"), Some(0));
assert_eq!(find_column_index(&schema, "name"), Some(1));
assert_eq!(find_column_index(&schema, "age"), Some(2));
assert_eq!(find_column_index(&schema, "email"), Some(3));
assert_eq!(find_column_index(&schema, "nonexistent"), None);
assert_eq!(find_column_index(&schema, "ID"), Some(0));
assert_eq!(find_column_index(&schema, "NAME"), Some(1));
}
#[test]
fn test_resolve_alias() {
let mut aliases = FxHashMap::default();
aliases.insert("n".to_string(), "name".to_string());
aliases.insert("a".to_string(), "age".to_string());
assert_eq!(resolve_alias("n", &aliases), "name");
assert_eq!(resolve_alias("a", &aliases), "age");
assert_eq!(resolve_alias("id", &aliases), "id"); }
}