wirerust/
filter.rs

1//! Filter module: wraps compiled filters and provides the main execution API.
2//!
3//! This module provides the CompiledFilter type.
4
5use crate::compiler::IrCompiledFilter;
6
7/// A compiled filter, ready for execution.
8pub struct CompiledFilter {
9    ir: IrCompiledFilter,
10}
11
12impl CompiledFilter {
13    /// Create a new compiled filter from an expression, schema, and function registry.
14    pub fn new(
15        expr: crate::expr::FilterExpr,
16        schema: std::sync::Arc<crate::schema::FilterSchema>,
17        functions: std::sync::Arc<crate::functions::FunctionRegistry>,
18    ) -> Self {
19        let ir = crate::compiler::DefaultCompiler::compile(expr, schema, functions);
20        Self { ir }
21    }
22    /// Execute the filter against a context.
23    pub fn execute(
24        &self,
25        context: &crate::context::FilterContext,
26    ) -> Result<bool, crate::WirerustError> {
27        self.ir.execute(context)
28    }
29    /// Get a reference to the schema used by this filter.
30    pub fn schema(&self) -> &crate::schema::FilterSchema {
31        &self.ir.schema
32    }
33    /// Get a reference to the function registry used by this filter.
34    pub fn functions(&self) -> &crate::functions::FunctionRegistry {
35        &self.ir.functions
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use crate::context::FilterContext;
43    use crate::expr::{ComparisonOp, FilterExpr};
44    use crate::functions::FunctionRegistry;
45    use crate::schema::FilterSchema;
46    use crate::schema::FilterSchemaBuilder;
47    use crate::types::{FieldType, LiteralValue};
48    use std::sync::Arc;
49
50    fn schema() -> FilterSchema {
51        FilterSchemaBuilder::new()
52            .field("foo", FieldType::Int)
53            .field("bar", FieldType::Bytes)
54            .build()
55    }
56
57    fn context() -> FilterContext {
58        let mut ctx = FilterContext::new();
59        let sch = schema();
60        ctx.set("foo", LiteralValue::Int(42), &sch).unwrap();
61        ctx.set("bar", LiteralValue::Bytes(Arc::new(b"baz".to_vec())), &sch)
62            .unwrap();
63        ctx
64    }
65
66    #[test]
67    fn test_compiled_filter_execute_true() {
68        let expr = FilterExpr::Comparison {
69            left: Box::new(FilterExpr::Value(LiteralValue::Bytes(Arc::new(
70                b"foo".to_vec(),
71            )))),
72            op: ComparisonOp::Eq,
73            right: Box::new(FilterExpr::Value(LiteralValue::Int(42))),
74        };
75        let filter =
76            CompiledFilter::new(expr, Arc::new(schema()), Arc::new(FunctionRegistry::new()));
77        assert!(filter.execute(&context()).unwrap());
78    }
79
80    #[test]
81    fn test_compiled_filter_execute_false() {
82        let expr = FilterExpr::Comparison {
83            left: Box::new(FilterExpr::Value(LiteralValue::Bytes(Arc::new(
84                b"foo".to_vec(),
85            )))),
86            op: ComparisonOp::Eq,
87            right: Box::new(FilterExpr::Value(LiteralValue::Int(0))),
88        };
89        let filter =
90            CompiledFilter::new(expr, Arc::new(schema()), Arc::new(FunctionRegistry::new()));
91        assert!(!filter.execute(&context()).unwrap());
92    }
93
94    #[test]
95    fn test_compiled_filter_schema_access() {
96        let expr = FilterExpr::Comparison {
97            left: Box::new(FilterExpr::Value(LiteralValue::Bytes(Arc::new(
98                b"foo".to_vec(),
99            )))),
100            op: ComparisonOp::Eq,
101            right: Box::new(FilterExpr::Value(LiteralValue::Int(42))),
102        };
103        let filter =
104            CompiledFilter::new(expr, Arc::new(schema()), Arc::new(FunctionRegistry::new()));
105        let sch = filter.schema();
106        assert_eq!(sch.get_field_type("foo"), Some(&FieldType::Int));
107    }
108}