Skip to main content

doido_cache/
memory.rs

1use crate::store::CacheStore;
2use doido_core::Result;
3use serde_json::Value;
4use std::{
5    collections::HashMap,
6    sync::RwLock,
7    time::{Duration, Instant},
8};
9
10pub struct MemoryStore {
11    data: RwLock<HashMap<String, (Value, Option<Instant>)>>,
12}
13
14impl MemoryStore {
15    pub fn new() -> Self {
16        Self {
17            data: RwLock::new(HashMap::new()),
18        }
19    }
20}
21
22impl Default for MemoryStore {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28#[async_trait::async_trait]
29impl CacheStore for MemoryStore {
30    async fn get(&self, key: &str) -> Result<Option<Value>> {
31        let guard = self.data.read().unwrap();
32        match guard.get(key) {
33            None => Ok(None),
34            Some((val, None)) => Ok(Some(val.clone())),
35            Some((val, Some(expiry))) => {
36                if Instant::now() > *expiry {
37                    drop(guard);
38                    self.data.write().unwrap().remove(key);
39                    Ok(None)
40                } else {
41                    Ok(Some(val.clone()))
42                }
43            }
44        }
45    }
46
47    async fn set(&self, key: &str, value: Value, ttl_secs: Option<u64>) -> Result<()> {
48        let expiry = ttl_secs.map(|s| Instant::now() + Duration::from_secs(s));
49        self.data
50            .write()
51            .unwrap()
52            .insert(key.to_string(), (value, expiry));
53        Ok(())
54    }
55
56    async fn delete(&self, key: &str) -> Result<()> {
57        self.data.write().unwrap().remove(key);
58        Ok(())
59    }
60
61    async fn exists(&self, key: &str) -> Result<bool> {
62        Ok(self.get(key).await?.is_some())
63    }
64
65    async fn increment(&self, key: &str, by: i64) -> Result<i64> {
66        let mut data = self.data.write().unwrap();
67        let entry = data
68            .entry(key.to_string())
69            .or_insert((serde_json::json!(0), None));
70        let current = entry.0.as_i64().unwrap_or(0);
71        let new_val = current + by;
72        entry.0 = serde_json::json!(new_val);
73        Ok(new_val)
74    }
75
76    async fn decrement(&self, key: &str, by: i64) -> Result<i64> {
77        self.increment(key, -by).await
78    }
79
80    async fn clear(&self) -> Result<()> {
81        self.data.write().unwrap().clear();
82        Ok(())
83    }
84}