use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TransactionId(u64);
impl TransactionId {
pub fn new() -> Self {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos() as u64;
TransactionId(timestamp)
}
pub fn id(&self) -> u64 {
self.0
}
pub fn from_u64(id: u64) -> Self {
TransactionId(id)
}
}
impl std::fmt::Display for TransactionId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "txn_{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TransactionStatus {
Active,
Preparing,
Committed,
RolledBack,
Failed(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AccessMode {
ReadOnly,
ReadWrite,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TxnIsolationLevel {
ReadUncommitted,
ReadCommitted,
RepeatableRead,
Serializable,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionState {
pub id: TransactionId,
pub session_id: Option<String>,
pub status: TransactionStatus,
pub isolation_level: TxnIsolationLevel,
pub access_mode: AccessMode,
pub start_time: SystemTime,
pub end_time: Option<SystemTime>,
pub operations: Vec<TransactionOperation>,
pub sequence_number: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionOperation {
pub operation_type: OperationType,
pub timestamp: SystemTime,
pub description: String,
pub sequence_number: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum OperationType {
Select,
Match,
Insert,
Update,
Set,
Delete,
Remove,
CreateTable,
CreateGraph,
AlterTable,
DropTable,
DropGraph,
CreateUser,
DropUser,
CreateRole,
DropRole,
GrantRole,
RevokeRole,
Begin,
Commit,
Rollback,
Other,
}
impl TransactionState {
pub fn new(isolation_level: TxnIsolationLevel, access_mode: AccessMode) -> Self {
Self {
id: TransactionId::new(),
session_id: None,
status: TransactionStatus::Active,
isolation_level,
access_mode,
start_time: SystemTime::now(),
end_time: None,
operations: Vec::new(),
sequence_number: 0,
}
}
pub fn new_with_session(
isolation_level: TxnIsolationLevel,
access_mode: AccessMode,
session_id: String,
) -> Self {
Self {
id: TransactionId::new(),
session_id: Some(session_id),
status: TransactionStatus::Active,
isolation_level,
access_mode,
start_time: SystemTime::now(),
end_time: None,
operations: Vec::new(),
sequence_number: 0,
}
}
pub fn add_operation(&mut self, operation_type: OperationType, description: String) {
if matches!(
operation_type,
OperationType::Insert
| OperationType::Update
| OperationType::Set
| OperationType::Delete
| OperationType::Remove
) {
self.sequence_number += 1;
}
self.operations.push(TransactionOperation {
operation_type,
timestamp: SystemTime::now(),
description,
sequence_number: self.sequence_number,
});
}
pub fn commit(&mut self) {
self.status = TransactionStatus::Committed;
self.end_time = Some(SystemTime::now());
}
pub fn rollback(&mut self) {
self.status = TransactionStatus::RolledBack;
self.end_time = Some(SystemTime::now());
}
pub fn fail(&mut self, error: String) {
self.status = TransactionStatus::Failed(error);
self.end_time = Some(SystemTime::now());
}
pub fn is_active(&self) -> bool {
self.status == TransactionStatus::Active
}
pub fn is_read_only(&self) -> bool {
self.access_mode == AccessMode::ReadOnly
}
pub fn duration(&self) -> std::time::Duration {
let end_time = self.end_time.unwrap_or_else(SystemTime::now);
end_time.duration_since(self.start_time).unwrap_or_default()
}
pub fn get_sequence_number(&self) -> u64 {
self.sequence_number
}
}
impl Default for TransactionState {
fn default() -> Self {
Self::new(TxnIsolationLevel::ReadCommitted, AccessMode::ReadWrite)
}
}