cache_service 1.1.0

Cache service based on Redis and in-memory cache
Documentation
use crate::in_memory_cache::InMemoryCache;
use crate::kv_cache::KvCache;

pub mod in_memory_cache;
pub mod kv_cache;

pub struct SetPayload<'a> {
    pub key: &'a str,
    pub value: &'a str,
    pub ttl: u64,
}

#[allow(dead_code)]
pub struct CacheService {
    in_memory_cache: InMemoryCache,
    kv_cache: KvCache,
    ttl: u64,
}

#[derive(Debug)]
pub enum CacheServiceError {
    InMemoryCacheError(in_memory_cache::InMemoryCacheError),
    KvCacheError(kv_cache::KvError),
}

impl CacheService {
    pub fn new(ttl: u64, redis_url: &str) -> CacheService {
        CacheService {
            in_memory_cache: InMemoryCache::new(),
            kv_cache: KvCache::new(redis_url).expect("KvCache creation failed"),
            ttl,
        }
    }

    pub fn resolve<T>(&mut self, key: &str, resolver: T) -> Result<String, CacheServiceError>
    where
        T: FnOnce() -> String,
    {
        let memory_value = self.in_memory_cache.get(key);

        if let Some(value) = memory_value {
            return Ok(value);
        }

        let kv_value = self.kv_cache.get(key);

        if let Some(value) = kv_value {
            return Ok(value);
        }
        let value = resolver();

        self.kv_cache
            .set(SetPayload {
                key,
                value: &value,
                ttl: self.ttl,
            })
            .map_err(CacheServiceError::KvCacheError)?;

        self.in_memory_cache
            .set(SetPayload {
                key,
                value: &value,
                ttl: self.ttl,
            })
            .map_err(CacheServiceError::InMemoryCacheError)?;

        Ok(value)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_should_resolve_value() {
        let mut cache = CacheService::new(10, "redis://127.0.0.1:6379");
        let value = cache.resolve("key", || "value".to_string()).unwrap();
        assert_eq!(value, "value");
    }

    #[test]
    fn it_should_resolve_value_from_memory() {
        let mut cache = CacheService::new(10, "redis://127.0.0.1:6379");
        cache
            .in_memory_cache
            .set(SetPayload {
                key: "key",
                value: "value",
                ttl: 10,
            })
            .expect("All should be ok");
        let value = cache.resolve("key", || "never_see".to_string()).unwrap();

        assert_eq!(value, "value");
    }

    #[test]
    fn it_should_resolve_value_from_kv() {
        let mut cache = CacheService::new(10, "redis://127.0.0.1:6379");
        cache
            .kv_cache
            .set(SetPayload {
                key: "key",
                value: "value",
                ttl: 10,
            })
            .expect("All should be ok");
        let value = cache.resolve("key", || "never_see".to_string()).unwrap();

        assert_eq!(value, "value");
    }

    #[test]
    fn should_set_value_to_memory_cache() {
        let mut cache = CacheService::new(10, "redis://127.0.0.1:6379");
        cache.resolve("memkey", || "value".to_string()).unwrap();
        cache.kv_cache.unset("memkey").unwrap();
        let in_memory_value = cache.in_memory_cache.get("memkey").unwrap();

        assert_eq!(in_memory_value, "value");
    }

    #[test]
    fn should_set_value_to_kv_cache() {
        let mut cache = CacheService::new(10, "redis://127.0.0.1:6379");
        cache.resolve("kvkey", || "kvval".to_string()).unwrap();

        let kv_cache = cache.kv_cache.get("kvkey").unwrap();

        assert_eq!(kv_cache, "kvval");
    }
}