cache_any/caches/
redis.rs

1use std::fmt::{Debug, Formatter};
2use std::sync::Arc;
3use redis::AsyncCommands;
4use tokio::sync::RwLock;
5use crate::{Cache, Cacheable};
6
7/// Cache using redis.
8/// 
9/// It uses [`redis::Client`] to connect to redis.
10/// Feature `redis` must be enabled.
11/// 
12/// A custom map should be specified. It will be used as the map of the redis key.
13/// 
14/// [`RedisCache`] implements [`Cache`]. See [`Cache`] for more details.
15/// 
16/// ## Example
17/// 
18/// ```rust,ignore
19/// let client = redis::Client::open("redis://127.0.0.1:6379/").unwrap();
20/// 
21/// // `aaa` is the hash map name
22/// let map = "aaa";
23/// let cache = RedisCache::new(client, map).await.unwrap(); 
24/// 
25/// cache.set("a", 1).await.unwrap();
26/// assert_eq!(cache.get::<u8>("a").await.unwrap().unwrap(), 1);
27/// 
28/// // Redis Data ('aaa' is a redis hash map):
29/// // aaa: a -> Encoded(1)
30/// ```
31#[derive(Debug, Clone)]
32pub struct RedisCache {
33    inner: Arc<RwLock<Inner>>,
34}
35
36impl RedisCache {
37    pub async fn new<S: ToString>(client: redis::Client, map: S) -> anyhow::Result<Self> {
38        let conn = client.get_multiplexed_async_connection().await?;
39
40        Ok(Self {
41            inner: Arc::new(RwLock::new(Inner {
42                map: Arc::new(map.to_string()),
43                client,
44                conn,
45            }))
46        })
47    }
48}
49
50#[async_trait::async_trait]
51impl Cache for RedisCache {
52    async fn get<T: Cacheable + Send + Sync>(&self, key: &str) -> anyhow::Result<Option<T>> {
53        let val: Option<String> = {
54            let mut inner = self.inner.write().await;
55            let map = inner.map.clone();
56            inner.conn.hget(map, key).await?
57        };
58
59        val.map(|val| T::from_hex(&val))
60            .transpose()
61    }
62
63    async fn set<T: Cacheable + Send + Sync>(&self, key: &str, value: T) -> anyhow::Result<()> {
64        let val = value.to_hex();
65        let mut inner = self.inner.write().await;
66        let map = inner.map.clone();
67        inner.conn.hset(map, key, val).await?;
68
69        Ok(())
70    }
71
72    async fn delete(&self, key: &str) -> anyhow::Result<()> {
73        let mut inner = self.inner.write().await;
74        let map = inner.map.clone();
75        inner.conn.hdel(map, key).await?;
76
77        Ok(())
78    }
79
80    async fn len(&self) -> anyhow::Result<usize> {
81        let mut inner = self.inner.write().await;
82        let map = inner.map.clone();
83        let len: u64 = inner.conn.hlen(map).await?;
84
85        Ok(len as usize)
86    }
87}
88
89struct Inner {
90    map: Arc<String>,
91    client: redis::Client,
92    conn: redis::aio::MultiplexedConnection,
93}
94
95impl Debug for Inner {
96    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97        f.debug_struct("RedisCache.Inner")
98            .field("client", &self.client)
99            .field("map", &self.map)
100            .finish()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use redis::Client;
107    use super::*;
108
109    #[tokio::test]
110    async fn test_redis_cache() -> anyhow::Result<()> {
111        let client = Client::open("redis://127.0.0.1:6379/")?;
112        let cache = RedisCache::new(client, "aaa").await?;
113
114        assert_eq!(cache.get::<u8>("none").await.unwrap(), None);
115        cache.set("a", String::from("aaaaaa")).await?;
116        assert_eq!(cache.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaa"));
117        cache.set("a", String::from("aaaaaaa")).await?;
118        assert_eq!(cache.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaaa"));
119
120        cache.set("b", String::from("bbbbbb")).await?;
121        assert_eq!(cache.get::<String>("b").await.unwrap().unwrap(), String::from("bbbbbb"));
122        cache.set("c", 1).await?;
123        assert_eq!(cache.get::<usize>("c").await.unwrap().unwrap(), 1);
124
125        let cloned = cache.clone();
126        assert_eq!(cloned.get::<u8>("none").await.unwrap(), None);
127        cloned.set("a", String::from("aaaaaa")).await?;
128        assert_eq!(cloned.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaa"));
129        cloned.set("a", String::from("aaaaaaa")).await?;
130        assert_eq!(cloned.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaaa"));
131
132        cloned.set("b", String::from("bbbbbb")).await?;
133        assert_eq!(cloned.get::<String>("b").await.unwrap().unwrap(), String::from("bbbbbb"));
134        cloned.set("c", 1).await?;
135        assert_eq!(cloned.get::<usize>("c").await.unwrap().unwrap(), 1);
136
137        println!("{:?}", cache);
138        println!("{:?}", cloned);
139        println!("size = {}", cloned.len().await?);
140        Ok(())
141    }
142}