rust_rule_miner/
transaction.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// A transaction (shopping cart, event sequence, etc.)
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Transaction {
8    pub id: String,
9    pub timestamp: DateTime<Utc>,
10    pub items: Vec<String>,
11    pub user_id: Option<String>,
12    pub metadata: HashMap<String, serde_json::Value>,
13}
14
15impl Transaction {
16    /// Create a new transaction
17    pub fn new<S: Into<String>>(id: S, items: Vec<String>, timestamp: DateTime<Utc>) -> Self {
18        Self {
19            id: id.into(),
20            timestamp,
21            items,
22            user_id: None,
23            metadata: HashMap::new(),
24        }
25    }
26
27    /// Create transaction with user ID
28    pub fn with_user<S: Into<String>>(
29        id: S,
30        items: Vec<String>,
31        timestamp: DateTime<Utc>,
32        user_id: S,
33    ) -> Self {
34        Self {
35            id: id.into(),
36            timestamp,
37            items,
38            user_id: Some(user_id.into()),
39            metadata: HashMap::new(),
40        }
41    }
42
43    /// Add metadata to transaction
44    pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
45        self.metadata = metadata;
46        self
47    }
48
49    /// Check if transaction contains an item
50    pub fn contains(&self, item: &str) -> bool {
51        self.items.iter().any(|i| i == item)
52    }
53
54    /// Check if transaction contains all items
55    pub fn contains_all(&self, items: &[String]) -> bool {
56        items.iter().all(|item| self.contains(item))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_transaction_creation() {
66        let tx = Transaction::new("tx1", vec!["A".to_string(), "B".to_string()], Utc::now());
67        assert_eq!(tx.id, "tx1");
68        assert_eq!(tx.items.len(), 2);
69    }
70
71    #[test]
72    fn test_transaction_contains() {
73        let tx = Transaction::new(
74            "tx1",
75            vec!["Laptop".to_string(), "Mouse".to_string()],
76            Utc::now(),
77        );
78        assert!(tx.contains("Laptop"));
79        assert!(!tx.contains("Keyboard"));
80    }
81
82    #[test]
83    fn test_transaction_contains_all() {
84        let tx = Transaction::new(
85            "tx1",
86            vec!["A".to_string(), "B".to_string(), "C".to_string()],
87            Utc::now(),
88        );
89        assert!(tx.contains_all(&["A".to_string(), "B".to_string()]));
90        assert!(!tx.contains_all(&["A".to_string(), "D".to_string()]));
91    }
92}