use crate::backend::{CacheBackend, MemoryBackend, RedisBackend, RedisMode, TieredBackend};
use crate::error::Result;
use std::sync::Arc;
pub struct TieredCacheBuilder {
l1_capacity: u64,
l1_ttl: Option<std::time::Duration>,
l2_connection_string: Option<String>,
l2_mode: RedisMode,
auto_promote: bool,
batch_writes: bool,
bloom_filter: bool,
}
impl Default for TieredCacheBuilder {
fn default() -> Self {
Self {
l1_capacity: 10000,
l1_ttl: None,
l2_connection_string: None,
l2_mode: RedisMode::Standalone,
auto_promote: true,
batch_writes: false,
bloom_filter: false,
}
}
}
impl TieredCacheBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn l1_capacity(mut self, capacity: u64) -> Self {
self.l1_capacity = capacity;
self
}
pub fn l1_ttl(mut self, ttl: std::time::Duration) -> Self {
self.l1_ttl = Some(ttl);
self
}
pub fn l2_connection_string(mut self, connection_string: &str) -> Self {
self.l2_connection_string = Some(connection_string.to_string());
self
}
pub fn l2_mode(mut self, mode: RedisMode) -> Self {
self.l2_mode = mode;
self
}
pub fn auto_promote(mut self, enabled: bool) -> Self {
self.auto_promote = enabled;
self
}
pub fn batch_writes(mut self, enabled: bool) -> Self {
self.batch_writes = enabled;
self
}
pub fn bloom_filter(mut self, enabled: bool) -> Self {
self.bloom_filter = enabled;
self
}
pub async fn build(self) -> Result<Arc<dyn CacheBackend>> {
let l2_connection_string = self.l2_connection_string.ok_or_else(|| {
crate::error::CacheError::ConfigError("L2 connection string is required".to_string())
})?;
let l1_builder = MemoryBackend::builder().capacity(self.l1_capacity);
let l1 = if let Some(ttl) = self.l1_ttl {
l1_builder.ttl(ttl).build()
} else {
l1_builder.build()
};
let l2 = RedisBackend::builder()
.connection_string(&l2_connection_string)
.mode(self.l2_mode)
.build()
.await?;
let backend = TieredBackend::builder()
.l1(l1)
.l2(l2)
.auto_promote(self.auto_promote)
.build()?;
Ok(Arc::new(backend))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_tiered_cache_builder_default() {
let l1 = MemoryBackend::new();
let l2 = MemoryBackend::new();
let backend = TieredBackend::builder()
.l1(l1)
.l2(l2)
.auto_promote(true)
.build()
.unwrap();
assert!(backend.health_check().await.unwrap());
}
#[tokio::test]
async fn test_tiered_cache_builder_with_options() {
let l1 = MemoryBackend::builder().capacity(1000).build();
let l2 = MemoryBackend::new();
let backend = TieredBackend::builder()
.l1(l1)
.l2(l2)
.auto_promote(false)
.build()
.unwrap();
assert!(backend.health_check().await.unwrap());
}
}