uvb_storage_memory/
transaction.rs1use async_trait::async_trait;
2use std::collections::HashMap;
3use std::sync::Arc;
4use std::time::SystemTime;
5use tokio::sync::RwLock;
6use uvb_storage_api::{TransactionError, TransactionRecord, TransactionStatus, TransactionStore};
7
8pub struct InMemoryTransactionStore {
10 transactions: Arc<RwLock<HashMap<String, TransactionRecord>>>,
11}
12
13impl InMemoryTransactionStore {
14 pub fn new() -> Self {
15 Self {
16 transactions: Arc::new(RwLock::new(HashMap::new())),
17 }
18 }
19}
20
21impl Default for InMemoryTransactionStore {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27#[async_trait]
28impl TransactionStore for InMemoryTransactionStore {
29 async fn create(&self, record: TransactionRecord) -> Result<(), TransactionError> {
30 let mut txns = self.transactions.write().await;
31 txns.insert(record.id.clone(), record);
32 Ok(())
33 }
34
35 async fn get(&self, id: &str) -> Result<Option<TransactionRecord>, TransactionError> {
36 let txns = self.transactions.read().await;
37 Ok(txns.get(id).cloned())
38 }
39
40 async fn update(&self, record: TransactionRecord) -> Result<(), TransactionError> {
41 let mut txns = self.transactions.write().await;
42 if !txns.contains_key(&record.id) {
43 return Err(TransactionError::NotFound);
44 }
45 txns.insert(record.id.clone(), record);
46 Ok(())
47 }
48
49 async fn delete(&self, id: &str) -> Result<(), TransactionError> {
50 let mut txns = self.transactions.write().await;
51 txns.remove(id).ok_or(TransactionError::NotFound)?;
52 Ok(())
53 }
54
55 async fn list_by_user(
56 &self,
57 user_id: &str,
58 limit: usize,
59 ) -> Result<Vec<TransactionRecord>, TransactionError> {
60 let txns = self.transactions.read().await;
61 let mut results: Vec<TransactionRecord> = txns
62 .values()
63 .filter(|t| t.subject.user_id == user_id)
64 .cloned()
65 .collect();
66
67 results.sort_by_key(|a| std::cmp::Reverse(a.created_at));
69 results.truncate(limit);
70
71 Ok(results)
72 }
73
74 async fn cleanup_expired(&self) -> Result<usize, TransactionError> {
75 let mut txns = self.transactions.write().await;
76 let now = SystemTime::now();
77
78 let expired_ids: Vec<String> = txns
79 .iter()
80 .filter(|(_, t)| t.expires_at <= now && t.status != TransactionStatus::Succeeded)
81 .map(|(id, _)| id.clone())
82 .collect();
83
84 let count = expired_ids.len();
85 for id in expired_ids {
86 if let Some(txn) = txns.get_mut(&id) {
87 txn.status = TransactionStatus::Expired;
88 }
89 }
90
91 Ok(count)
92 }
93}