Files
wifi-densepose/vendor/ruvector/crates/ruvector-graph-node/src/transactions.rs

162 lines
4.2 KiB
Rust

//! Transaction support for graph database operations
use std::collections::HashMap;
use uuid::Uuid;
/// Transaction state
#[derive(Debug, Clone)]
pub enum TransactionState {
Active,
Committed,
RolledBack,
}
/// Transaction metadata
#[derive(Debug, Clone)]
pub struct Transaction {
pub id: String,
pub state: TransactionState,
pub operations: Vec<String>,
}
/// Transaction manager
pub struct TransactionManager {
transactions: HashMap<String, Transaction>,
}
impl TransactionManager {
/// Create a new transaction manager
pub fn new() -> Self {
Self {
transactions: HashMap::new(),
}
}
/// Begin a new transaction
pub fn begin(&mut self) -> String {
let tx_id = Uuid::new_v4().to_string();
let tx = Transaction {
id: tx_id.clone(),
state: TransactionState::Active,
operations: Vec::new(),
};
self.transactions.insert(tx_id.clone(), tx);
tx_id
}
/// Commit a transaction
pub fn commit(&mut self, tx_id: &str) -> Result<(), String> {
let tx = self
.transactions
.get_mut(tx_id)
.ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
match tx.state {
TransactionState::Active => {
tx.state = TransactionState::Committed;
Ok(())
}
TransactionState::Committed => Err("Transaction already committed".to_string()),
TransactionState::RolledBack => Err("Transaction already rolled back".to_string()),
}
}
/// Rollback a transaction
pub fn rollback(&mut self, tx_id: &str) -> Result<(), String> {
let tx = self
.transactions
.get_mut(tx_id)
.ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
match tx.state {
TransactionState::Active => {
tx.state = TransactionState::RolledBack;
Ok(())
}
TransactionState::Committed => Err("Cannot rollback committed transaction".to_string()),
TransactionState::RolledBack => Err("Transaction already rolled back".to_string()),
}
}
/// Add an operation to a transaction
pub fn add_operation(&mut self, tx_id: &str, operation: String) -> Result<(), String> {
let tx = self
.transactions
.get_mut(tx_id)
.ok_or_else(|| format!("Transaction not found: {}", tx_id))?;
match tx.state {
TransactionState::Active => {
tx.operations.push(operation);
Ok(())
}
_ => Err("Transaction is not active".to_string()),
}
}
/// Get transaction state
pub fn get_state(&self, tx_id: &str) -> Option<TransactionState> {
self.transactions.get(tx_id).map(|tx| tx.state.clone())
}
/// Clean up old transactions
pub fn cleanup(&mut self) {
self.transactions
.retain(|_, tx| matches!(tx.state, TransactionState::Active));
}
}
impl Default for TransactionManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transaction_lifecycle() {
let mut tm = TransactionManager::new();
// Begin transaction
let tx_id = tm.begin();
assert!(matches!(
tm.get_state(&tx_id),
Some(TransactionState::Active)
));
// Add operation
tm.add_operation(&tx_id, "CREATE NODE".to_string()).unwrap();
// Commit
tm.commit(&tx_id).unwrap();
assert!(matches!(
tm.get_state(&tx_id),
Some(TransactionState::Committed)
));
// Cannot commit again
assert!(tm.commit(&tx_id).is_err());
}
#[test]
fn test_transaction_rollback() {
let mut tm = TransactionManager::new();
let tx_id = tm.begin();
tm.add_operation(&tx_id, "CREATE NODE".to_string()).unwrap();
// Rollback
tm.rollback(&tx_id).unwrap();
assert!(matches!(
tm.get_state(&tx_id),
Some(TransactionState::RolledBack)
));
// Cannot rollback again
assert!(tm.rollback(&tx_id).is_err());
}
}