rust_rule_engine/engine/
pattern_matcher.rs1#![allow(deprecated)]
2
3use crate::engine::facts::Facts;
4use crate::engine::rule::ConditionGroup;
5use std::collections::HashMap;
6
7pub struct PatternMatcher;
9
10impl PatternMatcher {
11 pub fn evaluate_exists(condition: &ConditionGroup, facts: &Facts) -> bool {
13 let all_facts = facts.get_all_facts();
14
15 for (fact_name, fact_value) in &all_facts {
18 if let Some(target_type) = Self::extract_target_type(condition) {
20 if fact_name.starts_with(&target_type) {
22 let mut temp_facts = HashMap::new();
25 temp_facts.insert(target_type.clone(), fact_value.clone());
26
27 if condition.evaluate(&temp_facts) {
29 return true;
30 }
31 }
32 } else {
33 if condition.evaluate(&all_facts) {
35 return true;
36 }
37 }
38 }
39
40 false
41 }
42
43 pub fn evaluate_not(condition: &ConditionGroup, facts: &Facts) -> bool {
45 !Self::evaluate_exists(condition, facts)
47 }
48
49 pub fn evaluate_forall(condition: &ConditionGroup, facts: &Facts) -> bool {
51 let all_facts = facts.get_all_facts();
52
53 let target_type = match Self::extract_target_type(condition) {
55 Some(t) => t,
56 None => {
57 return condition.evaluate(&all_facts);
59 }
60 };
61
62 let mut target_facts = Vec::new();
64 for (fact_name, fact_value) in &all_facts {
65 if fact_name.starts_with(&target_type) || fact_name == &target_type {
68 target_facts.push((fact_name, fact_value));
69 }
70 }
71
72 if target_facts.is_empty() {
74 return true;
75 }
76
77 for (_fact_name, fact_value) in target_facts {
79 let mut temp_facts = HashMap::new();
82 temp_facts.insert(target_type.clone(), fact_value.clone());
83
84 if !condition.evaluate(&temp_facts) {
85 return false; }
87 }
88
89 true }
91
92 fn extract_target_type(condition: &ConditionGroup) -> Option<String> {
94 match condition {
95 ConditionGroup::Single(cond) => {
96 if let Some(dot_pos) = cond.field.find('.') {
98 Some(cond.field[..dot_pos].to_string())
99 } else {
100 Some(cond.field.clone())
101 }
102 }
103 ConditionGroup::Compound { left, .. } => {
104 Self::extract_target_type(left)
106 }
107 _ => None,
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::engine::rule::Condition;
116 use crate::types::{Operator, Value};
117 use std::collections::HashMap;
118
119 #[test]
120 fn test_exists_pattern_matching() {
121 let facts = Facts::new();
122
123 let mut customer1 = HashMap::new();
125 customer1.insert("tier".to_string(), Value::String("VIP".to_string()));
126 facts
127 .add_value("Customer1", Value::Object(customer1))
128 .unwrap();
129
130 let mut customer2 = HashMap::new();
131 customer2.insert("tier".to_string(), Value::String("Regular".to_string()));
132 facts
133 .add_value("Customer2", Value::Object(customer2))
134 .unwrap();
135
136 let condition = ConditionGroup::Single(Condition::new(
138 "Customer1.tier".to_string(),
139 Operator::Equal,
140 Value::String("VIP".to_string()),
141 ));
142
143 assert!(PatternMatcher::evaluate_exists(&condition, &facts));
144
145 let condition_fail = ConditionGroup::Single(Condition::new(
147 "Customer1.tier".to_string(),
148 Operator::Equal,
149 Value::String("Premium".to_string()),
150 ));
151
152 assert!(!PatternMatcher::evaluate_exists(&condition_fail, &facts));
153 }
154
155 #[test]
156 fn test_not_pattern_matching() {
157 let facts = Facts::new();
158
159 let mut customer = HashMap::new();
161 customer.insert("tier".to_string(), Value::String("Regular".to_string()));
162 facts
163 .add_value("Customer", Value::Object(customer))
164 .unwrap();
165
166 let condition = ConditionGroup::Single(Condition::new(
168 "Customer.tier".to_string(),
169 Operator::Equal,
170 Value::String("VIP".to_string()),
171 ));
172
173 assert!(PatternMatcher::evaluate_not(&condition, &facts));
174
175 let condition_fail = ConditionGroup::Single(Condition::new(
177 "Customer.tier".to_string(),
178 Operator::Equal,
179 Value::String("Regular".to_string()),
180 ));
181
182 assert!(!PatternMatcher::evaluate_not(&condition_fail, &facts));
183 }
184
185 #[test]
186 fn test_forall_pattern_matching() {
187 let facts = Facts::new();
188
189 let mut customer1 = HashMap::new();
191 customer1.insert("tier".to_string(), Value::String("VIP".to_string()));
192 facts
193 .add_value("Customer1", Value::Object(customer1))
194 .unwrap();
195
196 let mut customer2 = HashMap::new();
197 customer2.insert("tier".to_string(), Value::String("VIP".to_string()));
198 facts
199 .add_value("Customer2", Value::Object(customer2))
200 .unwrap();
201
202 let condition = ConditionGroup::Single(Condition::new(
205 "Customer.tier".to_string(), Operator::Equal,
207 Value::String("VIP".to_string()),
208 ));
209
210 assert!(PatternMatcher::evaluate_forall(&condition, &facts));
211
212 let mut customer3 = HashMap::new();
214 customer3.insert("tier".to_string(), Value::String("Regular".to_string()));
215 facts
216 .add_value("Customer3", Value::Object(customer3))
217 .unwrap();
218
219 assert!(!PatternMatcher::evaluate_forall(&condition, &facts));
221 }
222
223 #[test]
224 fn test_extract_target_type() {
225 let condition = ConditionGroup::Single(Condition::new(
226 "Customer.tier".to_string(),
227 Operator::Equal,
228 Value::String("VIP".to_string()),
229 ));
230
231 assert_eq!(
232 PatternMatcher::extract_target_type(&condition),
233 Some("Customer".to_string())
234 );
235
236 let simple_condition = ConditionGroup::Single(Condition::new(
237 "Customer".to_string(),
238 Operator::Equal,
239 Value::String("VIP".to_string()),
240 ));
241
242 assert_eq!(
243 PatternMatcher::extract_target_type(&simple_condition),
244 Some("Customer".to_string())
245 );
246 }
247}