ruvector_graph_node/
transactions.rs1use std::collections::HashMap;
4use uuid::Uuid;
5
6#[derive(Debug, Clone)]
8pub enum TransactionState {
9 Active,
10 Committed,
11 RolledBack,
12}
13
14#[derive(Debug, Clone)]
16pub struct Transaction {
17 pub id: String,
18 pub state: TransactionState,
19 pub operations: Vec<String>,
20}
21
22pub struct TransactionManager {
24 transactions: HashMap<String, Transaction>,
25}
26
27impl TransactionManager {
28 pub fn new() -> Self {
30 Self {
31 transactions: HashMap::new(),
32 }
33 }
34
35 pub fn begin(&mut self) -> String {
37 let tx_id = Uuid::new_v4().to_string();
38 let tx = Transaction {
39 id: tx_id.clone(),
40 state: TransactionState::Active,
41 operations: Vec::new(),
42 };
43 self.transactions.insert(tx_id.clone(), tx);
44 tx_id
45 }
46
47 pub fn commit(&mut self, tx_id: &str) -> Result<(), String> {
49 let tx = self
50 .transactions
51 .get_mut(tx_id)
52 .ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
53
54 match tx.state {
55 TransactionState::Active => {
56 tx.state = TransactionState::Committed;
57 Ok(())
58 }
59 TransactionState::Committed => Err("Transaction already committed".to_string()),
60 TransactionState::RolledBack => Err("Transaction already rolled back".to_string()),
61 }
62 }
63
64 pub fn rollback(&mut self, tx_id: &str) -> Result<(), String> {
66 let tx = self
67 .transactions
68 .get_mut(tx_id)
69 .ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
70
71 match tx.state {
72 TransactionState::Active => {
73 tx.state = TransactionState::RolledBack;
74 Ok(())
75 }
76 TransactionState::Committed => Err("Cannot rollback committed transaction".to_string()),
77 TransactionState::RolledBack => Err("Transaction already rolled back".to_string()),
78 }
79 }
80
81 pub fn add_operation(&mut self, tx_id: &str, operation: String) -> Result<(), String> {
83 let tx = self
84 .transactions
85 .get_mut(tx_id)
86 .ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
87
88 match tx.state {
89 TransactionState::Active => {
90 tx.operations.push(operation);
91 Ok(())
92 }
93 _ => Err("Transaction is not active".to_string()),
94 }
95 }
96
97 pub fn get_state(&self, tx_id: &str) -> Option<TransactionState> {
99 self.transactions.get(tx_id).map(|tx| tx.state.clone())
100 }
101
102 pub fn cleanup(&mut self) {
104 self.transactions
105 .retain(|_, tx| matches!(tx.state, TransactionState::Active));
106 }
107}
108
109impl Default for TransactionManager {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_transaction_lifecycle() {
121 let mut tm = TransactionManager::new();
122
123 let tx_id = tm.begin();
125 assert!(matches!(
126 tm.get_state(&tx_id),
127 Some(TransactionState::Active)
128 ));
129
130 tm.add_operation(&tx_id, "CREATE NODE".to_string()).unwrap();
132
133 tm.commit(&tx_id).unwrap();
135 assert!(matches!(
136 tm.get_state(&tx_id),
137 Some(TransactionState::Committed)
138 ));
139
140 assert!(tm.commit(&tx_id).is_err());
142 }
143
144 #[test]
145 fn test_transaction_rollback() {
146 let mut tm = TransactionManager::new();
147
148 let tx_id = tm.begin();
149 tm.add_operation(&tx_id, "CREATE NODE".to_string()).unwrap();
150
151 tm.rollback(&tx_id).unwrap();
153 assert!(matches!(
154 tm.get_state(&tx_id),
155 Some(TransactionState::RolledBack)
156 ));
157
158 assert!(tm.rollback(&tx_id).is_err());
160 }
161}