ecommerce/
ecommerce.rs

1use rust_rule_engine::engine::facts::Facts;
2use rust_rule_engine::engine::knowledge_base::KnowledgeBase;
3use rust_rule_engine::engine::rule::{Condition, ConditionGroup, Rule};
4use rust_rule_engine::engine::{EngineConfig, RustRuleEngine};
5use rust_rule_engine::types::{ActionType, Operator, Value};
6use std::collections::HashMap;
7
8fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
9    println!("=== E-commerce Rules Demo ===");
10    println!("==============================\n");
11
12    // Create customer data
13    let mut customer_props = HashMap::new();
14    customer_props.insert("IsNew".to_string(), Value::Boolean(true));
15    customer_props.insert(
16        "Membership".to_string(),
17        Value::String("standard".to_string()),
18    );
19    customer_props.insert("TotalSpent".to_string(), Value::Number(750.0));
20    customer_props.insert("WelcomeEmailSent".to_string(), Value::Boolean(false));
21
22    // Create order data
23    let mut order_props = HashMap::new();
24    order_props.insert("Total".to_string(), Value::Number(75.0));
25    order_props.insert("ItemCount".to_string(), Value::Integer(2));
26    order_props.insert(
27        "Category".to_string(),
28        Value::String("clothing".to_string()),
29    );
30    order_props.insert("DiscountRate".to_string(), Value::Number(0.0));
31    order_props.insert("FreeShipping".to_string(), Value::Boolean(false));
32    order_props.insert(
33        "DiscountType".to_string(),
34        Value::String("none".to_string()),
35    );
36
37    // Create promotion data
38    let mut promotion_props = HashMap::new();
39    promotion_props.insert("SeasonalDiscount".to_string(), Value::Number(0.05));
40    promotion_props.insert("BulkDiscount".to_string(), Value::Number(0.10));
41    promotion_props.insert("Active".to_string(), Value::Boolean(true));
42
43    // Create facts
44    let facts = Facts::new();
45    facts.add_value("Customer", Value::Object(customer_props))?;
46    facts.add_value("Order", Value::Object(order_props))?;
47    facts.add_value("Promotion", Value::Object(promotion_props))?;
48
49    println!("šŸ Initial e-commerce data:");
50    if let Some(customer) = facts.get("Customer") {
51        println!("   Customer = {customer:?}");
52    }
53    if let Some(order) = facts.get("Order") {
54        println!("   Order = {order:?}");
55    }
56    if let Some(promotion) = facts.get("Promotion") {
57        println!("   Promotion = {promotion:?}");
58    }
59    println!();
60
61    // Create knowledge base
62    let mut kb = KnowledgeBase::new("EcommerceRules");
63
64    // Rule 1: New Customer Discount (salience 25)
65    let new_customer_rule = Rule::new(
66        "NewCustomerDiscount".to_string(),
67        ConditionGroup::and(
68            ConditionGroup::single(Condition::new(
69                "Customer.IsNew".to_string(),
70                Operator::Equal,
71                Value::Boolean(true),
72            )),
73            ConditionGroup::single(Condition::new(
74                "Order.Total".to_string(),
75                Operator::GreaterThan,
76                Value::Number(50.0),
77            )),
78        ),
79        vec![
80            ActionType::MethodCall {
81                object: "Order".to_string(),
82                method: "setDiscountRate".to_string(),
83                args: vec![Value::Number(0.10)],
84            },
85            ActionType::MethodCall {
86                object: "Order".to_string(),
87                method: "setDiscountType".to_string(),
88                args: vec![Value::String("welcome".to_string())],
89            },
90            ActionType::MethodCall {
91                object: "Customer".to_string(),
92                method: "setWelcomeEmailSent".to_string(),
93                args: vec![Value::Boolean(true)],
94            },
95            ActionType::Call {
96                function: "log".to_string(),
97                args: vec![Value::String(
98                    "New customer welcome discount applied".to_string(),
99                )],
100            },
101        ],
102    )
103    .with_salience(25);
104
105    // Rule 2: Premium Member Benefits (salience 20)
106    let premium_member_rule = Rule::new(
107        "PremiumMemberBenefits".to_string(),
108        ConditionGroup::and(
109            ConditionGroup::single(Condition::new(
110                "Customer.Membership".to_string(),
111                Operator::Equal,
112                Value::String("premium".to_string()),
113            )),
114            ConditionGroup::single(Condition::new(
115                "Order.Total".to_string(),
116                Operator::GreaterThan,
117                Value::Number(100.0),
118            )),
119        ),
120        vec![
121            ActionType::MethodCall {
122                object: "Order".to_string(),
123                method: "setDiscountRate".to_string(),
124                args: vec![Value::Number(0.15)],
125            },
126            ActionType::MethodCall {
127                object: "Order".to_string(),
128                method: "setFreeShipping".to_string(),
129                args: vec![Value::Boolean(true)],
130            },
131            ActionType::Call {
132                function: "log".to_string(),
133                args: vec![Value::String("Premium member benefits applied".to_string())],
134            },
135        ],
136    )
137    .with_salience(20);
138
139    // Rule 3: VIP Upgrade (salience 30)
140    let vip_upgrade_rule = Rule::new(
141        "VIPUpgrade".to_string(),
142        ConditionGroup::and(
143            ConditionGroup::single(Condition::new(
144                "Customer.TotalSpent".to_string(),
145                Operator::GreaterThan,
146                Value::Number(1000.0),
147            )),
148            ConditionGroup::single(Condition::new(
149                "Customer.Membership".to_string(),
150                Operator::NotEqual,
151                Value::String("VIP".to_string()),
152            )),
153        ),
154        vec![
155            ActionType::MethodCall {
156                object: "Customer".to_string(),
157                method: "setMembership".to_string(),
158                args: vec![Value::String("VIP".to_string())],
159            },
160            ActionType::MethodCall {
161                object: "Order".to_string(),
162                method: "setDiscountRate".to_string(),
163                args: vec![Value::Number(0.25)],
164            },
165            ActionType::Call {
166                function: "log".to_string(),
167                args: vec![Value::String(
168                    "Customer upgraded to VIP membership".to_string(),
169                )],
170            },
171        ],
172    )
173    .with_salience(30);
174
175    // Rule 4: Free Shipping for Large Orders (salience 15)
176    let free_shipping_rule = Rule::new(
177        "FreeShippingLargeOrders".to_string(),
178        ConditionGroup::single(Condition::new(
179            "Order.Total".to_string(),
180            Operator::GreaterThanOrEqual,
181            Value::Number(100.0),
182        )),
183        vec![
184            ActionType::MethodCall {
185                object: "Order".to_string(),
186                method: "setFreeShipping".to_string(),
187                args: vec![Value::Boolean(true)],
188            },
189            ActionType::Call {
190                function: "log".to_string(),
191                args: vec![Value::String(
192                    "Free shipping applied for large order".to_string(),
193                )],
194            },
195        ],
196    )
197    .with_salience(15);
198
199    // Rule 5: Bulk Discount (salience 12)
200    let bulk_discount_rule = Rule::new(
201        "BulkDiscount".to_string(),
202        ConditionGroup::single(Condition::new(
203            "Order.ItemCount".to_string(),
204            Operator::GreaterThanOrEqual,
205            Value::Integer(5),
206        )),
207        vec![
208            ActionType::Call {
209                function: "max".to_string(),
210                args: vec![
211                    Value::String("Order.DiscountRate".to_string()),
212                    Value::Number(0.10),
213                ],
214            },
215            ActionType::Call {
216                function: "log".to_string(),
217                args: vec![Value::String("Bulk discount applied".to_string())],
218            },
219        ],
220    )
221    .with_salience(12);
222
223    // Rule 6: Seasonal Promotion (salience 10)
224    let seasonal_promotion_rule = Rule::new(
225        "SeasonalPromotion".to_string(),
226        ConditionGroup::and(
227            ConditionGroup::single(Condition::new(
228                "Promotion.Active".to_string(),
229                Operator::Equal,
230                Value::Boolean(true),
231            )),
232            ConditionGroup::single(Condition::new(
233                "Order.Category".to_string(),
234                Operator::Equal,
235                Value::String("clothing".to_string()),
236            )),
237        ),
238        vec![
239            ActionType::Call {
240                function: "max".to_string(),
241                args: vec![
242                    Value::String("Order.DiscountRate".to_string()),
243                    Value::String("Promotion.SeasonalDiscount".to_string()),
244                ],
245            },
246            ActionType::Call {
247                function: "log".to_string(),
248                args: vec![Value::String("Seasonal promotion applied".to_string())],
249            },
250        ],
251    )
252    .with_salience(10);
253
254    // Add rules to knowledge base
255    let _ = kb.add_rule(new_customer_rule);
256    let _ = kb.add_rule(premium_member_rule);
257    let _ = kb.add_rule(vip_upgrade_rule);
258    let _ = kb.add_rule(free_shipping_rule);
259    let _ = kb.add_rule(bulk_discount_rule);
260    let _ = kb.add_rule(seasonal_promotion_rule);
261
262    println!(
263        "šŸ“š Knowledge Base loaded with {} rules",
264        kb.get_statistics().total_rules
265    );
266    println!("šŸ”„ Rules: {:?}\n", kb.get_rule_names());
267
268    // Create engine with debug mode
269    let config = EngineConfig {
270        debug_mode: true,
271        max_cycles: 5,
272        ..Default::default()
273    };
274    let engine = RustRuleEngine::with_config(kb, config);
275
276    // Execute rules
277    println!("šŸš€ Executing e-commerce rules...");
278    let result = engine.execute(&facts)?;
279
280    println!("\nšŸ“Š E-commerce Execution Results:");
281    println!("   Cycles: {}", result.cycle_count);
282    println!("   Rules evaluated: {}", result.rules_evaluated);
283    println!("   Rules fired: {}", result.rules_fired);
284    println!("   Execution time: {:?}", result.execution_time);
285
286    println!("\nšŸ Final e-commerce state:");
287    if let Some(customer) = facts.get("Customer") {
288        println!("   Customer = {customer:?}");
289    }
290    if let Some(order) = facts.get("Order") {
291        println!("   Order = {order:?}");
292    }
293    if let Some(promotion) = facts.get("Promotion") {
294        println!("   Promotion = {promotion:?}");
295    }
296
297    println!("\nšŸŽÆ E-commerce Rules Demonstrated:");
298    println!("   šŸŽ New Customer Welcome Discount");
299    println!("   šŸ’Ž Premium Member Benefits");
300    println!("   🌟 VIP Membership Upgrades");
301    println!("   🚚 Free Shipping Rules");
302    println!("   šŸ“¦ Bulk Purchase Discounts");
303    println!("   šŸ·ļø Seasonal Promotions");
304
305    Ok(())
306}