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 let operator_str = Self::operator_to_string(&condition.operator);
135 let value_str = Self::value_to_string(&condition.value);
136
137 let alpha = AlphaNode {
138 field: condition.field.clone(),
139 operator: operator_str,
140 value: value_str,
141 };
142
143 Ok(ReteUlNode::UlAlpha(alpha))
144 }
145
146 fn operator_to_string(op: &Operator) -> String {
148 match op {
149 Operator::Equal => "==".to_string(),
150 Operator::NotEqual => "!=".to_string(),
151 Operator::GreaterThan => ">".to_string(),
152 Operator::GreaterThanOrEqual => ">=".to_string(),
153 Operator::LessThan => "<".to_string(),
154 Operator::LessThanOrEqual => "<=".to_string(),
155 Operator::Contains => "contains".to_string(),
156 Operator::NotContains => "!contains".to_string(),
157 Operator::StartsWith => "startsWith".to_string(),
158 Operator::EndsWith => "endsWith".to_string(),
159 Operator::Matches => "matches".to_string(),
160 }
161 }
162
163 fn value_to_string(value: &Value) -> String {
165 match value {
166 Value::Number(n) => n.to_string(),
167 Value::Integer(i) => i.to_string(),
168 Value::String(s) => s.clone(),
169 Value::Boolean(b) => b.to_string(),
170 Value::Null => "null".to_string(),
171 Value::Array(arr) => {
172 let items: Vec<String> = arr.iter()
174 .map(|v| Self::value_to_string(v))
175 .collect();
176 format!("[{}]", items.join(","))
177 }
178 Value::Object(_) => {
179 "object".to_string()
181 }
182 Value::Expression(expr) => {
183 expr.clone()
185 }
186 }
187 }
188
189 fn create_action_closure(
191 actions: Vec<crate::types::ActionType>,
192 ) -> std::sync::Arc<dyn Fn(&mut TypedFacts) + Send + Sync> {
193 std::sync::Arc::new(move |facts: &mut TypedFacts| {
194 for action in &actions {
196 Self::execute_action(action, facts);
197 }
198 })
199 }
200
201 fn execute_action(action: &crate::types::ActionType, facts: &mut TypedFacts) {
203 use crate::types::ActionType;
204
205 match action {
206 ActionType::Set { field, value } => {
207 let evaluated_value = match value {
209 Value::Expression(expr) => {
210 Self::evaluate_expression_for_rete(expr, facts)
212 }
213 _ => value.clone(),
214 };
215
216 let fact_value = Self::value_to_fact_value(&evaluated_value);
218 facts.set(field, fact_value);
219 }
220 ActionType::Log { message } => {
221 println!("📝 LOG: {}", message);
222 }
223 ActionType::Call { function, args: _ } => {
224 println!("🔧 CALL: {}", function);
226 }
227 ActionType::MethodCall { object, method, args: _ } => {
228 println!("📞 METHOD: {}.{}", object, method);
229 }
230 ActionType::Update { object } => {
231 println!("🔄 UPDATE: {}", object);
232 }
233 ActionType::Retract { object } => {
234 println!("🗑️ RETRACT: {}", object);
235 facts.set(format!("_retract_{}", object), FactValue::Boolean(true));
237 }
238 ActionType::Custom { action_type, params: _ } => {
239 println!("⚙️ CUSTOM: {}", action_type);
240 }
241 ActionType::ActivateAgendaGroup { group } => {
242 println!("📋 ACTIVATE GROUP: {}", group);
243 }
244 ActionType::ScheduleRule { rule_name, delay_ms } => {
245 println!("⏰ SCHEDULE: {} (delay: {}ms)", rule_name, delay_ms);
246 }
247 ActionType::CompleteWorkflow { workflow_name } => {
248 println!("✔️ COMPLETE WORKFLOW: {}", workflow_name);
249 }
250 ActionType::SetWorkflowData { key, value: _ } => {
251 println!("📊 SET WORKFLOW DATA: {}", key);
252 }
253 }
254 }
255
256 fn value_to_fact_value(value: &Value) -> FactValue {
258 match value {
259 Value::Number(n) => {
260 if n.fract() == 0.0 {
262 FactValue::Integer(*n as i64)
263 } else {
264 FactValue::Float(*n)
265 }
266 }
267 Value::Integer(i) => FactValue::Integer(*i),
268 Value::String(s) => FactValue::String(s.clone()),
269 Value::Boolean(b) => FactValue::Boolean(*b),
270 Value::Null => FactValue::Null,
271 Value::Array(arr) => {
272 let fact_arr: Vec<FactValue> = arr.iter()
273 .map(Self::value_to_fact_value)
274 .collect();
275 FactValue::Array(fact_arr)
276 }
277 Value::Object(_) => {
278 FactValue::String("object".to_string())
280 }
281 Value::Expression(expr) => {
282 FactValue::String(format!("[EXPR: {}]", expr))
284 }
285 }
286 }
287
288 fn extract_dependencies(rule: &TypedReteUlRule) -> Vec<String> {
290 let mut deps = Vec::new();
291 Self::extract_deps_from_node(&rule.node, &mut deps);
292
293 deps.sort();
295 deps.dedup();
296
297 deps
298 }
299
300 fn extract_deps_from_node(node: &ReteUlNode, deps: &mut Vec<String>) {
302 match node {
303 ReteUlNode::UlAlpha(alpha) => {
304 if let Some(dot_pos) = alpha.field.find('.') {
306 let fact_type = alpha.field[..dot_pos].to_string();
307 deps.push(fact_type);
308 }
309 }
310 ReteUlNode::UlAnd(left, right) | ReteUlNode::UlOr(left, right) => {
311 Self::extract_deps_from_node(left, deps);
312 Self::extract_deps_from_node(right, deps);
313 }
314 ReteUlNode::UlNot(inner)
315 | ReteUlNode::UlExists(inner)
316 | ReteUlNode::UlForall(inner) => {
317 Self::extract_deps_from_node(inner, deps);
318 }
319 ReteUlNode::UlAccumulate { source_pattern, .. } => {
320 deps.push(source_pattern.clone());
322 }
323 ReteUlNode::UlTerminal(_) => {
324 }
326 }
327 }
328
329 fn evaluate_expression_for_rete(expr: &str, typed_facts: &TypedFacts) -> Value {
331 use crate::engine::facts::Facts;
333
334 let mut facts = Facts::new();
335
336 for (key, value) in typed_facts.get_all() {
340 let converted_value = Self::fact_value_to_value(value);
341
342 facts.set(key, converted_value.clone());
345
346 if !key.contains('.') {
348 facts.set(&format!("Order.{}", key), converted_value);
349 }
350 }
351
352 match crate::expression::evaluate_expression(expr, &facts) {
354 Ok(result) => result,
355 Err(e) => {
356 Value::String(expr.to_string())
359 }
360 }
361 }
362
363 fn fact_value_to_value(fact_value: &FactValue) -> Value {
365 match fact_value {
366 FactValue::String(s) => {
367 if let Ok(i) = s.parse::<i64>() {
369 Value::Integer(i)
370 } else if let Ok(f) = s.parse::<f64>() {
371 Value::Number(f)
372 } else if s == "true" {
373 Value::Boolean(true)
374 } else if s == "false" {
375 Value::Boolean(false)
376 } else {
377 Value::String(s.clone())
378 }
379 }
380 FactValue::Integer(i) => Value::Integer(*i),
381 FactValue::Float(f) => Value::Number(*f),
382 FactValue::Boolean(b) => Value::Boolean(*b),
383 FactValue::Array(arr) => {
384 Value::Array(arr.iter().map(Self::fact_value_to_value).collect())
385 }
386 FactValue::Null => Value::Null,
387 }
388 }
389}
390
391#[cfg(test)]
392mod tests {
393 use super::*;
394
395 #[test]
396 fn test_convert_simple_rule() {
397 let grl = r#"
398 rule "TestRule" salience 10 no-loop {
399 when
400 Person.age > 18
401 then
402 Person.is_adult = true;
403 }
404 "#;
405
406 let rules = GRLParser::parse_rules(grl).unwrap();
407 assert_eq!(rules.len(), 1);
408
409 let rete_rule = GrlReteLoader::convert_rule_to_rete(rules[0].clone()).unwrap();
410 assert_eq!(rete_rule.name, "TestRule");
411 assert_eq!(rete_rule.priority, 10);
412 assert!(rete_rule.no_loop);
413 }
414
415 #[test]
416 fn test_extract_dependencies() {
417 let grl = r#"
418 rule "MultiTypeRule" {
419 when
420 Person.age > 18 && Order.amount > 1000
421 then
422 Person.premium = true;
423 }
424 "#;
425
426 let rules = GRLParser::parse_rules(grl).unwrap();
427 let rete_rule = GrlReteLoader::convert_rule_to_rete(rules[0].clone()).unwrap();
428 let deps = GrlReteLoader::extract_dependencies(&rete_rule);
429
430 assert_eq!(deps.len(), 2);
431 assert!(deps.contains(&"Person".to_string()));
432 assert!(deps.contains(&"Order".to_string()));
433 }
434
435 #[test]
436 fn test_load_from_string() {
437 let grl = r#"
438 rule "Rule1" {
439 when
440 Person.age > 18
441 then
442 Person.is_adult = true;
443 }
444
445 rule "Rule2" {
446 when
447 Order.amount > 1000
448 then
449 Order.high_value = true;
450 }
451 "#;
452
453 let mut engine = IncrementalEngine::new();
454 let count = GrlReteLoader::load_from_string(grl, &mut engine).unwrap();
455
456 assert_eq!(count, 2);
457 }
458}