pub mod ast;
pub mod evaluator;
pub mod optimizer;
pub mod parser;
pub mod tokenizer;
pub mod validator;
use anyhow::Result;
use serde_json::Value;
pub use ast::{Expression, NullHandling, SortDirection, SortKey};
pub use evaluator::{Collation, CompiledFilter, CompiledSort, ExpressionEvaluator};
pub use optimizer::ExpressionOptimizer;
pub use parser::ExpressionParser;
pub use validator::ExpressionValidator;
pub struct ExpressionEngine {
parser: ExpressionParser,
evaluator: ExpressionEvaluator,
optimizer: ExpressionOptimizer,
validator: ExpressionValidator,
}
impl ExpressionEngine {
pub fn new() -> Self {
Self {
parser: ExpressionParser::new(),
evaluator: ExpressionEvaluator::new(),
optimizer: ExpressionOptimizer::new(),
validator: ExpressionValidator::new(),
}
}
pub fn compile_filter(&mut self, expr: &str) -> Result<CompiledFilter> {
let ast = self.parser.parse_filter(expr)?;
self.validator.validate(&ast)?;
let optimized = self.optimizer.optimize(ast)?;
Ok(CompiledFilter::new(optimized, self.evaluator.clone()))
}
pub fn compile_sort(&mut self, expr: &str) -> Result<CompiledSort> {
let sort_keys = self.parser.parse_sort(expr)?;
for key in &sort_keys {
self.validator.validate(&key.expression)?;
}
Ok(CompiledSort::new(sort_keys))
}
pub fn compile_sort_with_collation(
&mut self,
expr: &str,
collation: Collation,
) -> Result<CompiledSort> {
let sort_keys = self.parser.parse_sort(expr)?;
for key in &sort_keys {
self.validator.validate(&key.expression)?;
}
Ok(CompiledSort::with_collation(sort_keys, collation))
}
pub fn evaluate_filter(&mut self, expr: &str, item: &Value) -> Result<bool> {
let filter = self.compile_filter(expr)?;
filter.evaluate(item)
}
pub fn analyze(&self, expr: &str) -> Result<ExpressionMetadata> {
let ast = self.parser.parse_filter(expr)?;
let analyzer = ExpressionAnalyzer;
Ok(analyzer.analyze(&ast))
}
}
impl Default for ExpressionEngine {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ExpressionMetadata {
pub accessed_fields: Vec<String>,
pub used_functions: Vec<String>,
pub complexity: u32,
pub indexable: bool,
pub hints: Vec<String>,
}
struct ExpressionAnalyzer;
impl ExpressionAnalyzer {
fn analyze(&self, _expr: &Expression) -> ExpressionMetadata {
ExpressionMetadata {
accessed_fields: vec![],
used_functions: vec![],
complexity: 1,
indexable: false,
hints: vec![],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_expression_engine_filter() {
let mut engine = ExpressionEngine::new();
let filter = engine
.compile_filter("priority > 5 && status == 'active'")
.unwrap();
let item1 = json!({"priority": 7, "status": "active"});
let item2 = json!({"priority": 3, "status": "active"});
let item3 = json!({"priority": 7, "status": "inactive"});
assert!(filter.evaluate(&item1).unwrap());
assert!(!filter.evaluate(&item2).unwrap());
assert!(!filter.evaluate(&item3).unwrap());
}
#[test]
fn test_expression_engine_sort() {
let mut engine = ExpressionEngine::new();
let sort = engine.compile_sort("priority DESC, name ASC").unwrap();
let mut items = vec![
json!({"priority": 3, "name": "B"}),
json!({"priority": 5, "name": "A"}),
json!({"priority": 5, "name": "C"}),
];
sort.apply(&mut items).unwrap();
assert_eq!(items[0]["priority"], 5);
assert_eq!(items[0]["name"], "A");
assert_eq!(items[1]["priority"], 5);
assert_eq!(items[1]["name"], "C");
assert_eq!(items[2]["priority"], 3);
}
}