Skip to main content

shared/infrastructure/cache/in_memory/
adapter.rs

1use async_trait::async_trait;
2use std::collections::HashMap;
3use std::sync::Arc;
4use std::time::{Duration, Instant};
5use tokio::sync::Mutex;
6
7use crate::domain::cache::CacheAdapter;
8use crate::error::{CoreError, InternalError, Result};
9
10struct CacheEntry {
11    value: String,
12    expires_at: Option<Instant>,
13}
14
15pub struct InMemoryAdapter {
16    store: Arc<Mutex<HashMap<String, CacheEntry>>>,
17}
18
19impl InMemoryAdapter {
20    pub fn new() -> Self {
21        Self {
22            store: Arc::new(Mutex::new(HashMap::new())),
23        }
24    }
25}
26
27impl Default for InMemoryAdapter {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33#[async_trait]
34impl CacheAdapter for InMemoryAdapter {
35    async fn insert(&self, key: &str, value: &str, expiration: u64) -> Result<()> {
36        let mut store = self.store.lock().await;
37        store.insert(
38            key.to_string(),
39            CacheEntry {
40                value: value.to_string(),
41                expires_at: Some(Instant::now() + Duration::from_secs(expiration)),
42            },
43        );
44        Ok(())
45    }
46
47    async fn find_one(&self, key: &str) -> Result<Option<String>> {
48        let store = self.store.lock().await;
49
50        match store.get(key) {
51            Some(entry) => {
52                if let Some(expires_at) = entry.expires_at
53                    && Instant::now() > expires_at
54                {
55                    return Ok(None);
56                }
57                Ok(Some(entry.value.clone()))
58            }
59            None => Ok(None),
60        }
61    }
62
63    async fn update(&self, key: &str, value: &str, expiration: u64) -> Result<()> {
64        let mut store = self.store.lock().await;
65        store.entry(key.to_string()).and_modify(|v| {
66            *v = CacheEntry {
67                value: value.to_string(),
68                expires_at: Some(Instant::now() + Duration::from_secs(expiration)),
69            };
70        });
71
72        Ok(())
73    }
74
75    async fn increment(&self, key: &str) -> Result<u64> {
76        let mut store = self.store.lock().await;
77        let entry = store.entry(key.to_string()).or_insert(CacheEntry {
78            value: "0".to_string(),
79            expires_at: None,
80        });
81
82        let new_val: u64 = entry.value.parse().unwrap_or(0) + 1;
83        entry.value = new_val.to_string();
84
85        Ok(new_val)
86    }
87
88    async fn delete_one(&self, key: &str) -> Result<()> {
89        let mut store = self.store.lock().await;
90        if store.remove(key).is_none() {
91            return Err(CoreError::Internal(InternalError::Cache(
92                "Failed deleting an entry form cache".to_string(),
93            )));
94        }
95
96        Ok(())
97    }
98
99    async fn flush_all(&self) -> Result<()> {
100        let mut store = self.store.lock().await;
101        store.clear();
102
103        Ok(())
104    }
105}