ntex_redis/cmd/keys.rs
1use std::convert::{TryFrom, TryInto};
2
3use ntex::util::ByteString;
4
5use super::{utils, Command, CommandError};
6use crate::codec::{BulkString, Request, Response};
7
8/// DEL redis command
9///
10/// Removes the specified keys. A key is ignored if it does not exist.
11///
12/// ```rust
13/// use ntex_redis::{cmd, RedisConnector};
14/// # use rand::{thread_rng, Rng, distributions::Alphanumeric};
15/// # fn gen_random_key() -> String {
16/// # thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect::<String>()
17/// # }
18///
19/// #[ntex::main]
20/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
21/// let redis = RedisConnector::new("127.0.0.1:6379").connect().await?;
22/// let key = gen_random_key();
23///
24/// // set string value
25/// redis.exec(cmd::Set(&key, "value")).await?;
26///
27/// // remove keys
28/// let value = redis.exec(
29/// cmd::Del(&key).key("test_1").key("test_2")
30/// ).await?;
31///
32/// assert_eq!(value, 1);
33/// Ok(())
34/// }
35/// ```
36pub fn Del<T>(key: T) -> KeysCommand
37where
38 BulkString: From<T>,
39{
40 KeysCommand(vec![
41 Request::from_static("DEL"),
42 Request::BulkString(key.into()),
43 ])
44}
45
46/// EXISTS redis command
47///
48/// Returns if key exists.
49///
50/// ```rust
51/// use ntex_redis::{cmd, RedisConnector};
52/// # use rand::{thread_rng, Rng, distributions::Alphanumeric};
53/// # fn gen_random_key() -> String {
54/// # thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect::<String>()
55/// # }
56///
57/// #[ntex::main]
58/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
59/// let redis = RedisConnector::new("127.0.0.1:6379").connect().await?;
60/// let key = gen_random_key();
61///
62/// // set string value
63/// redis.exec(cmd::Set(&key, "value")).await?;
64///
65/// // check keys existence
66/// let value = redis.exec(
67/// cmd::Exists(&key).keys(vec!["test_1", "test_2"])
68/// ).await?;
69///
70/// assert_eq!(value, 1);
71/// Ok(())
72/// }
73/// ```
74pub fn Exists<T>(key: T) -> KeysCommand
75where
76 BulkString: From<T>,
77{
78 KeysCommand(vec![
79 Request::from_static("EXISTS"),
80 Request::BulkString(key.into()),
81 ])
82}
83
84pub struct KeysCommand(Vec<Request>);
85
86impl KeysCommand {
87 /// Add a key to this command.
88 pub fn key<T>(mut self, other: T) -> Self
89 where
90 BulkString: From<T>,
91 {
92 self.0.push(other.into());
93 self
94 }
95
96 /// Add more keys to this command.
97 pub fn keys<T>(mut self, other: impl IntoIterator<Item = T>) -> Self
98 where
99 BulkString: From<T>,
100 {
101 self.0.extend(other.into_iter().map(|t| t.into()));
102 self
103 }
104}
105
106impl Command for KeysCommand {
107 type Output = usize;
108
109 fn to_request(self) -> Request {
110 Request::Array(self.0)
111 }
112
113 fn to_output(val: Response) -> Result<Self::Output, CommandError> {
114 match val {
115 Response::Integer(val) => Ok(val as usize),
116 _ => Err(CommandError::Output("Cannot parse response", val)),
117 }
118 }
119}
120
121/// EXPIRE redis command
122///
123/// Set a timeout on `key`.
124pub fn Expire<T, S>(key: T, seconds: S) -> utils::BoolOutputCommand
125where
126 BulkString: From<T>,
127 i64: From<S>,
128{
129 utils::BoolOutputCommand(Request::Array(vec![
130 Request::from_static("EXPIRE"),
131 Request::BulkString(key.into()),
132 Request::BulkString(i64::from(seconds).to_string().into()),
133 ]))
134}
135
136/// EXPIREAT redis command
137///
138/// Set a timeout on `key`.
139pub fn ExpireAt<T, S>(key: T, timestamp: S) -> utils::BoolOutputCommand
140where
141 BulkString: From<T>,
142 i64: From<S>,
143{
144 utils::BoolOutputCommand(Request::Array(vec![
145 Request::from_static("EXPIREAT"),
146 Request::BulkString(key.into()),
147 Request::BulkString(i64::from(timestamp).to_string().into()),
148 ]))
149}
150
151/// TTL redis command
152///
153/// Returns the remaining time to live of a `key` that has a timeout.
154pub fn Ttl<T>(key: T) -> TtlCommand
155where
156 BulkString: From<T>,
157{
158 TtlCommand(vec![
159 Request::from_static("TTL"),
160 Request::BulkString(key.into()),
161 ])
162}
163
164#[derive(Debug, PartialEq, Eq)]
165pub enum TtlResult {
166 Seconds(i64),
167 NoExpire,
168 NotFound,
169}
170
171pub struct TtlCommand(Vec<Request>);
172
173impl Command for TtlCommand {
174 type Output = TtlResult;
175
176 fn to_request(self) -> Request {
177 Request::Array(self.0)
178 }
179
180 fn to_output(val: Response) -> Result<Self::Output, CommandError> {
181 let result = i64::try_from(val)?;
182 Ok(match result {
183 -1 => TtlResult::NoExpire,
184 -2 => TtlResult::NotFound,
185 s => TtlResult::Seconds(s),
186 })
187 }
188}
189
190/// KEYS redis command
191///
192/// Returns all keys matching pattern.
193///
194/// ```rust
195/// use ntex_redis::{cmd, RedisConnector};
196/// # use rand::{thread_rng, Rng, distributions::Alphanumeric};
197/// # fn gen_random_key() -> String {
198/// # thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect::<String>()
199/// # }
200///
201/// #[ntex::main]
202/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
203/// let redis = RedisConnector::new("127.0.0.1:6379").connect().await?;
204///
205/// // set keys
206/// redis.exec(cmd::Set("firstname", "Jack")).await?;
207/// redis.exec(cmd::Set("lastname", "Stuntman")).await?;
208///
209/// // get keys
210/// let mut keys = redis.exec(cmd::Keys("*name*")).await?;
211/// # keys.sort();
212///
213/// assert_eq!(&keys[..], &["firstname", "lastname"][..]);
214/// Ok(())
215/// }
216/// ```
217pub fn Keys<T>(key: T) -> KeysPatternCommand
218where
219 BulkString: From<T>,
220{
221 KeysPatternCommand(Request::Array(vec![
222 Request::from_static("KEYS"),
223 Request::BulkString(key.into()),
224 ]))
225}
226
227pub struct KeysPatternCommand(Request);
228
229impl Command for KeysPatternCommand {
230 type Output = Vec<ByteString>;
231
232 fn to_request(self) -> Request {
233 self.0
234 }
235
236 fn to_output(val: Response) -> Result<Self::Output, CommandError> {
237 match val.try_into() {
238 Ok(val) => Ok(val),
239 Err((_, val)) => Err(CommandError::Output("Cannot parse response", val)),
240 }
241 }
242}