1use crate::engine::rule::Rule;
2use crate::errors::{Result, RuleEngineError};
3use crate::parser::grl::GRLParser;
4use crate::types::Value;
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7
8#[derive(Debug)]
11pub struct KnowledgeBase {
12 name: String,
13 rules: Arc<RwLock<Vec<Rule>>>,
14 rule_index: Arc<RwLock<HashMap<String, usize>>>,
15 version: Arc<RwLock<u64>>,
16}
17
18impl KnowledgeBase {
19 pub fn new(name: &str) -> Self {
21 Self {
22 name: name.to_string(),
23 rules: Arc::new(RwLock::new(Vec::new())),
24 rule_index: Arc::new(RwLock::new(HashMap::new())),
25 version: Arc::new(RwLock::new(0)),
26 }
27 }
28
29 pub fn name(&self) -> &str {
31 &self.name
32 }
33
34 pub fn version(&self) -> u64 {
36 *self.version.read().unwrap()
37 }
38
39 pub fn add_rule(&self, rule: Rule) -> Result<()> {
41 let mut rules = self.rules.write().unwrap();
42 let mut index = self.rule_index.write().unwrap();
43 let mut version = self.version.write().unwrap();
44
45 if index.contains_key(&rule.name) {
47 return Err(RuleEngineError::ParseError {
48 message: format!("Rule '{}' already exists", rule.name),
49 });
50 }
51
52 let rule_position = rules.len();
53 index.insert(rule.name.clone(), rule_position);
54 rules.push(rule);
55
56 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
58
59 index.clear();
61 for (pos, rule) in rules.iter().enumerate() {
62 index.insert(rule.name.clone(), pos);
63 }
64
65 *version += 1;
66 Ok(())
67 }
68
69 pub fn add_rules_from_grl(&self, grl_text: &str) -> Result<usize> {
71 let rules = GRLParser::parse_rules(grl_text)?;
72 let count = rules.len();
73
74 for rule in rules {
75 self.add_rule(rule)?;
76 }
77
78 Ok(count)
79 }
80
81 pub fn remove_rule(&self, rule_name: &str) -> Result<bool> {
83 let mut rules = self.rules.write().unwrap();
84 let mut index = self.rule_index.write().unwrap();
85 let mut version = self.version.write().unwrap();
86
87 if let Some(&position) = index.get(rule_name) {
88 rules.remove(position);
89
90 index.clear();
92 for (pos, rule) in rules.iter().enumerate() {
93 index.insert(rule.name.clone(), pos);
94 }
95
96 *version += 1;
97 Ok(true)
98 } else {
99 Ok(false)
100 }
101 }
102
103 pub fn get_rule(&self, rule_name: &str) -> Option<Rule> {
105 let rules = self.rules.read().unwrap();
106 let index = self.rule_index.read().unwrap();
107
108 if let Some(&position) = index.get(rule_name) {
109 rules.get(position).cloned()
110 } else {
111 None
112 }
113 }
114
115 pub fn get_rules(&self) -> Vec<Rule> {
117 let rules = self.rules.read().unwrap();
118 rules.clone()
119 }
120
121 pub fn get_rule_names(&self) -> Vec<String> {
123 let index = self.rule_index.read().unwrap();
124 index.keys().cloned().collect()
125 }
126
127 pub fn rule_count(&self) -> usize {
129 let rules = self.rules.read().unwrap();
130 rules.len()
131 }
132
133 pub fn set_rule_enabled(&self, rule_name: &str, enabled: bool) -> Result<bool> {
135 let mut rules = self.rules.write().unwrap();
136 let index = self.rule_index.read().unwrap();
137 let mut version = self.version.write().unwrap();
138
139 if let Some(&position) = index.get(rule_name) {
140 if let Some(rule) = rules.get_mut(position) {
141 rule.enabled = enabled;
142 *version += 1;
143 Ok(true)
144 } else {
145 Ok(false)
146 }
147 } else {
148 Ok(false)
149 }
150 }
151
152 pub fn clear(&self) {
154 let mut rules = self.rules.write().unwrap();
155 let mut index = self.rule_index.write().unwrap();
156 let mut version = self.version.write().unwrap();
157
158 rules.clear();
159 index.clear();
160 *version += 1;
161 }
162
163 pub fn get_rules_snapshot(&self) -> Vec<Rule> {
165 let rules = self.rules.read().unwrap();
166 rules.clone()
167 }
168
169 pub fn get_statistics(&self) -> KnowledgeBaseStats {
171 let rules = self.rules.read().unwrap();
172
173 let enabled_count = rules.iter().filter(|r| r.enabled).count();
174 let disabled_count = rules.len() - enabled_count;
175
176 let mut priority_distribution = HashMap::new();
177 for rule in rules.iter() {
178 *priority_distribution.entry(rule.salience).or_insert(0) += 1;
179 }
180
181 KnowledgeBaseStats {
182 name: self.name.clone(),
183 version: self.version(),
184 total_rules: rules.len(),
185 enabled_rules: enabled_count,
186 disabled_rules: disabled_count,
187 priority_distribution,
188 }
189 }
190
191 pub fn export_to_grl(&self) -> String {
193 let rules = self.rules.read().unwrap();
194 let mut grl_output = String::new();
195
196 grl_output.push_str(&format!("// Knowledge Base: {}\n", self.name));
197 grl_output.push_str(&format!("// Version: {}\n", self.version()));
198 grl_output.push_str(&format!("// Rules: {}\n\n", rules.len()));
199
200 for rule in rules.iter() {
201 grl_output.push_str(&rule.to_grl());
202 grl_output.push_str("\n\n");
203 }
204
205 grl_output
206 }
207}
208
209impl Clone for KnowledgeBase {
210 fn clone(&self) -> Self {
211 let rules = self.rules.read().unwrap();
212 let new_kb = KnowledgeBase::new(&self.name);
213
214 for rule in rules.iter() {
215 let _ = new_kb.add_rule(rule.clone());
216 }
217
218 new_kb
219 }
220}
221
222#[derive(Debug, Clone)]
224pub struct KnowledgeBaseStats {
225 pub name: String,
227 pub version: u64,
229 pub total_rules: usize,
231 pub enabled_rules: usize,
233 pub disabled_rules: usize,
235 pub priority_distribution: HashMap<i32, usize>,
237}
238
239impl std::fmt::Display for KnowledgeBaseStats {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 writeln!(f, "Knowledge Base: {}", self.name)?;
242 writeln!(f, "Version: {}", self.version)?;
243 writeln!(f, "Total Rules: {}", self.total_rules)?;
244 writeln!(f, "Enabled Rules: {}", self.enabled_rules)?;
245 writeln!(f, "Disabled Rules: {}", self.disabled_rules)?;
246 writeln!(f, "Priority Distribution:")?;
247
248 let mut priorities: Vec<_> = self.priority_distribution.iter().collect();
249 priorities.sort_by(|a, b| b.0.cmp(a.0));
250
251 for (priority, count) in priorities {
252 writeln!(f, " Priority {}: {} rules", priority, count)?;
253 }
254
255 Ok(())
256 }
257}
258
259trait RuleGRLExport {
261 fn to_grl(&self) -> String;
262}
263
264impl RuleGRLExport for Rule {
265 fn to_grl(&self) -> String {
266 let mut grl = String::new();
267
268 grl.push_str(&format!("rule {}", self.name));
270
271 if let Some(ref description) = self.description {
272 grl.push_str(&format!(" \"{}\"", description));
273 }
274
275 if self.salience != 0 {
276 grl.push_str(&format!(" salience {}", self.salience));
277 }
278
279 grl.push_str(" {\n");
280
281 grl.push_str(" when\n");
283 grl.push_str(&format!(" {}\n", self.conditions.to_grl()));
284
285 grl.push_str(" then\n");
287 for action in &self.actions {
288 grl.push_str(&format!(" {};\n", action.to_grl()));
289 }
290
291 grl.push('}');
292
293 if !self.enabled {
294 grl = format!("// DISABLED\n{}", grl);
295 }
296
297 grl
298 }
299}
300
301trait ConditionGroupGRLExport {
303 fn to_grl(&self) -> String;
304}
305
306impl ConditionGroupGRLExport for crate::engine::rule::ConditionGroup {
307 fn to_grl(&self) -> String {
308 match self {
309 crate::engine::rule::ConditionGroup::Single(condition) => {
310 format!(
311 "{} {} {}",
312 condition.field,
313 condition.operator.to_grl(),
314 condition.value.to_grl()
315 )
316 }
317 crate::engine::rule::ConditionGroup::Compound {
318 left,
319 operator,
320 right,
321 } => {
322 let op_str = match operator {
323 crate::types::LogicalOperator::And => "&&",
324 crate::types::LogicalOperator::Or => "||",
325 crate::types::LogicalOperator::Not => "!",
326 };
327 format!("{} {} {}", left.to_grl(), op_str, right.to_grl())
328 }
329 crate::engine::rule::ConditionGroup::Not(condition) => {
330 format!("!{}", condition.to_grl())
331 }
332 }
333 }
334}
335
336trait OperatorGRLExport {
338 fn to_grl(&self) -> &'static str;
339}
340
341impl OperatorGRLExport for crate::types::Operator {
342 fn to_grl(&self) -> &'static str {
343 match self {
344 crate::types::Operator::Equal => "==",
345 crate::types::Operator::NotEqual => "!=",
346 crate::types::Operator::GreaterThan => ">",
347 crate::types::Operator::GreaterThanOrEqual => ">=",
348 crate::types::Operator::LessThan => "<",
349 crate::types::Operator::LessThanOrEqual => "<=",
350 crate::types::Operator::Contains => "contains",
351 crate::types::Operator::NotContains => "not_contains",
352 crate::types::Operator::StartsWith => "starts_with",
353 crate::types::Operator::EndsWith => "ends_with",
354 crate::types::Operator::Matches => "matches",
355 }
356 }
357}
358
359trait ValueGRLExport {
361 fn to_grl(&self) -> String;
362}
363
364impl ValueGRLExport for Value {
365 fn to_grl(&self) -> String {
366 match self {
367 Value::String(s) => format!("\"{}\"", s),
368 Value::Number(n) => n.to_string(),
369 Value::Integer(i) => i.to_string(),
370 Value::Boolean(b) => b.to_string(),
371 Value::Null => "null".to_string(),
372 Value::Array(_) => "[array]".to_string(),
373 Value::Object(_) => "{object}".to_string(),
374 }
375 }
376}
377
378trait ActionTypeGRLExport {
380 fn to_grl(&self) -> String;
381}
382
383impl ActionTypeGRLExport for crate::types::ActionType {
384 fn to_grl(&self) -> String {
385 match self {
386 crate::types::ActionType::Set { field, value } => {
387 format!("{} = {}", field, value.to_grl())
388 }
389 crate::types::ActionType::Log { message } => {
390 format!("Log(\"{}\")", message)
391 }
392 crate::types::ActionType::MethodCall {
393 object,
394 method,
395 args,
396 } => {
397 let args_str = args
398 .iter()
399 .map(|arg| arg.to_grl())
400 .collect::<Vec<_>>()
401 .join(", ");
402 format!("{}.{}({})", object, method, args_str)
403 }
404 crate::types::ActionType::Update { object } => {
405 format!("update({})", object)
406 }
407 crate::types::ActionType::Call { function, args } => {
408 let args_str = args
409 .iter()
410 .map(|arg| arg.to_grl())
411 .collect::<Vec<_>>()
412 .join(", ");
413 format!("{}({})", function, args_str)
414 }
415 crate::types::ActionType::Custom { action_type, .. } => {
416 format!("Custom(\"{}\")", action_type)
417 }
418 }
419 }
420}