rs-zero 0.1.1

Rust-first microservice framework inspired by go-zero engineering practices
Documentation
use std::time::Duration;

use crate::cache::{CacheKey, CacheResult, CacheStore, MemoryCacheStore};
use async_trait::async_trait;

use crate::cache_redis::RedisCacheConfig;

/// Redis cache store facade.
///
/// The default build uses an in-memory delegate so tests do not require Redis.
/// Enabling `cache-redis` makes client construction available through
/// `RedisClientFactory`; production applications can wire real connections
/// behind the same `CacheStore` trait.
#[derive(Debug, Clone)]
pub struct RedisCacheStore {
    config: RedisCacheConfig,
    delegate: MemoryCacheStore,
}

impl RedisCacheStore {
    /// Creates a store facade.
    pub fn new(config: RedisCacheConfig) -> Self {
        Self {
            config,
            delegate: MemoryCacheStore::new(),
        }
    }

    /// Returns the configured namespace.
    pub fn namespace(&self) -> &str {
        &self.config.namespace
    }

    /// Validates that the backend can be addressed.
    pub async fn health_check(&self) -> CacheResult<()> {
        let key = CacheKey::new(&self.config.namespace, ["health"]);
        self.delegate
            .set_raw(&key, b"ok".to_vec(), Some(self.config.default_ttl))
            .await
    }
}

#[async_trait]
impl CacheStore for RedisCacheStore {
    async fn get_raw(&self, key: &CacheKey) -> CacheResult<Option<Vec<u8>>> {
        self.delegate.get_raw(key).await
    }

    async fn set_raw(
        &self,
        key: &CacheKey,
        value: Vec<u8>,
        ttl: Option<Duration>,
    ) -> CacheResult<()> {
        self.delegate
            .set_raw(key, value, ttl.or(Some(self.config.default_ttl)))
            .await
    }

    async fn delete(&self, key: &CacheKey) -> CacheResult<()> {
        self.delegate.delete(key).await
    }
}

#[cfg(test)]
mod tests {
    use crate::cache::{CacheKey, CacheStore};

    use crate::cache_redis::{RedisCacheConfig, RedisCacheStore};

    #[tokio::test]
    async fn redis_store_facade_supports_cache_trait() {
        let store = RedisCacheStore::new(RedisCacheConfig::default());
        let key = CacheKey::new(store.namespace(), ["user", "1"]);
        store
            .set_json(&key, &serde_json::json!({"id":1}), None)
            .await
            .expect("set");
        let value: serde_json::Value = store.get_json(&key).await.expect("get").expect("value");
        assert_eq!(value["id"], 1);
        store.health_check().await.expect("health");
    }
}