Skip to main content

crates_docs/cache/
mod.rs

1//! Cache module
2//!
3//! Provides memory cache and Redis cache support.
4
5#[cfg(feature = "cache-memory")]
6pub mod memory;
7
8#[cfg(feature = "cache-redis")]
9pub mod redis;
10
11use std::time::Duration;
12
13/// Cache trait
14#[async_trait::async_trait]
15pub trait Cache: Send + Sync {
16    /// Get cache value
17    async fn get(&self, key: &str) -> Option<String>;
18
19    /// Set cache value
20    async fn set(&self, key: String, value: String, ttl: Option<Duration>);
21
22    /// Delete cache value
23    async fn delete(&self, key: &str);
24
25    /// Clear cache
26    async fn clear(&self);
27
28    /// Check if key exists
29    async fn exists(&self, key: &str) -> bool;
30}
31
32/// Cache configuration
33#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
34pub struct CacheConfig {
35    /// Cache type: memory or redis
36    pub cache_type: String,
37
38    /// Memory cache size (number of entries)
39    pub memory_size: Option<usize>,
40
41    /// Redis connection URL
42    pub redis_url: Option<String>,
43
44    /// Default TTL (seconds)
45    pub default_ttl: Option<u64>,
46}
47
48impl Default for CacheConfig {
49    fn default() -> Self {
50        Self {
51            cache_type: "memory".to_string(),
52            memory_size: Some(1000),
53            redis_url: None,
54            default_ttl: Some(3600), // 1 hour
55        }
56    }
57}
58
59/// Create cache instance
60///
61/// # Errors
62///
63/// Returns an error if cache type is not supported or configuration is invalid
64pub fn create_cache(config: &CacheConfig) -> Result<Box<dyn Cache>, crate::error::Error> {
65    match config.cache_type.as_str() {
66        "memory" => {
67            #[cfg(feature = "cache-memory")]
68            {
69                let size = config.memory_size.unwrap_or(1000);
70                Ok(Box::new(memory::MemoryCache::new(size)))
71            }
72            #[cfg(not(feature = "cache-memory"))]
73            {
74                Err(crate::error::Error::Config(
75                    "memory cache feature is not enabled".to_string(),
76                ))
77            }
78        }
79        "redis" => {
80            #[cfg(feature = "cache-redis")]
81            {
82                // Note: Redis cache requires async initialization, this returns a placeholder
83                // In practice, use the create_cache_async function
84                Err(crate::error::Error::Config(
85                    "Redis cache requires async initialization. Use create_cache_async instead."
86                        .to_string(),
87                ))
88            }
89            #[cfg(not(feature = "cache-redis"))]
90            {
91                Err(crate::error::Error::Config(
92                    "redis cache feature is not enabled".to_string(),
93                ))
94            }
95        }
96        _ => Err(crate::error::Error::Config(format!(
97            "unsupported cache type: {}",
98            config.cache_type
99        ))),
100    }
101}
102
103/// Create cache instance asynchronously
104///
105/// # Errors
106///
107/// Returns an error if cache type is not supported or configuration is invalid
108#[cfg(feature = "cache-redis")]
109pub async fn create_cache_async(
110    config: &CacheConfig,
111) -> Result<Box<dyn Cache>, crate::error::Error> {
112    match config.cache_type.as_str() {
113        "memory" => {
114            let size = config.memory_size.unwrap_or(1000);
115            Ok(Box::new(memory::MemoryCache::new(size)))
116        }
117        "redis" => {
118            let url = config
119                .redis_url
120                .as_ref()
121                .ok_or_else(|| crate::error::Error::Config("redis_url is required".to_string()))?;
122            Ok(Box::new(redis::RedisCache::new(url).await?))
123        }
124        _ => Err(crate::error::Error::Config(format!(
125            "unsupported cache type: {}",
126            config.cache_type
127        ))),
128    }
129}