cache_service/
kv_cache.rs1use redis::{Client, Commands, Connection, RedisError};
2
3use crate::SetPayload;
4
5pub struct KvCache {
6 con: Connection,
7}
8
9#[derive(Debug)]
10pub enum KvError {
11 CommandFailed(RedisError),
12 ConnectionNotEstablished,
13}
14
15impl From<RedisError> for KvError {
16 fn from(err: RedisError) -> Self {
17 KvError::CommandFailed(err)
18 }
19}
20
21impl KvCache {
22 pub fn new(url: &str) -> Result<KvCache, KvError> {
23 let client = Client::open(url).map_err(|_| KvError::ConnectionNotEstablished)?;
24 let con = client
25 .get_connection()
26 .map_err(|_| KvError::ConnectionNotEstablished)?;
27 Ok(KvCache { con })
28 }
29
30 pub fn set(&mut self, payload: SetPayload) -> Result<String, KvError> {
31 let res: String = self.con.get(payload.key).unwrap_or_else(|_| "".to_string());
32 if res.is_empty() {
33 self.con
34 .set_ex(payload.key, payload.value, payload.ttl)
35 .map_err(KvError::CommandFailed)?;
36 return Ok(payload.value.to_string());
37 }
38 Ok(res)
39 }
40
41 pub fn get(&mut self, key: &str) -> Option<String> {
42 let res: String = self.con.get(key).unwrap_or_else(|_| "".to_string());
43 if res.is_empty() {
44 return None;
45 }
46 Some(res)
47 }
48
49 pub fn unset(&mut self, key: &str) -> Result<(), KvError> {
50 self.con.del(key).map_err(KvError::CommandFailed)?;
51 Ok(())
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 impl KvCache {
60 fn set_raw(&mut self, key: &str, value: &str) -> Result<(), KvError> {
61 self.con.set(key, value).map_err(KvError::CommandFailed)?;
62 Ok(())
63 }
64 }
65
66 fn teardown(key: &str) {
67 let mut cache = KvCache::new("redis://127.0.0.1:6379")
68 .expect("Should establish connection with no problem");
69 cache.unset(key).expect("Should not fail");
70 }
71
72 #[test]
73 fn it_should_return_empty_value() {
74 let key = "foo1";
75 let mut cache = KvCache::new("redis://127.0.0.1:6379")
76 .expect("Should establish connection with no problem");
77 let res = cache
78 .set(SetPayload {
79 key,
80 value: "",
81 ttl: 1,
82 })
83 .expect("Should not fail");
84 teardown(key);
85 assert_eq!(res, "");
86 }
87
88 #[test]
89 fn it_should_return_value() {
90 let key = "foo2";
91 let mut cache = KvCache::new("redis://127.0.0.1:6379")
92 .expect("Should establish connection with no problem");
93 cache.set_raw(key, "42").expect("Should not fail");
94 let res = cache
95 .set(SetPayload {
96 key,
97 value: "42",
98 ttl: 1,
99 })
100 .expect("Should not fail");
101 teardown(key);
102 assert_eq!(res, "42");
103 }
104
105 #[test]
106 fn it_should_return_error_for_wrong_connection() {
107 let cache = KvCache::new("");
108 assert!(matches!(cache, Err(KvError::ConnectionNotEstablished)));
109 }
110
111 #[test]
112 fn it_should_cache_value_for_ttl() {
113 let key = "foo3";
114 let mut cache = KvCache::new("redis://127.0.0.1:6379")
115 .expect("Should establish connection with no problem");
116
117 cache
118 .set(SetPayload {
119 key,
120 value: "42",
121 ttl: 1,
122 })
123 .expect("Should not fail");
124 let res = cache.get(key).unwrap();
125 assert_eq!(res, "42");
126 std::thread::sleep(std::time::Duration::from_secs(2));
127 let res = cache.get(key);
128 teardown(key);
129 assert!(res.is_none());
130 }
131}