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}