1use regex::Regex;
4use crate::{RuleCondition, Result, RulesError};
5use crate::context::ExecutionContext;
6
7pub struct ConditionEvaluator;
9
10impl ConditionEvaluator {
11 pub fn new() -> Self {
13 Self
14 }
15
16 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 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}