rustdis/commands/
setnx.rs

1use bytes::Bytes;
2use std::sync::{Arc, Mutex};
3
4use crate::commands::executable::Executable;
5use crate::commands::CommandParser;
6use crate::frame::Frame;
7use crate::store::Store;
8use crate::Error;
9
10/// Set key to hold string value if key does not exist. In that case, it is equal to SET. When key
11/// already holds a value, no operation is performed. SETNX is short for "SET if Not eXists".
12///
13/// Ref: <https://redis.io/docs/latest/commands/setnx/>
14#[derive(Debug, PartialEq)]
15pub struct Setnx {
16    pub key: String,
17    pub value: Bytes,
18}
19
20impl Executable for Setnx {
21    fn exec(self, store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
22        let mut store = store.lock().unwrap();
23
24        let res = match store.get(&self.key) {
25            Some(_) => Frame::Integer(0),
26            None => {
27                store.set(self.key, self.value);
28                Frame::Integer(1)
29            }
30        };
31
32        Ok(res)
33    }
34}
35
36impl TryFrom<&mut CommandParser> for Setnx {
37    type Error = Error;
38
39    fn try_from(parser: &mut CommandParser) -> Result<Self, Self::Error> {
40        let key = parser.next_string()?;
41        let value = parser.next_bytes()?;
42
43        Ok(Self { key, value })
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::commands::Command;
51    use bytes::Bytes;
52
53    #[test]
54    fn when_key_does_not_exists() {
55        let store = Arc::new(Mutex::new(Store::new()));
56
57        let frame = Frame::Array(vec![
58            Frame::Bulk(Bytes::from("SETNX")),
59            Frame::Bulk(Bytes::from("key1")),
60            Frame::Bulk(Bytes::from("1")),
61        ]);
62        let cmd = Command::try_from(frame).unwrap();
63
64        assert_eq!(
65            cmd,
66            Command::Setnx(Setnx {
67                key: String::from("key1"),
68                value: Bytes::from("1")
69            })
70        );
71
72        let res = cmd.exec(store.clone()).unwrap();
73
74        assert_eq!(res, Frame::Integer(1));
75        assert_eq!(store.lock().unwrap().get("key1"), Some(&Bytes::from("1")));
76    }
77
78    #[test]
79    fn when_key_already_exists() {
80        let store = Arc::new(Mutex::new(Store::new()));
81
82        let frame = Frame::Array(vec![
83            Frame::Bulk(Bytes::from("SETNX")),
84            Frame::Bulk(Bytes::from("key1")),
85            Frame::Bulk(Bytes::from("1")),
86        ]);
87        let cmd = Command::try_from(frame).unwrap();
88
89        assert_eq!(
90            cmd,
91            Command::Setnx(Setnx {
92                key: String::from("key1"),
93                value: Bytes::from("1")
94            })
95        );
96
97        store
98            .lock()
99            .unwrap()
100            .set(String::from("key1"), Bytes::from("1"));
101
102        let res = cmd.exec(store.clone()).unwrap();
103
104        assert_eq!(res, Frame::Integer(0));
105        assert_eq!(store.lock().unwrap().get("key1"), Some(&Bytes::from("1")));
106    }
107}