backbone_orm/
in_memory.rs1use std::collections::HashMap;
48use std::sync::Arc;
49use tokio::sync::RwLock;
50
51pub struct InMemoryStore<T: Clone + Send + Sync> {
60 items: RwLock<HashMap<String, T>>,
62 deleted: RwLock<HashMap<String, T>>,
64}
65
66impl<T: Clone + Send + Sync> InMemoryStore<T> {
67 pub fn new() -> Self {
69 Self {
70 items: RwLock::new(HashMap::new()),
71 deleted: RwLock::new(HashMap::new()),
72 }
73 }
74
75 pub fn new_shared() -> Arc<Self> {
77 Arc::new(Self::new())
78 }
79
80 pub async fn insert(&self, id: String, item: T) {
86 self.items.write().await.insert(id, item);
87 }
88
89 pub async fn get(&self, id: &str) -> Option<T> {
91 self.items.read().await.get(id).cloned()
92 }
93
94 pub async fn get_deleted(&self, id: &str) -> Option<T> {
96 self.deleted.read().await.get(id).cloned()
97 }
98
99 pub async fn exists(&self, id: &str) -> bool {
101 self.items.read().await.contains_key(id)
102 }
103
104 pub async fn exists_in_trash(&self, id: &str) -> bool {
106 self.deleted.read().await.contains_key(id)
107 }
108
109 pub async fn update(&self, id: &str, item: T) -> Option<T> {
111 let mut items = self.items.write().await;
112 if items.contains_key(id) {
113 items.insert(id.to_string(), item.clone());
114 Some(item)
115 } else {
116 None
117 }
118 }
119
120 pub async fn remove(&self, id: &str) -> Option<T> {
122 self.items.write().await.remove(id)
123 }
124
125 pub async fn soft_delete(&self, id: &str) -> bool {
131 let mut items = self.items.write().await;
132 let mut deleted = self.deleted.write().await;
133 if let Some(item) = items.remove(id) {
134 deleted.insert(id.to_string(), item);
135 true
136 } else {
137 false
138 }
139 }
140
141 pub async fn restore(&self, id: &str) -> Option<T> {
143 let mut items = self.items.write().await;
144 let mut deleted = self.deleted.write().await;
145 if let Some(item) = deleted.remove(id) {
146 items.insert(id.to_string(), item.clone());
147 Some(item)
148 } else {
149 None
150 }
151 }
152
153 pub async fn hard_delete(&self, id: &str) -> Option<T> {
155 self.deleted.write().await.remove(id)
156 }
157
158 pub async fn empty_trash(&self) -> u64 {
160 let mut deleted = self.deleted.write().await;
161 let count = deleted.len() as u64;
162 deleted.clear();
163 count
164 }
165
166 pub async fn list(&self, page: u32, limit: u32) -> (Vec<T>, u64) {
181 let items = self.items.read().await;
182 let total = items.len() as u64;
183 let skip = ((page.saturating_sub(1)) * limit) as usize;
184 let items: Vec<T> = items.values().skip(skip).take(limit as usize).cloned().collect();
185 (items, total)
186 }
187
188 pub async fn list_deleted(&self, page: u32, limit: u32) -> (Vec<T>, u64) {
190 let deleted = self.deleted.read().await;
191 let total = deleted.len() as u64;
192 let skip = ((page.saturating_sub(1)) * limit) as usize;
193 let items: Vec<T> = deleted.values().skip(skip).take(limit as usize).cloned().collect();
194 (items, total)
195 }
196
197 pub async fn all(&self) -> Vec<T> {
199 self.items.read().await.values().cloned().collect()
200 }
201
202 pub async fn all_deleted(&self) -> Vec<T> {
204 self.deleted.read().await.values().cloned().collect()
205 }
206
207 pub async fn count(&self) -> u64 {
213 self.items.read().await.len() as u64
214 }
215
216 pub async fn trash_count(&self) -> u64 {
218 self.deleted.read().await.len() as u64
219 }
220
221 pub async fn clear(&self) {
223 self.items.write().await.clear();
224 self.deleted.write().await.clear();
225 }
226
227 pub async fn clear_active(&self) {
229 self.items.write().await.clear();
230 }
231
232 pub async fn ids(&self) -> Vec<String> {
234 self.items.read().await.keys().cloned().collect()
235 }
236
237 pub async fn trash_ids(&self) -> Vec<String> {
239 self.deleted.read().await.keys().cloned().collect()
240 }
241}
242
243impl<T: Clone + Send + Sync> Default for InMemoryStore<T> {
244 fn default() -> Self {
245 Self::new()
246 }
247}
248
249#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[derive(Debug, Clone, PartialEq)]
258 struct TestEntity {
259 id: String,
260 name: String,
261 }
262
263 #[tokio::test]
264 async fn test_insert_and_get() {
265 let store = InMemoryStore::<TestEntity>::new();
266 let entity = TestEntity {
267 id: "1".to_string(),
268 name: "Test".to_string(),
269 };
270
271 store.insert("1".to_string(), entity.clone()).await;
272
273 let found = store.get("1").await;
274 assert!(found.is_some());
275 assert_eq!(found.unwrap().name, "Test");
276 }
277
278 #[tokio::test]
279 async fn test_update() {
280 let store = InMemoryStore::<TestEntity>::new();
281 let entity = TestEntity {
282 id: "1".to_string(),
283 name: "Original".to_string(),
284 };
285
286 store.insert("1".to_string(), entity).await;
287
288 let updated = TestEntity {
289 id: "1".to_string(),
290 name: "Updated".to_string(),
291 };
292
293 let result = store.update("1", updated).await;
294 assert!(result.is_some());
295
296 let found = store.get("1").await;
297 assert_eq!(found.unwrap().name, "Updated");
298 }
299
300 #[tokio::test]
301 async fn test_soft_delete_and_restore() {
302 let store = InMemoryStore::<TestEntity>::new();
303 let entity = TestEntity {
304 id: "1".to_string(),
305 name: "Test".to_string(),
306 };
307
308 store.insert("1".to_string(), entity).await;
309
310 let deleted = store.soft_delete("1").await;
312 assert!(deleted);
313 assert!(store.get("1").await.is_none());
314 assert!(store.get_deleted("1").await.is_some());
315
316 let restored = store.restore("1").await;
318 assert!(restored.is_some());
319 assert!(store.get("1").await.is_some());
320 assert!(store.get_deleted("1").await.is_none());
321 }
322
323 #[tokio::test]
324 async fn test_list_pagination() {
325 let store = InMemoryStore::<TestEntity>::new();
326
327 for i in 0..10 {
328 let entity = TestEntity {
329 id: i.to_string(),
330 name: format!("Entity {}", i),
331 };
332 store.insert(i.to_string(), entity).await;
333 }
334
335 let (items, total) = store.list(1, 3).await;
336 assert_eq!(items.len(), 3);
337 assert_eq!(total, 10);
338
339 let (items, total) = store.list(4, 3).await;
340 assert_eq!(items.len(), 1);
341 assert_eq!(total, 10);
342 }
343
344 #[tokio::test]
345 async fn test_empty_trash() {
346 let store = InMemoryStore::<TestEntity>::new();
347
348 for i in 0..5 {
349 let entity = TestEntity {
350 id: i.to_string(),
351 name: format!("Entity {}", i),
352 };
353 store.insert(i.to_string(), entity).await;
354 store.soft_delete(&i.to_string()).await;
355 }
356
357 assert_eq!(store.trash_count().await, 5);
358
359 let emptied = store.empty_trash().await;
360 assert_eq!(emptied, 5);
361 assert_eq!(store.trash_count().await, 0);
362 }
363
364 #[tokio::test]
365 async fn test_exists() {
366 let store = InMemoryStore::<TestEntity>::new();
367 let entity = TestEntity {
368 id: "1".to_string(),
369 name: "Test".to_string(),
370 };
371
372 store.insert("1".to_string(), entity).await;
373
374 assert!(store.exists("1").await);
375 assert!(!store.exists("2").await);
376
377 store.soft_delete("1").await;
378 assert!(!store.exists("1").await);
379 assert!(store.exists_in_trash("1").await);
380 }
381}