1use crate::cmd::{Parse, ParseError};
2use crate::prelude::*;
3
4use bytes::Bytes;
5use std::time::Duration;
6use tracing::{debug, instrument};
7
8#[derive(Debug)]
9pub struct Set {
10 key: String,
11 value: Bytes,
12 expire: Option<Duration>,
13}
14
15impl Set {
16 pub fn new(key: impl ToString, value: Bytes, expire: Option<Duration>) -> Set { Set { key: key.to_string(), value, expire } }
17
18 pub fn key(&self) -> &str { &self.key }
19
20 pub fn value(&self) -> &Bytes { &self.value }
21
22 pub fn expire(&self) -> Option<Duration> { self.expire }
23
24 pub fn parse_frames(parse: &mut Parse) -> crate::Result<Set> {
25 use ParseError::EndOfStream;
26
27 let key = parse.next_string()?;
28 let value = parse.next_bytes()?;
29 let mut expire = None;
30
31 match parse.next_string() {
32 Ok(s) if s.to_uppercase() == "EX" => {
33 let secs = parse.next_int()?;
34 expire = Some(Duration::from_secs(secs));
35 }
36 Ok(s) if s.to_uppercase() == "PX" => {
37 let ms = parse.next_int()?;
38 expire = Some(Duration::from_millis(ms));
39 }
40 Ok(_) => return Err("currently `SET` only supports the expiration option".into()),
41 Err(EndOfStream) => {}
42 Err(err) => return Err(err.into()),
43 }
44
45 Ok(Set { key, value, expire })
46 }
47
48 #[instrument(skip(self, db, dst))]
49 pub async fn apply(self, db: &Db, dst: &mut Connection) -> crate::Result<()> {
50 db.set(self.key, self.value, self.expire);
51
52 let response = Frame::Simple("OK".to_string());
53 debug!(?response);
54 dst.write_frame(&response).await?;
55
56 Ok(())
57 }
58
59 pub fn into_frame(self) -> Frame {
60 let mut frame = Frame::array();
61 frame.push_bulk(Bytes::from("set".as_bytes()));
62 frame.push_bulk(Bytes::from(self.key.into_bytes()));
63 frame.push_bulk(self.value);
64 if let Some(ms) = self.expire {
65 frame.push_bulk(Bytes::from("px".as_bytes()));
66 frame.push_int(ms.as_millis() as u64);
67 }
68 frame
69 }
70}