rustdis/commands/
mset.rs

1use std::sync::{Arc, Mutex};
2
3use bytes::Bytes;
4
5use crate::commands::executable::Executable;
6use crate::commands::{CommandParser, CommandParserError};
7use crate::frame::Frame;
8use crate::store::Store;
9use crate::Error;
10
11/// Sets the given keys to their respective values. Replaces existing values with new values.
12///
13/// Ref: <https://redis.io/docs/latest/commands/mset/>
14#[derive(Debug, PartialEq)]
15pub struct Mset {
16    pub pairs: Vec<(String, Bytes)>,
17}
18
19impl Executable for Mset {
20    fn exec(self, store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
21        if self.pairs.is_empty() {
22            return Ok(Frame::Error(
23                "ERR wrong number of arguments for command".to_string(),
24            ));
25        }
26
27        let mut store = store.lock().unwrap();
28
29        for (key, value) in self.pairs.iter() {
30            store.set(key.to_string(), value.clone());
31        }
32
33        Ok(Frame::Simple("OK".to_string()))
34    }
35}
36
37impl TryFrom<&mut CommandParser> for Mset {
38    type Error = Error;
39
40    fn try_from(parser: &mut CommandParser) -> Result<Self, Self::Error> {
41        let mut pairs = vec![];
42
43        loop {
44            match (parser.next_string(), parser.next_bytes()) {
45                (Ok(key), Ok(value)) => pairs.push((key, value)),
46                // TODO: move back the `keys.is_empty()` check here.
47                // We handle the case where no keys are provided in the `exec` method,
48                // because at the moment we don't have a way to return an error from here.
49                (Err(CommandParserError::EndOfStream), _) => {
50                    break;
51                }
52                (_, Err(CommandParserError::EndOfStream)) => {
53                    break;
54                }
55                (Err(err), _) => return Err(err.into()),
56                (_, Err(err)) => return Err(err.into()),
57            }
58        }
59
60        Ok(Self { pairs })
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::commands::Command;
68    use bytes::Bytes;
69
70    #[test]
71    fn insert_one() {
72        let store = Arc::new(Mutex::new(Store::new()));
73
74        let frame = Frame::Array(vec![
75            Frame::Bulk(Bytes::from("MSET")),
76            Frame::Bulk(Bytes::from("key1")),
77            Frame::Bulk(Bytes::from("value1")),
78        ]);
79        let cmd = Command::try_from(frame).unwrap();
80
81        assert_eq!(
82            cmd,
83            Command::Mset(Mset {
84                pairs: vec![(String::from("key1"), Bytes::from("value1"))]
85            })
86        );
87
88        let res = cmd.exec(store.clone()).unwrap();
89
90        assert_eq!(res, Frame::Simple("OK".to_string()));
91
92        assert_eq!(
93            store.lock().unwrap().get("key1").unwrap(),
94            &Bytes::from("value1")
95        );
96    }
97
98    #[test]
99    fn insert_many() {
100        let store = Arc::new(Mutex::new(Store::new()));
101
102        let frame = Frame::Array(vec![
103            Frame::Bulk(Bytes::from("MSET")),
104            Frame::Bulk(Bytes::from("key1")),
105            Frame::Bulk(Bytes::from("value1")),
106            Frame::Bulk(Bytes::from("key2")),
107            Frame::Bulk(Bytes::from("value2")),
108            Frame::Bulk(Bytes::from("key3")),
109            Frame::Bulk(Bytes::from("value3")),
110        ]);
111        let cmd = Command::try_from(frame).unwrap();
112
113        assert_eq!(
114            cmd,
115            Command::Mset(Mset {
116                pairs: vec![
117                    (String::from("key1"), Bytes::from("value1")),
118                    (String::from("key2"), Bytes::from("value2")),
119                    (String::from("key3"), Bytes::from("value3"))
120                ]
121            })
122        );
123
124        let res = cmd.exec(store.clone()).unwrap();
125
126        assert_eq!(res, Frame::Simple("OK".to_string()));
127
128        assert_eq!(
129            store.lock().unwrap().get("key1"),
130            Some(&Bytes::from("value1")),
131        );
132
133        assert_eq!(
134            store.lock().unwrap().get("key2"),
135            Some(&Bytes::from("value2")),
136        );
137
138        assert_eq!(
139            store.lock().unwrap().get("key3"),
140            Some(&Bytes::from("value3")),
141        );
142    }
143
144    #[test]
145    fn overide_existing() {
146        let store = Arc::new(Mutex::new(Store::new()));
147
148        let frame = Frame::Array(vec![
149            Frame::Bulk(Bytes::from("MSET")),
150            Frame::Bulk(Bytes::from("key1")),
151            Frame::Bulk(Bytes::from("value1")),
152        ]);
153        let cmd = Command::try_from(frame).unwrap();
154
155        assert_eq!(
156            cmd,
157            Command::Mset(Mset {
158                pairs: vec![(String::from("key1"), Bytes::from("value1")),]
159            })
160        );
161
162        {
163            let mut store = store.lock().unwrap();
164            store.set(String::from("key1"), Bytes::from("1"));
165        }
166
167        let res = cmd.exec(store.clone()).unwrap();
168
169        assert_eq!(res, Frame::Simple("OK".to_string()));
170
171        assert_eq!(
172            store.lock().unwrap().get("key1").unwrap(),
173            &Bytes::from("value1")
174        );
175    }
176
177    #[test]
178    fn no_keys() {
179        let store = Arc::new(Mutex::new(Store::new()));
180
181        let frame = Frame::Array(vec![Frame::Bulk(Bytes::from("MSET"))]);
182        let cmd = Command::try_from(frame).unwrap();
183
184        assert_eq!(cmd, Command::Mset(Mset { pairs: vec![] }));
185
186        let res = cmd.exec(store.clone()).unwrap();
187
188        assert_eq!(
189            res,
190            Frame::Error("ERR wrong number of arguments for command".to_string())
191        );
192    }
193}