1use crate::error::Result;
2use async_trait::async_trait;
3use std::time::Duration;
4
5#[derive(Debug, Clone, Default, PartialEq, Eq)]
6pub struct CacheScanPage {
7 pub entries: Vec<(String, String)>,
8 pub next_cursor: Option<String>,
9}
10
11#[async_trait]
13pub trait CacheManager: Send + Sync {
14 async fn has(&self, key: &str) -> Result<bool>;
16
17 async fn get(&self, key: &str) -> Result<Option<String>>;
20
21 async fn set(&self, key: &str, value: &str, ttl_seconds: u64) -> Result<()>;
23
24 async fn remove(&self, key: &str) -> Result<()>;
26
27 async fn disconnect(&self) -> Result<()>;
29
30 async fn check_health(&self) -> Result<()> {
32 Ok(())
34 }
35
36 async fn ttl(&self, key: &str) -> Result<Option<Duration>>;
37
38 async fn scan_prefix(&self, prefix: &str, limit: usize) -> Result<Vec<(String, String)>> {
43 let _ = (prefix, limit);
44 Ok(Vec::new())
45 }
46
47 async fn scan_prefix_page(
48 &self,
49 prefix: &str,
50 cursor: Option<String>,
51 limit: usize,
52 ) -> Result<CacheScanPage> {
53 let _ = cursor;
54 Ok(CacheScanPage {
55 entries: self.scan_prefix(prefix, limit).await?,
56 next_cursor: None,
57 })
58 }
59
60 async fn set_if_not_exists(&self, key: &str, value: &str, ttl_seconds: u64) -> Result<bool> {
64 if self.has(key).await? {
65 return Ok(false);
66 }
67 self.set(key, value, ttl_seconds).await?;
68 Ok(true)
69 }
70
71 async fn increment_by(&self, key: &str, delta: i64, ttl_seconds: u64) -> Result<i64> {
72 let current = self
73 .get(key)
74 .await?
75 .and_then(|value| value.parse::<i64>().ok())
76 .unwrap_or(0);
77 let next = current.saturating_add(delta);
78 self.set(key, &next.to_string(), ttl_seconds).await?;
79 Ok(next)
80 }
81}