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