embedded_redis/commands/keys.rs
1//! Abstraction of KEYS command.
2//!
3//! Returns the keys matching a Redis glob-style pattern, such as `user:*` or `user:??`.
4//! The pattern is passed unchanged to Redis. Keys are returned as binary-safe [Bytes] values;
5//! no matches produce an empty vector. The order of the keys is unspecified.
6//!
7//! For general information about this command, see the [Redis documentation](https://redis.io/commands/keys/).
8//! KEYS scans the entire database in O(N) time and can block Redis on large databases.
9//!
10//! # Using command object
11//! ```
12//! # async_std::task::block_on(async {
13//! # use core::net::SocketAddr;
14//! # use core::str::FromStr;
15//! # use bytes::Bytes;
16//! # use std_embedded_nal_async::Stack;
17//! # use std_embedded_time::StandardClock;
18//! use embedded_redis::commands::keys::KeysCommand;
19//! use embedded_redis::network::ConnectionHandler;
20//!
21//! let stack = Stack::default();
22//! let clock = StandardClock::default();
23//! let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
24//! let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
25//! client.set("keys_example:one", "value").await.unwrap();
26//!
27//! let command = KeysCommand::new("keys_example:*");
28//! let keys = client.send(command).await.unwrap();
29//! assert!(keys.contains(&Bytes::from_static(b"keys_example:one")));
30//! # });
31//! ```
32//!
33//! # Shorthand
34//! [Client::keys] accepts `&'static str`, `String`, or [Bytes] patterns and supports both RESP2 and RESP3.
35//! ```
36//! # async_std::task::block_on(async {
37//! # use core::net::SocketAddr;
38//! # use core::str::FromStr;
39//! # use bytes::Bytes;
40//! # use std_embedded_nal_async::Stack;
41//! # use std_embedded_time::StandardClock;
42//! # use embedded_redis::network::ConnectionHandler;
43//! # let stack = Stack::default();
44//! # let clock = StandardClock::default();
45//! # let mut connection_handler = ConnectionHandler::resp3(SocketAddr::from_str("127.0.0.1:6379").unwrap());
46//! # let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
47//! let keys = client.keys("keys_example:*").await.unwrap();
48//! let keys = client.keys("keys_example:*".to_string()).await.unwrap();
49//! let keys = client.keys(Bytes::from_static(b"keys_example:*")).await.unwrap();
50//! # });
51//! ```
52use crate::commands::auth::AuthCommand;
53use crate::commands::builder::{CommandBuilder, ToBytesVec};
54use crate::commands::hello::HelloCommand;
55use crate::commands::{Command, ResponseTypeError};
56use crate::network::protocol::Protocol;
57use crate::network::{Client, CommandErrors};
58use alloc::vec::Vec;
59use bytes::Bytes;
60use embedded_io_async::{Read, Write};
61use embedded_time::Clock;
62
63/// Abstraction of KEYS command.
64pub struct KeysCommand {
65 pattern: Bytes,
66}
67
68impl KeysCommand {
69 /// Creates a command with a Redis glob-style pattern. Use `*` to match all keys.
70 ///
71 /// Accepts `&'static str`, `String`, or [Bytes], including binary patterns.
72 pub fn new<K>(pattern: K) -> Self
73 where
74 Bytes: From<K>,
75 {
76 Self {
77 pattern: pattern.into(),
78 }
79 }
80}
81
82impl<F> Command<F> for KeysCommand
83where
84 F: From<CommandBuilder> + ToBytesVec,
85{
86 /// Matching keys, or an empty vector when no keys match.
87 type Response = Vec<Bytes>;
88
89 fn encode(&self) -> F {
90 CommandBuilder::new("KEYS").arg(&self.pattern).into()
91 }
92
93 fn eval_response(&self, frame: F) -> Result<Self::Response, ResponseTypeError> {
94 frame.to_vec().ok_or(ResponseTypeError {})
95 }
96}
97
98impl<'a, T: Read + Write, C: Clock, P: Protocol> Client<'a, T, C, P>
99where
100 AuthCommand: Command<<P as Protocol>::FrameType>,
101 HelloCommand: Command<<P as Protocol>::FrameType>,
102{
103 /// Shorthand for [KeysCommand]. Returns matching keys, or an empty vector if none match.
104 pub async fn keys<K>(&self, pattern: K) -> Result<Vec<Bytes>, CommandErrors>
105 where
106 <P as Protocol>::FrameType: ToBytesVec,
107 <P as Protocol>::FrameType: From<CommandBuilder>,
108 Bytes: From<K>,
109 {
110 self.send(KeysCommand::new(pattern)).await
111 }
112}