1use crate::engine::rule::{Condition, ConditionGroup, Rule};
7use crate::parser::GRLParser;
8use crate::rete::{AlphaNode, ReteUlNode, TypedReteUlRule};
9use crate::rete::facts::{TypedFacts, FactValue};
10use crate::rete::propagation::IncrementalEngine;
11use crate::types::{Operator, Value};
12use crate::errors::{Result, RuleEngineError};
13use std::fs;
14use std::path::Path;
15
16pub struct GrlReteLoader;
19
20impl GrlReteLoader {
21 pub fn load_from_file<P: AsRef<Path>>(
23 path: P,
24 engine: &mut IncrementalEngine,
25 ) -> Result<usize> {
26 let grl_text = fs::read_to_string(path.as_ref()).map_err(|e| {
27 RuleEngineError::ParseError {
28 message: format!("Failed to read GRL file: {}", e),
29 }
30 })?;
31
32 Self::load_from_string(&grl_text, engine)
33 }
34
35 pub fn load_from_string(
37 grl_text: &str,
38 engine: &mut IncrementalEngine,
39 ) -> Result<usize> {
40 let rules = GRLParser::parse_rules(grl_text)?;
42
43 let mut loaded_count = 0;
44
45 for rule in rules {
46 let rete_rule = Self::convert_rule_to_rete(rule)?;
48
49 let dependencies = Self::extract_dependencies(&rete_rule);
51
52 engine.add_rule(rete_rule, dependencies);
54 loaded_count += 1;
55 }
56
57 Ok(loaded_count)
58 }
59
60 fn convert_rule_to_rete(rule: Rule) -> Result<TypedReteUlRule> {
62 let node = Self::convert_condition_group(&rule.conditions)?;
64
65 let rete_rule = TypedReteUlRule {
67 name: rule.name.clone(),
68 node,
69 priority: rule.salience,
70 no_loop: rule.no_loop,
71 action: Self::create_action_closure(rule.actions),
72 };
73
74 Ok(rete_rule)
75 }
76
77 fn convert_condition_group(group: &ConditionGroup) -> Result<ReteUlNode> {
79 match group {
80 ConditionGroup::Single(condition) => {
81 Self::convert_condition(condition)
82 }
83 ConditionGroup::Compound { left, operator, right } => {
84 let left_node = Self::convert_condition_group(left)?;
85 let right_node = Self::convert_condition_group(right)?;
86
87 match operator {
88 crate::types::LogicalOperator::And => {
89 Ok(ReteUlNode::UlAnd(Box::new(left_node), Box::new(right_node)))
90 }
91 crate::types::LogicalOperator::Or => {
92 Ok(ReteUlNode::UlOr(Box::new(left_node), Box::new(right_node)))
93 }
94 crate::types::LogicalOperator::Not => {
95 Ok(ReteUlNode::UlNot(Box::new(left_node)))
97 }
98 }
99 }
100 ConditionGroup::Not(inner) => {
101 let inner_node = Self::convert_condition_group(inner)?;
102 Ok(ReteUlNode::UlNot(Box::new(inner_node)))
103 }
104 ConditionGroup::Exists(inner) => {
105 let inner_node = Self::convert_condition_group(inner)?;
106 Ok(ReteUlNode::UlExists(Box::new(inner_node)))
107 }
108 ConditionGroup::Forall(inner) => {
109 let inner_node = Self::convert_condition_group(inner)?;
110 Ok(ReteUlNode::UlForall(Box::new(inner_node)))
111 }
112 ConditionGroup::Accumulate {
113 result_var,
114 source_pattern,
115 extract_field,
116 source_conditions,
117 function,
118 function_arg,
119 } => {
120 Ok(ReteUlNode::UlAccumulate {
121 result_var: result_var.clone(),
122 source_pattern: source_pattern.clone(),
123 extract_field: extract_field.clone(),
124 source_conditions: source_conditions.clone(),
125 function: function.clone(),
126 function_arg: function_arg.clone(),
127 })
128 }
129 }
130 }
131
132 fn convert_condition(condition: &Condition) -> Result<ReteUlNode> {
134 use crate::engine::rule::ConditionExpression;
135
136 match &condition.expression {
138 ConditionExpression::MultiField { field, operation, variable } => {
139 let operator_str = Self::operator_to_string(&condition.operator);
141 let value_str = if !matches!(condition.value, Value::Boolean(_)) {
142 Some(Self::value_to_string(&condition.value))
143 } else {
144 None
145 };
146
147 let (op, cmp_val) = if operation == "count" && operator_str != "==" {
149 (Some(operator_str), value_str)
151 } else {
152 (None, value_str)
154 };
155
156 Ok(ReteUlNode::UlMultiField {
157 field: field.clone(),
158 operation: operation.clone(),
159 value: if operation == "contains" { cmp_val.clone() } else { None },
160 operator: op,
161 compare_value: if operation == "count" { cmp_val } else { None },
162 })
163 }
164 _ => {
165 let operator_str = Self::operator_to_string(&condition.operator);
167 let value_str = Self::value_to_string(&condition.value);
168
169 let alpha = AlphaNode {
170 field: condition.field.clone(),
171 operator: operator_str,
172 value: value_str,
173 };
174
175 Ok(ReteUlNode::UlAlpha(alpha))
176 }
177 }
178 }
179
180 fn operator_to_string(op: &Operator) -> String {
182 match op {
183 Operator::Equal => "==".to_string(),
184 Operator::NotEqual => "!=".to_string(),
185 Operator::GreaterThan => ">".to_string(),
186 Operator::GreaterThanOrEqual => ">=".to_string(),
187 Operator::LessThan => "<".to_string(),
188 Operator::LessThanOrEqual => "<=".to_string(),
189 Operator::Contains => "contains".to_string(),
190 Operator::NotContains => "!contains".to_string(),
191 Operator::StartsWith => "startsWith".to_string(),
192 Operator::EndsWith => "endsWith".to_string(),
193 Operator::Matches => "matches".to_string(),
194 }
195 }
196
197 fn value_to_string(value: &Value) -> String {
199 match value {
200 Value::Number(n) => n.to_string(),
201 Value::Integer(i) => i.to_string(),
202 Value::String(s) => s.clone(),
203 Value::Boolean(b) => b.to_string(),
204 Value::Null => "null".to_string(),
205 Value::Array(arr) => {
206 let items: Vec<String> = arr.iter()
208 .map(|v| Self::value_to_string(v))
209 .collect();
210 format!("[{}]", items.join(","))
211 }
212 Value::Object(_) => {
213 "object".to_string()
215 }
216 Value::Expression(expr) => {
217 expr.clone()
219 }
220 }
221 }
222
223 fn create_action_closure(
225 actions: Vec<crate::types::ActionType>,
226 ) -> std::sync::Arc<dyn Fn(&mut TypedFacts, &mut super::ActionResults) + Send + Sync> {
227 std::sync::Arc::new(move |facts: &mut TypedFacts, results: &mut super::ActionResults| {
228 for action in &actions {
230 Self::execute_action(action, facts, results);
231 }
232 })
233 }
234
235 fn execute_action(
237 action: &crate::types::ActionType,
238 facts: &mut TypedFacts,
239 results: &mut super::ActionResults,
240 ) {
241 use crate::types::ActionType;
242
243 match action {
244 ActionType::Set { field, value } => {
245 let evaluated_value = match value {
247 Value::Expression(expr) => {
248 Self::evaluate_expression_for_rete(expr, facts)
250 }
251 _ => value.clone(),
252 };
253
254 let fact_value = Self::value_to_fact_value(&evaluated_value);
256 facts.set(field, fact_value);
257 }
258 ActionType::Log { message } => {
259 println!("📝 LOG: {}", message);
260 }
261 ActionType::Call { function, args } => {
262 results.add(super::ActionResult::CallFunction {
264 function_name: function.clone(),
265 args: args.iter().map(|v| Self::value_to_string(v)).collect(),
266 });
267 println!("🔧 CALL: {}", function);
268 }
269 ActionType::MethodCall { object, method, args } => {
270 let mut all_args = vec![object.clone()];
272 all_args.extend(args.iter().map(|v| Self::value_to_string(v)));
273
274 results.add(super::ActionResult::CallFunction {
275 function_name: format!("{}.{}", object, method),
276 args: all_args,
277 });
278 println!("� METHOD: {}.{}", object, method);
279 }
280 ActionType::Update { object } => {
281 println!("� UPDATE: {}", object);
284 }
286 ActionType::Retract { object } => {
287 let object_name = object.trim_matches('"');
289
290 if let Some(handle) = facts.get_fact_handle(object_name) {
292 results.add(super::ActionResult::Retract(handle));
294 println!("🗑️ RETRACT: {} (handle: {:?})", object_name, handle);
295 } else {
296 results.add(super::ActionResult::RetractByType(object_name.to_string()));
298 println!("🗑️ RETRACT: {} (by type, no handle found)", object_name);
299 }
300 }
301 ActionType::Custom { action_type, params } => {
302 println!("⚙️ CUSTOM: {}", action_type);
303
304 match action_type.as_str() {
306 "set" => {
307 if let Some(field_val) = params.get("0").or_else(|| params.get("field")) {
310 if let Some(value_val) = params.get("1").or_else(|| params.get("value")) {
311 let field_str = match field_val {
313 Value::String(s) => s.clone(),
314 Value::Expression(expr) => format!("{:?}", expr),
315 _ => return,
316 };
317
318 let field_clean = field_str
320 .trim_matches(|c: char| !c.is_alphanumeric() && c != '.')
321 .to_string();
322
323 let evaluated_value = match value_val {
325 Value::Expression(expr) => {
326 Self::evaluate_expression_for_rete(expr, facts)
327 }
328 _ => value_val.clone(),
329 };
330
331 let fact_value = Self::value_to_fact_value(&evaluated_value);
333 facts.set(&field_clean, fact_value);
334 }
335 }
336 }
337 _ => {
338 }
340 }
341 }
342 ActionType::ActivateAgendaGroup { group } => {
343 results.add(super::ActionResult::ActivateAgendaGroup(group.clone()));
345 println!("📋 ACTIVATE GROUP: {}", group);
346 }
347 ActionType::ScheduleRule { rule_name, delay_ms } => {
348 results.add(super::ActionResult::ScheduleRule {
350 rule_name: rule_name.clone(),
351 delay_ms: *delay_ms,
352 });
353 println!("⏰ SCHEDULE: {} (delay: {}ms)", rule_name, delay_ms);
354 }
355 ActionType::CompleteWorkflow { workflow_name } => {
356 println!("✔️ COMPLETE WORKFLOW: {}", workflow_name);
357 }
358 ActionType::SetWorkflowData { key, value: _ } => {
359 println!("📊 SET WORKFLOW DATA: {}", key);
360 }
361 }
362 }
363
364 fn value_to_fact_value(value: &Value) -> FactValue {
366 match value {
367 Value::Number(n) => {
368 if n.fract() == 0.0 {
370 FactValue::Integer(*n as i64)
371 } else {
372 FactValue::Float(*n)
373 }
374 }
375 Value::Integer(i) => FactValue::Integer(*i),
376 Value::String(s) => FactValue::String(s.clone()),
377 Value::Boolean(b) => FactValue::Boolean(*b),
378 Value::Null => FactValue::Null,
379 Value::Array(arr) => {
380 let fact_arr: Vec<FactValue> = arr.iter()
381 .map(Self::value_to_fact_value)
382 .collect();
383 FactValue::Array(fact_arr)
384 }
385 Value::Object(_) => {
386 FactValue::String("object".to_string())
388 }
389 Value::Expression(expr) => {
390 FactValue::String(format!("[EXPR: {}]", expr))
392 }
393 }
394 }
395
396 fn extract_dependencies(rule: &TypedReteUlRule) -> Vec<String> {
398 let mut deps = Vec::new();
399 Self::extract_deps_from_node(&rule.node, &mut deps);
400
401 deps.sort();
403 deps.dedup();
404
405 deps
406 }
407
408 fn extract_deps_from_node(node: &ReteUlNode, deps: &mut Vec<String>) {
410 match node {
411 ReteUlNode::UlAlpha(alpha) => {
412 if let Some(dot_pos) = alpha.field.find('.') {
414 let fact_type = alpha.field[..dot_pos].to_string();
415 deps.push(fact_type);
416 }
417 }
418 ReteUlNode::UlMultiField { field, .. } => {
419 if let Some(dot_pos) = field.find('.') {
421 let fact_type = field[..dot_pos].to_string();
422 deps.push(fact_type);
423 }
424 }
425 ReteUlNode::UlAnd(left, right) | ReteUlNode::UlOr(left, right) => {
426 Self::extract_deps_from_node(left, deps);
427 Self::extract_deps_from_node(right, deps);
428 }
429 ReteUlNode::UlNot(inner)
430 | ReteUlNode::UlExists(inner)
431 | ReteUlNode::UlForall(inner) => {
432 Self::extract_deps_from_node(inner, deps);
433 }
434 ReteUlNode::UlAccumulate { source_pattern, .. } => {
435 deps.push(source_pattern.clone());
437 }
438 ReteUlNode::UlTerminal(_) => {
439 }
441 }
442 }
443
444 fn evaluate_expression_for_rete(expr: &str, typed_facts: &TypedFacts) -> Value {
446 use crate::engine::facts::Facts;
448
449 let mut facts = Facts::new();
450
451 for (key, value) in typed_facts.get_all() {
455 let converted_value = Self::fact_value_to_value(value);
456
457 facts.set(key, converted_value.clone());
460
461 if !key.contains('.') {
463 facts.set(&format!("Order.{}", key), converted_value);
464 }
465 }
466
467 match crate::expression::evaluate_expression(expr, &facts) {
469 Ok(result) => result,
470 Err(e) => {
471 Value::String(expr.to_string())
474 }
475 }
476 }
477
478 fn fact_value_to_value(fact_value: &FactValue) -> Value {
480 match fact_value {
481 FactValue::String(s) => {
482 if let Ok(i) = s.parse::<i64>() {
484 Value::Integer(i)
485 } else if let Ok(f) = s.parse::<f64>() {
486 Value::Number(f)
487 } else if s == "true" {
488 Value::Boolean(true)
489 } else if s == "false" {
490 Value::Boolean(false)
491 } else {
492 Value::String(s.clone())
493 }
494 }
495 FactValue::Integer(i) => Value::Integer(*i),
496 FactValue::Float(f) => Value::Number(*f),
497 FactValue::Boolean(b) => Value::Boolean(*b),
498 FactValue::Array(arr) => {
499 Value::Array(arr.iter().map(Self::fact_value_to_value).collect())
500 }
501 FactValue::Null => Value::Null,
502 }
503 }
504}
505
506#[cfg(test)]
507mod tests {
508 use super::*;
509
510 #[test]
511 fn test_convert_simple_rule() {
512 let grl = r#"
513 rule "TestRule" salience 10 no-loop {
514 when
515 Person.age > 18
516 then
517 Person.is_adult = true;
518 }
519 "#;
520
521 let rules = GRLParser::parse_rules(grl).unwrap();
522 assert_eq!(rules.len(), 1);
523
524 let rete_rule = GrlReteLoader::convert_rule_to_rete(rules[0].clone()).unwrap();
525 assert_eq!(rete_rule.name, "TestRule");
526 assert_eq!(rete_rule.priority, 10);
527 assert!(rete_rule.no_loop);
528 }
529
530 #[test]
531 fn test_extract_dependencies() {
532 let grl = r#"
533 rule "MultiTypeRule" {
534 when
535 Person.age > 18 && Order.amount > 1000
536 then
537 Person.premium = true;
538 }
539 "#;
540
541 let rules = GRLParser::parse_rules(grl).unwrap();
542 let rete_rule = GrlReteLoader::convert_rule_to_rete(rules[0].clone()).unwrap();
543 let deps = GrlReteLoader::extract_dependencies(&rete_rule);
544
545 assert_eq!(deps.len(), 2);
546 assert!(deps.contains(&"Person".to_string()));
547 assert!(deps.contains(&"Order".to_string()));
548 }
549
550 #[test]
551 fn test_load_from_string() {
552 let grl = r#"
553 rule "Rule1" {
554 when
555 Person.age > 18
556 then
557 Person.is_adult = true;
558 }
559
560 rule "Rule2" {
561 when
562 Order.amount > 1000
563 then
564 Order.high_value = true;
565 }
566 "#;
567
568 let mut engine = IncrementalEngine::new();
569 let count = GrlReteLoader::load_from_string(grl, &mut engine).unwrap();
570
571 assert_eq!(count, 2);
572 }
573}