Skip to main content

embedded_redis/commands/
get.rs

1//! Abstraction of GET command.
2//!
3//! For general information about this command, see the [Redis documentation](<https://redis.io/commands/get/>).
4//!
5//! # Basic usage
6//! In case of existing key [`Some(GetResponse)`](GetResponse) is returned.
7//! ```
8//! # async_std::task::block_on(async {
9//!# use core::str::FromStr;
10//!# use core::net::SocketAddr;
11//!# use std_embedded_nal_async::Stack;
12//!# use std_embedded_time::StandardClock;
13//!# use embedded_redis::commands::get::GetCommand;
14//!# use embedded_redis::commands::set::SetCommand;
15//!# use embedded_redis::network::ConnectionHandler;
16//!#
17//! let stack = Stack::default();
18//! let clock = StandardClock::default();
19//!
20//! let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
21//! let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
22//!#
23//!# let _ = client.send(SetCommand::new("test_key", "test_value")).await;
24//!
25//! let command = GetCommand::static_key("test_key");
26//! let response = client.send(command).await.unwrap().unwrap();
27//! assert_eq!("test_value", response.as_str().unwrap())
28//! # });
29//! ```
30//! # Missing key (NIL/NULL response)
31//! In case of missing key `None` is returned
32//! ```
33//! # async_std::task::block_on(async {
34//!# use core::str::FromStr;
35//!# use core::net::SocketAddr;
36//!# use std_embedded_nal_async::Stack;
37//!# use std_embedded_time::StandardClock;
38//!# use embedded_redis::commands::get::GetCommand;
39//!# use embedded_redis::commands::set::SetCommand;
40//!# use embedded_redis::network::ConnectionHandler;
41//!#
42//!# let stack = Stack::default();
43//!# let clock = StandardClock::default();
44//!#
45//!# let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
46//!# let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
47//!#
48//! let command = GetCommand::static_key("missing_key");
49//! let response = client.send(command).await.unwrap();
50//! assert!(response.is_none())
51//! # });
52//! ```
53//! # Using Bytes
54//! For best performance (instead of &str or String cloning), especially with large amounts of data, it is recommended to use [Bytes](<https://docs.rs/bytes/latest/bytes/>).
55//! ```
56//! # async_std::task::block_on(async {
57//!# use core::str::FromStr;
58//!# use bytes::Bytes;
59//!# use core::net::SocketAddr;
60//!# use std_embedded_nal_async::Stack;
61//!# use std_embedded_time::StandardClock;
62//!# use embedded_redis::commands::get::GetCommand;
63//!# use embedded_redis::commands::set::SetCommand;
64//!# use embedded_redis::network::ConnectionHandler;
65//!#
66//!# let stack = Stack::default();
67//!# let clock = StandardClock::default();
68//!#
69//!# let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
70//!# let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
71//!#
72//!# let _ = client.send(SetCommand::new("test_key", "test_value")).await;
73//!#
74//! // Using Bytes object as key
75//! let command = GetCommand::new(Bytes::from_static("large_key".as_bytes()));
76//!
77//! // Using response as Bytes
78//! let command = GetCommand::new("test_key");
79//! let response = client.send(command).await.unwrap().unwrap();
80//! let _response_bytes = response.to_bytes();
81//! # });
82//! ```
83//! # Shorthand
84//! [Client](Client#method.get) provides a shorthand method for this command.
85//! ```
86//! # async_std::task::block_on(async {
87//!# use core::str::FromStr;
88//!# use core::net::SocketAddr;
89//!# use std_embedded_nal_async::Stack;
90//!# use std_embedded_time::StandardClock;
91//!# use embedded_redis::commands::set::SetCommand;
92//!# use embedded_redis::network::ConnectionHandler;
93//!#
94//!# let stack = Stack::default();
95//!# let clock = StandardClock::default();
96//!#
97//!# let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
98//!# let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
99//!#
100//!# let _ = client.send(SetCommand::new("test_key", "test_value")).await;
101//!#
102//! let response = client.get("test_key").await.unwrap().unwrap();
103//! assert_eq!("test_value", response.as_str().unwrap())
104//! # });
105//! ```
106use crate::commands::auth::AuthCommand;
107use crate::commands::builder::{CommandBuilder, IsNullFrame, ToStringBytes};
108use crate::commands::hello::HelloCommand;
109use crate::commands::{Command, ResponseTypeError};
110use crate::network::client::{Client, CommandErrors};
111use crate::network::protocol::Protocol;
112use alloc::string::String;
113use bytes::Bytes;
114use embedded_io_async::{Read, Write};
115use embedded_time::Clock;
116
117///Abstraction of GET command.
118pub struct GetCommand {
119    key: Bytes,
120}
121
122impl GetCommand {
123    pub fn new<K>(key: K) -> Self
124    where
125        Bytes: From<K>,
126    {
127        GetCommand { key: key.into() }
128    }
129
130    /// Create from static key
131    pub fn static_key(key: &'static str) -> Self {
132        Self {
133            key: Bytes::from_static(key.as_bytes()),
134        }
135    }
136}
137
138///Abstraction of GET response
139#[derive(Debug)]
140pub struct GetResponse {
141    inner: Bytes,
142}
143
144impl GetResponse {
145    pub fn new(inner: Bytes) -> Self {
146        GetResponse { inner }
147    }
148
149    /// Extracts inner value
150    pub fn to_bytes(self) -> Bytes {
151        self.inner
152    }
153
154    /// Tries converting to String by copy, returns None in case of error (wrong UTF8 encoding)
155    pub fn as_string(&self) -> Option<String> {
156        let result = String::from_utf8(self.inner.to_vec());
157        if result.is_err() {
158            return None;
159        }
160
161        Some(result.unwrap())
162    }
163
164    /// Returns a &str to inner data, returns None in case of invalid UTF8 encoding
165    pub fn as_str(&self) -> Option<&str> {
166        let result = core::str::from_utf8(self.inner.as_ref());
167        if result.is_err() {
168            return None;
169        }
170
171        Some(result.unwrap())
172    }
173
174    /// Constructs the response object from frame
175    pub(crate) fn from_frame<F>(frame: F) -> Result<Option<Self>, ResponseTypeError>
176    where
177        F: IsNullFrame + ToStringBytes,
178    {
179        if frame.is_null_frame() {
180            return Ok(None);
181        }
182
183        Ok(Some(GetResponse::new(
184            frame.to_string_bytes().ok_or(ResponseTypeError {})?,
185        )))
186    }
187}
188
189impl<F> Command<F> for GetCommand
190where
191    F: From<CommandBuilder> + IsNullFrame + ToStringBytes,
192{
193    type Response = Option<GetResponse>;
194
195    fn encode(&self) -> F {
196        CommandBuilder::new("GET").arg(&self.key).into()
197    }
198
199    fn eval_response(&self, frame: F) -> Result<Self::Response, ResponseTypeError> {
200        GetResponse::from_frame(frame)
201    }
202}
203
204impl<'a, T: Read + Write, C: Clock, P: Protocol> Client<'a, T, C, P>
205where
206    AuthCommand: Command<<P as Protocol>::FrameType>,
207    HelloCommand: Command<<P as Protocol>::FrameType>,
208{
209    /// Shorthand for [GetCommand]
210    pub async fn get<K>(&self, key: K) -> Result<Option<GetResponse>, CommandErrors>
211    where
212        <P as Protocol>::FrameType: ToStringBytes,
213        <P as Protocol>::FrameType: IsNullFrame,
214        <P as Protocol>::FrameType: From<CommandBuilder>,
215        Bytes: From<K>,
216    {
217        self.send(GetCommand::new(key)).await
218    }
219}