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}