1use crate::rete::network::{ReteUlNode, build_rete_ul_from_condition_group, evaluate_rete_ul_node};
3use crate::rete::alpha::AlphaNode;
4
5#[derive(Debug, Clone)]
6pub struct Rule {
7 pub name: String,
8 pub conditions: ConditionGroup,
9 pub action: String,
10}
11
12#[derive(Debug, Clone)]
13pub enum ConditionGroup {
14 Single(Condition),
15 Compound {
16 left: Box<ConditionGroup>,
17 operator: String,
18 right: Box<ConditionGroup>,
19 },
20 Not(Box<ConditionGroup>),
21 Exists(Box<ConditionGroup>),
22 Forall(Box<ConditionGroup>),
23}
24
25
26#[derive(Debug, Clone)]
27pub struct Condition {
28 pub field: String,
29 pub operator: String,
30 pub value: String,
31}
32
33pub fn build_rete_ul_from_rule(rule: &Rule) -> ReteUlNode {
35 let cond_node = build_rete_ul_from_condition_group(&rule.conditions);
36 ReteUlNode::UlAnd(Box::new(cond_node), Box::new(ReteUlNode::UlTerminal(rule.name.clone())))
37}
38
39#[cfg(test)]
42mod tests {
43 use super::*;
44 use std::collections::HashMap;
45 use crate::rete::network::evaluate_rete_ul_node;
46
47 #[test]
48 fn test_auto_rete_conversion() {
49 let rule = Rule {
50 name: "ActiveAdult".to_string(),
51 conditions: ConditionGroup::Compound {
52 left: Box::new(ConditionGroup::Single(Condition {
53 field: "status".to_string(),
54 operator: "==".to_string(),
55 value: "active".to_string(),
56 })),
57 operator: "AND".to_string(),
58 right: Box::new(ConditionGroup::Single(Condition {
59 field: "age".to_string(),
60 operator: ">".to_string(),
61 value: "18".to_string(),
62 })),
63 },
64 action: "notify".to_string(),
65 };
66 let rete_node = build_rete_ul_from_rule(&rule);
67 let mut facts = HashMap::new();
68 facts.insert("status".to_string(), "active".to_string());
69 facts.insert("age".to_string(), "20".to_string());
70 let result = evaluate_rete_ul_node(&rete_node, &facts);
71 assert!(result);
72
73 let or_group = ConditionGroup::Compound {
75 left: Box::new(ConditionGroup::Single(Condition {
76 field: "user.status".to_string(),
77 operator: "==".to_string(),
78 value: "active".to_string(),
79 })),
80 operator: "OR".to_string(),
81 right: Box::new(ConditionGroup::Single(Condition {
82 field: "user.age".to_string(),
83 operator: ">".to_string(),
84 value: "18".to_string(),
85 })),
86 };
87 let or_rule = Rule {
88 name: "ActiveOrAdult".to_string(),
89 conditions: or_group,
90 action: "notify".to_string(),
91 };
92 let or_node = build_rete_ul_from_rule(&or_rule);
93 let mut facts2 = HashMap::new();
94 facts2.insert("user.status".to_string(), "inactive".to_string());
95 facts2.insert("user.age".to_string(), "20".to_string());
96 let result_or = evaluate_rete_ul_node(&or_node, &facts2);
97 assert!(result_or);
98
99 let mut facts3 = HashMap::new();
100 facts3.insert("user.status".to_string(), "active".to_string());
101 facts3.insert("user.age".to_string(), "15".to_string());
102 let result_or2 = evaluate_rete_ul_node(&or_node, &facts3);
103 assert!(result_or2);
104
105 let mut facts4 = HashMap::new();
106 facts4.insert("user.status".to_string(), "inactive".to_string());
107 facts4.insert("user.age".to_string(), "15".to_string());
108 let result_or3 = evaluate_rete_ul_node(&or_node, &facts4);
109 assert!(!result_or3);
110 }
111
112 #[test]
113 fn test_exists_forall_and_types() {
114 let exists_group = ConditionGroup::Exists(Box::new(ConditionGroup::Single(Condition {
116 field: "user.age".to_string(),
117 operator: ">".to_string(),
118 value: "18".to_string(),
119 })));
120 let exists_rule = Rule {
121 name: "AnyAdult".to_string(),
122 conditions: exists_group,
123 action: "notify".to_string(),
124 };
125 let exists_node = build_rete_ul_from_rule(&exists_rule);
126 let mut facts = HashMap::new();
127 facts.insert("user1.age".to_string(), "15".to_string());
128 facts.insert("user2.age".to_string(), "22".to_string());
129 facts.insert("user3.age".to_string(), "17".to_string());
130 let result_exists = evaluate_rete_ul_node(&exists_node, &facts);
131 assert!(result_exists);
132
133 let forall_group = ConditionGroup::Forall(Box::new(ConditionGroup::Single(Condition {
135 field: "order.amount".to_string(),
136 operator: ">".to_string(),
137 value: "100".to_string(),
138 })));
139 let forall_rule = Rule {
140 name: "AllBigOrder".to_string(),
141 conditions: forall_group,
142 action: "notify".to_string(),
143 };
144 let forall_node = build_rete_ul_from_rule(&forall_rule);
145 let mut facts2 = HashMap::new();
146 facts2.insert("order1.amount".to_string(), "120".to_string());
147 facts2.insert("order2.amount".to_string(), "150".to_string());
148 facts2.insert("order3.amount".to_string(), "101".to_string());
149 let result_forall = evaluate_rete_ul_node(&forall_node, &facts2);
150 assert!(result_forall);
151
152 let mut facts3 = HashMap::new();
154 facts3.insert("order1.amount".to_string(), "120".to_string());
155 facts3.insert("order2.amount".to_string(), "99".to_string());
156 facts3.insert("order3.amount".to_string(), "101".to_string());
157 let result_forall2 = evaluate_rete_ul_node(&forall_node, &facts3);
158 assert!(!result_forall2);
159
160 let bool_group = ConditionGroup::Single(Condition {
162 field: "user.active".to_string(),
163 operator: "==".to_string(),
164 value: "true".to_string(),
165 });
166 let bool_rule = Rule {
167 name: "UserActive".to_string(),
168 conditions: bool_group,
169 action: "notify".to_string(),
170 };
171 let bool_node = build_rete_ul_from_rule(&bool_rule);
172 let mut facts4 = HashMap::new();
173 facts4.insert("user.active".to_string(), "true".to_string());
174 let result_bool = evaluate_rete_ul_node(&bool_node, &facts4);
175 assert!(result_bool);
176 facts4.insert("user.active".to_string(), "false".to_string());
177 let result_bool2 = evaluate_rete_ul_node(&bool_node, &facts4);
178 assert!(!result_bool2);
179 }
180}