use crate::error::Result;
use async_trait::async_trait;
use std::time::Duration;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CacheScanPage {
pub entries: Vec<(String, String)>,
pub next_cursor: Option<String>,
}
#[async_trait]
pub trait CacheManager: Send + Sync {
async fn has(&self, key: &str) -> Result<bool>;
async fn get(&self, key: &str) -> Result<Option<String>>;
async fn set(&self, key: &str, value: &str, ttl_seconds: u64) -> Result<()>;
async fn remove(&self, key: &str) -> Result<()>;
async fn disconnect(&self) -> Result<()>;
async fn check_health(&self) -> Result<()> {
Ok(())
}
async fn ttl(&self, key: &str) -> Result<Option<Duration>>;
async fn scan_prefix(&self, prefix: &str, limit: usize) -> Result<Vec<(String, String)>> {
let _ = (prefix, limit);
Ok(Vec::new())
}
async fn scan_prefix_page(
&self,
prefix: &str,
cursor: Option<String>,
limit: usize,
) -> Result<CacheScanPage> {
let _ = cursor;
Ok(CacheScanPage {
entries: self.scan_prefix(prefix, limit).await?,
next_cursor: None,
})
}
async fn set_if_not_exists(&self, key: &str, value: &str, ttl_seconds: u64) -> Result<bool> {
if self.has(key).await? {
return Ok(false);
}
self.set(key, value, ttl_seconds).await?;
Ok(true)
}
async fn increment_by(&self, key: &str, delta: i64, ttl_seconds: u64) -> Result<i64> {
let current = self
.get(key)
.await?
.and_then(|value| value.parse::<i64>().ok())
.unwrap_or(0);
let next = current.saturating_add(delta);
self.set(key, &next.to_string(), ttl_seconds).await?;
Ok(next)
}
}