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