daa_rules/
conditions.rs

1//! Condition evaluation for rules
2
3use regex::Regex;
4use crate::{RuleCondition, Result, RulesError};
5use crate::context::ExecutionContext;
6
7/// Condition evaluator
8pub struct ConditionEvaluator;
9
10impl ConditionEvaluator {
11    /// Create a new condition evaluator
12    pub fn new() -> Self {
13        Self
14    }
15
16    /// Evaluate a condition against the context
17    pub async fn evaluate_condition(&self, condition: &RuleCondition, context: &ExecutionContext) -> Result<bool> {
18        match condition {
19            RuleCondition::Equals { field, value } => {
20                if let Some(field_value) = context.get_variable(field) {
21                    Ok(field_value == value)
22                } else {
23                    Ok(false)
24                }
25            }
26            
27            RuleCondition::NotEquals { field, value } => {
28                if let Some(field_value) = context.get_variable(field) {
29                    Ok(field_value != value)
30                } else {
31                    Ok(true)
32                }
33            }
34            
35            RuleCondition::GreaterThan { field, value } => {
36                if let Some(field_value) = context.get_variable(field) {
37                    if let Ok(num) = field_value.parse::<f64>() {
38                        Ok(num > *value)
39                    } else {
40                        Ok(false)
41                    }
42                } else {
43                    Ok(false)
44                }
45            }
46            
47            RuleCondition::LessThan { field, value } => {
48                if let Some(field_value) = context.get_variable(field) {
49                    if let Ok(num) = field_value.parse::<f64>() {
50                        Ok(num < *value)
51                    } else {
52                        Ok(false)
53                    }
54                } else {
55                    Ok(false)
56                }
57            }
58            
59            RuleCondition::Matches { field, pattern } => {
60                if let Some(field_value) = context.get_variable(field) {
61                    let regex = Regex::new(pattern)
62                        .map_err(|e| RulesError::ConditionEvaluation(format!("Invalid regex: {}", e)))?;
63                    Ok(regex.is_match(field_value))
64                } else {
65                    Ok(false)
66                }
67            }
68            
69            RuleCondition::Exists { field } => {
70                Ok(context.get_variable(field).is_some())
71            }
72            
73            RuleCondition::In { field, values } => {
74                if let Some(field_value) = context.get_variable(field) {
75                    Ok(values.contains(field_value))
76                } else {
77                    Ok(false)
78                }
79            }
80            
81            RuleCondition::And { conditions } => {
82                for condition in conditions {
83                    if !Box::pin(self.evaluate_condition(condition, context)).await? {
84                        return Ok(false);
85                    }
86                }
87                Ok(true)
88            }
89            
90            RuleCondition::Or { conditions } => {
91                for condition in conditions {
92                    if Box::pin(self.evaluate_condition(condition, context)).await? {
93                        return Ok(true);
94                    }
95                }
96                Ok(false)
97            }
98            
99            RuleCondition::Not { condition } => {
100                let result = Box::pin(self.evaluate_condition(condition, context)).await?;
101                Ok(!result)
102            }
103            
104            _ => {
105                // For other condition types, default to false
106                tracing::warn!("Unhandled condition type: {:?}", condition);
107                Ok(false)
108            }
109        }
110    }
111}
112
113impl Default for ConditionEvaluator {
114    fn default() -> Self {
115        Self::new()
116    }
117}