rust_rule_engine/backward/
rule_executor.rs1use crate::engine::rule::{Condition, ConditionExpression, ConditionGroup, Rule};
7use crate::types::{ActionType, Value};
8use crate::{Facts, KnowledgeBase};
9use crate::errors::{Result, RuleEngineError};
10
11pub struct RuleExecutor {
13 knowledge_base: KnowledgeBase,
14}
15
16impl RuleExecutor {
17 pub fn new(knowledge_base: KnowledgeBase) -> Self {
19 Self { knowledge_base }
20 }
21
22 pub fn try_execute_rule(
29 &self,
30 rule: &Rule,
31 facts: &mut Facts,
32 ) -> Result<bool> {
33 if !self.evaluate_conditions(&rule.conditions, facts)? {
35 return Ok(false);
36 }
37
38 self.execute_actions(rule, facts)?;
40
41 Ok(true)
42 }
43
44 pub fn evaluate_conditions(
46 &self,
47 group: &ConditionGroup,
48 facts: &Facts,
49 ) -> Result<bool> {
50 match group {
51 ConditionGroup::Single(condition) => {
52 self.evaluate_condition(condition, facts)
53 }
54
55 ConditionGroup::Compound { left, operator, right } => {
56 let left_result = self.evaluate_conditions(left, facts)?;
57
58 match operator {
60 crate::types::LogicalOperator::And => {
61 if !left_result {
62 return Ok(false);
63 }
64 self.evaluate_conditions(right, facts)
65 }
66 crate::types::LogicalOperator::Or => {
67 if left_result {
68 return Ok(true);
69 }
70 self.evaluate_conditions(right, facts)
71 }
72 _ => {
73 Err(RuleEngineError::ExecutionError(
74 format!("Unsupported logical operator: {:?}", operator)
75 ))
76 }
77 }
78 }
79
80 ConditionGroup::Not(inner) => {
81 let result = self.evaluate_conditions(inner, facts)?;
82 Ok(!result)
83 }
84
85 ConditionGroup::Exists(conditions) => {
86 self.evaluate_conditions(conditions, facts)
89 }
90
91 ConditionGroup::Forall(conditions) => {
92 self.evaluate_conditions(conditions, facts)
95 }
96
97 ConditionGroup::Accumulate { .. } => {
98 Ok(true)
101 }
102 }
103 }
104
105 pub fn evaluate_condition(&self, condition: &Condition, facts: &Facts) -> Result<bool> {
107 match &condition.expression {
108 ConditionExpression::Field(field_name) => {
109 if let Some(value) = facts.get_nested(field_name).or_else(|| facts.get(field_name)) {
111 Ok(condition.operator.evaluate(&value, &condition.value))
112 } else {
113 match condition.operator {
116 crate::types::Operator::NotEqual => {
117 Ok(true)
119 }
120 _ => Ok(false),
121 }
122 }
123 }
124
125 ConditionExpression::FunctionCall { name, args } => {
126 self.evaluate_function_call(name, args, condition, facts)
128 }
129
130 ConditionExpression::Test { name, args } => {
131 self.evaluate_test_expression(name, args, facts)
133 }
134
135 ConditionExpression::MultiField { field, operation, variable } => {
136 self.evaluate_multifield(field, operation, variable, condition, facts)
138 }
139 }
140 }
141
142 fn evaluate_function_call(
144 &self,
145 function_name: &str,
146 args: &[String],
147 condition: &Condition,
148 facts: &Facts,
149 ) -> Result<bool> {
150 let mut arg_values = Vec::new();
155 for arg in args {
156 if let Some(value) = facts.get(arg).or_else(|| facts.get_nested(arg)) {
157 arg_values.push(value);
158 } else {
159 if let Ok(val) = self.parse_literal_value(arg) {
161 arg_values.push(val);
162 } else {
163 return Ok(false);
165 }
166 }
167 }
168
169 match function_name {
173 "len" | "length" | "size" => {
174 if arg_values.len() == 1 {
175 let len = match &arg_values[0] {
176 Value::String(s) => s.len() as f64,
177 Value::Array(arr) => arr.len() as f64,
178 _ => return Ok(false),
179 };
180
181 Ok(condition.operator.evaluate(&Value::Number(len), &condition.value))
182 } else {
183 Ok(false)
184 }
185 }
186
187 "isEmpty" | "is_empty" => {
188 if arg_values.len() == 1 {
189 let is_empty = match &arg_values[0] {
190 Value::String(s) => s.is_empty(),
191 Value::Array(arr) => arr.is_empty(),
192 Value::Null => true,
193 _ => false,
194 };
195
196 Ok(condition.operator.evaluate(&Value::Boolean(is_empty), &condition.value))
197 } else {
198 Ok(false)
199 }
200 }
201
202 "contains" => {
203 if arg_values.len() == 2 {
204 let contains = match (&arg_values[0], &arg_values[1]) {
205 (Value::String(s), Value::String(substr)) => s.contains(substr.as_str()),
206 (Value::Array(arr), val) => arr.contains(val),
207 _ => false,
208 };
209
210 Ok(condition.operator.evaluate(&Value::Boolean(contains), &condition.value))
211 } else {
212 Ok(false)
213 }
214 }
215
216 _ => {
217 Ok(false)
220 }
221 }
222 }
223
224 fn evaluate_test_expression(
226 &self,
227 function_name: &str,
228 args: &[String],
229 facts: &Facts,
230 ) -> Result<bool> {
231 match function_name {
235 "exists" => {
236 if args.len() == 1 {
238 Ok(facts.get(&args[0]).is_some() || facts.get_nested(&args[0]).is_some())
239 } else {
240 Ok(false)
241 }
242 }
243
244 "notExists" | "not_exists" => {
245 if args.len() == 1 {
247 Ok(facts.get(&args[0]).is_none() && facts.get_nested(&args[0]).is_none())
248 } else {
249 Ok(false)
250 }
251 }
252
253 _ => {
254 Ok(false)
256 }
257 }
258 }
259
260 fn evaluate_multifield(
262 &self,
263 field: &str,
264 operation: &str,
265 variable: &Option<String>,
266 condition: &Condition,
267 facts: &Facts,
268 ) -> Result<bool> {
269 let field_value = facts.get(field).or_else(|| facts.get_nested(field));
271
272 match operation {
273 "collect" => {
274 Ok(field_value.is_some())
276 }
277
278 "count" => {
279 let count = if let Some(value) = field_value {
281 match value {
282 Value::Array(arr) => arr.len() as f64,
283 _ => 1.0,
284 }
285 } else {
286 0.0
287 };
288
289 Ok(condition.operator.evaluate(&Value::Number(count), &condition.value))
290 }
291
292 "first" => {
293 if let Some(Value::Array(arr)) = field_value {
295 if !arr.is_empty() {
296 Ok(true)
297 } else {
298 Ok(false)
299 }
300 } else {
301 Ok(false)
302 }
303 }
304
305 "last" => {
306 if let Some(Value::Array(arr)) = field_value {
308 if !arr.is_empty() {
309 Ok(true)
310 } else {
311 Ok(false)
312 }
313 } else {
314 Ok(false)
315 }
316 }
317
318 "empty" | "isEmpty" => {
319 let is_empty = if let Some(value) = field_value {
321 match value {
322 Value::Array(arr) => arr.is_empty(),
323 Value::String(s) => s.is_empty(),
324 Value::Null => true,
325 _ => false,
326 }
327 } else {
328 true
329 };
330
331 Ok(is_empty)
332 }
333
334 "not_empty" | "notEmpty" => {
335 let is_not_empty = if let Some(value) = field_value {
337 match value {
338 Value::Array(arr) => !arr.is_empty(),
339 Value::String(s) => !s.is_empty(),
340 Value::Null => false,
341 _ => true,
342 }
343 } else {
344 false
345 };
346
347 Ok(is_not_empty)
348 }
349
350 "contains" => {
351 if let Some(Value::Array(arr)) = field_value {
353 Ok(arr.contains(&condition.value))
354 } else {
355 Ok(false)
356 }
357 }
358
359 _ => {
360 Ok(false)
362 }
363 }
364 }
365
366 fn execute_actions(&self, rule: &Rule, facts: &mut Facts) -> Result<()> {
368 for action in &rule.actions {
369 self.execute_action(action, facts)?;
370 }
371
372 Ok(())
373 }
374
375 fn execute_action(&self, action: &ActionType, facts: &mut Facts) -> Result<()> {
377 match action {
378 ActionType::Set { field, value } => {
379 let evaluated_value = self.evaluate_value_expression(value, facts)?;
381 facts.set(field, evaluated_value);
382 Ok(())
383 }
384
385 ActionType::MethodCall { object, method, args } => {
386 if let Some(obj_value) = facts.get(object) {
388 let mut obj_value = obj_value.clone();
389 let mut arg_values = Vec::new();
391 for arg in args {
392 let val = self.evaluate_value_expression(arg, facts)?;
393 arg_values.push(val);
394 }
395
396 let result = obj_value.call_method(method, arg_values)
398 .map_err(|e| RuleEngineError::ExecutionError(e))?;
399
400 facts.set(object, obj_value);
402
403 if result != Value::Null {
405 facts.set(&format!("{}._return", object), result);
406 }
407
408 Ok(())
409 } else {
410 Err(RuleEngineError::ExecutionError(
411 format!("Object not found: {}", object)
412 ))
413 }
414 }
415
416 ActionType::Retract { object } => {
417 facts.remove(object);
420 Ok(())
421 }
422
423 ActionType::Log { message } => {
424 println!("[BC Action] {}", message);
426 Ok(())
427 }
428
429 ActionType::Custom { .. } => {
430 Ok(())
432 }
433
434 ActionType::ActivateAgendaGroup { .. } => {
435 Ok(())
437 }
438
439 ActionType::ScheduleRule { .. } => {
440 Ok(())
442 }
443
444 ActionType::CompleteWorkflow { .. } => {
445 Ok(())
447 }
448
449 ActionType::SetWorkflowData { .. } => {
450 Ok(())
452 }
453 }
454 }
455
456 fn evaluate_value_expression(&self, value: &Value, facts: &Facts) -> Result<Value> {
458 match value {
459 Value::Expression(expr) => {
460 if let Some(val) = facts.get(expr).or_else(|| facts.get_nested(expr)) {
463 Ok(val)
464 } else if let Ok(lit) = self.parse_literal_value(expr) {
465 Ok(lit)
466 } else {
467 Ok(value.clone())
468 }
469 }
470 _ => Ok(value.clone()),
471 }
472 }
473
474 fn parse_literal_value(&self, s: &str) -> Result<Value> {
476 if s == "true" {
478 return Ok(Value::Boolean(true));
479 }
480 if s == "false" {
481 return Ok(Value::Boolean(false));
482 }
483 if s == "null" {
484 return Ok(Value::Null);
485 }
486
487 if let Ok(n) = s.parse::<f64>() {
489 return Ok(Value::Number(n));
490 }
491
492 if let Ok(i) = s.parse::<i64>() {
494 return Ok(Value::Integer(i));
495 }
496
497 Ok(Value::String(s.to_string()))
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use crate::types::Operator;
506
507 #[test]
508 fn test_evaluate_simple_condition() {
509 let kb = KnowledgeBase::new("test");
510 let executor = RuleExecutor::new(kb);
511
512 let mut facts = Facts::new();
513 facts.set("User.Age", Value::Number(25.0));
514
515 let condition = Condition::new(
516 "User.Age".to_string(),
517 Operator::GreaterThan,
518 Value::Number(18.0),
519 );
520
521 let result = executor.evaluate_condition(&condition, &facts).unwrap();
522 assert!(result);
523 }
524
525 #[test]
526 fn test_evaluate_function_call_len() {
527 let kb = KnowledgeBase::new("test");
528 let executor = RuleExecutor::new(kb);
529
530 let mut facts = Facts::new();
531 facts.set("User.Name", Value::String("John".to_string()));
532
533 let condition = Condition::with_function(
534 "len".to_string(),
535 vec!["User.Name".to_string()],
536 Operator::GreaterThan,
537 Value::Number(3.0),
538 );
539
540 let result = executor.evaluate_condition(&condition, &facts).unwrap();
541 assert!(result); }
543
544 #[test]
545 fn test_execute_set_action() {
546 let kb = KnowledgeBase::new("test");
547 let executor = RuleExecutor::new(kb);
548
549 let mut facts = Facts::new();
550
551 let action = ActionType::Set {
552 field: "User.IsVIP".to_string(),
553 value: Value::Boolean(true),
554 };
555
556 executor.execute_action(&action, &mut facts).unwrap();
557
558 assert_eq!(facts.get("User.IsVIP"), Some(Value::Boolean(true)));
559 }
560}