mini_redis/cmd/
get.rs

1use crate::{Connection, Db, Frame, Parse};
2
3use bytes::Bytes;
4use tracing::{debug, instrument};
5
6/// Get the value of key.
7///
8/// If the key does not exist the special value nil is returned. An error is
9/// returned if the value stored at key is not a string, because GET only
10/// handles string values.
11#[derive(Debug)]
12pub struct Get {
13    /// Name of the key to get
14    key: String,
15}
16
17impl Get {
18    /// Create a new `Get` command which fetches `key`.
19    pub fn new(key: impl ToString) -> Get {
20        Get {
21            key: key.to_string(),
22        }
23    }
24
25    /// Get the key
26    pub fn key(&self) -> &str {
27        &self.key
28    }
29
30    /// Parse a `Get` instance from a received frame.
31    ///
32    /// The `Parse` argument provides a cursor-like API to read fields from the
33    /// `Frame`. At this point, the entire frame has already been received from
34    /// the socket.
35    ///
36    /// The `GET` string has already been consumed.
37    ///
38    /// # Returns
39    ///
40    /// Returns the `Get` value on success. If the frame is malformed, `Err` is
41    /// returned.
42    ///
43    /// # Format
44    ///
45    /// Expects an array frame containing two entries.
46    ///
47    /// ```text
48    /// GET key
49    /// ```
50    pub(crate) fn parse_frames(parse: &mut Parse) -> crate::Result<Get> {
51        // The `GET` string has already been consumed. The next value is the
52        // name of the key to get. If the next value is not a string or the
53        // input is fully consumed, then an error is returned.
54        let key = parse.next_string()?;
55
56        Ok(Get { key })
57    }
58
59    /// Apply the `Get` command to the specified `Db` instance.
60    ///
61    /// The response is written to `dst`. This is called by the server in order
62    /// to execute a received command.
63    #[instrument(skip(self, db, dst))]
64    pub(crate) async fn apply(self, db: &Db, dst: &mut Connection) -> crate::Result<()> {
65        // Get the value from the shared database state
66        let response = if let Some(value) = db.get(&self.key) {
67            // If a value is present, it is written to the client in "bulk"
68            // format.
69            Frame::Bulk(value)
70        } else {
71            // If there is no value, `Null` is written.
72            Frame::Null
73        };
74
75        debug!(?response);
76
77        // Write the response back to the client
78        dst.write_frame(&response).await?;
79
80        Ok(())
81    }
82
83    /// Converts the command into an equivalent `Frame`.
84    ///
85    /// This is called by the client when encoding a `Get` command to send to
86    /// the server.
87    pub(crate) fn into_frame(self) -> Frame {
88        let mut frame = Frame::array();
89        frame.push_bulk(Bytes::from("get".as_bytes()));
90        frame.push_bulk(Bytes::from(self.key.into_bytes()));
91        frame
92    }
93}