mco_redis_rs/
commands.rs

1// can't use rustfmt here because it screws up the file.
2#![cfg_attr(rustfmt, rustfmt_skip)]
3use crate::cmd::{cmd, Cmd, Iter};
4use crate::connection::{Connection, ConnectionLike, Msg};
5use crate::pipeline::Pipeline;
6use crate::types::{FromRedisValue, NumericBehavior, RedisResult, ToRedisArgs, RedisWrite};
7
8#[cfg(feature = "cluster")]
9use crate::cluster_pipeline::ClusterPipeline;
10
11#[cfg(feature = "geospatial")]
12use crate::geo;
13
14#[cfg(feature = "streams")]
15use crate::streams;
16
17#[cfg(feature = "acl")]
18use crate::acl;
19
20macro_rules! implement_commands {
21    (
22        $lifetime: lifetime
23        $(
24            $(#[$attr:meta])+
25            fn $name:ident<$($tyargs:ident : $ty:ident),*>(
26                $($argname:ident: $argty:ty),*) $body:block
27        )*
28    ) =>
29    (
30        /// Implements common redis commands for connection like objects.  This
31        /// allows you to send commands straight to a connection or client.  It
32        /// is also implemented for redis results of clients which makes for
33        /// very convenient access in some basic cases.
34        ///
35        /// This allows you to use nicer syntax for some common operations.
36        /// For instance this code:
37        ///
38        /// ```rust,no_run
39        /// # fn do_something() -> redis::RedisResult<()> {
40        /// let client = redis::Client::open("redis://127.0.0.1/")?;
41        /// let mut con = client.get_connection()?;
42        /// redis::cmd("SET").arg("my_key").arg(42).execute(&mut con);
43        /// assert_eq!(redis::cmd("GET").arg("my_key").query(&mut con), Ok(42));
44        /// # Ok(()) }
45        /// ```
46        ///
47        /// Will become this:
48        ///
49        /// ```rust,no_run
50        /// # fn do_something() -> redis::RedisResult<()> {
51        /// use redis::Commands;
52        /// let client = redis::Client::open("redis://127.0.0.1/")?;
53        /// let mut con = client.get_connection()?;
54        /// con.set("my_key", 42)?;
55        /// assert_eq!(con.get("my_key"), Ok(42));
56        /// # Ok(()) }
57        /// ```
58        pub trait Commands : ConnectionLike+Sized {
59            $(
60                $(#[$attr])*
61                #[inline]
62                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
63                fn $name<$lifetime, $($tyargs: $ty, )* RV: FromRedisValue>(
64                    &mut self $(, $argname: $argty)*) -> RedisResult<RV>
65                    { Cmd::$name($($argname),*).query(self) }
66            )*
67
68            /// Incrementally iterate the keys space.
69            #[inline]
70            fn scan<RV: FromRedisValue>(&mut self) -> RedisResult<Iter<'_, RV>> {
71                let mut c = cmd("SCAN");
72                c.cursor_arg(0);
73                c.iter(self)
74            }
75
76            /// Incrementally iterate the keys space for keys matching a pattern.
77            #[inline]
78            fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> RedisResult<Iter<'_, RV>> {
79                let mut c = cmd("SCAN");
80                c.cursor_arg(0).arg("MATCH").arg(pattern);
81                c.iter(self)
82            }
83
84            /// Incrementally iterate hash fields and associated values.
85            #[inline]
86            fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
87                let mut c = cmd("HSCAN");
88                c.arg(key).cursor_arg(0);
89                c.iter(self)
90            }
91
92            /// Incrementally iterate hash fields and associated values for
93            /// field names matching a pattern.
94            #[inline]
95            fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
96                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
97                let mut c = cmd("HSCAN");
98                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
99                c.iter(self)
100            }
101
102            /// Incrementally iterate set elements.
103            #[inline]
104            fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
105                let mut c = cmd("SSCAN");
106                c.arg(key).cursor_arg(0);
107                c.iter(self)
108            }
109
110            /// Incrementally iterate set elements for elements matching a pattern.
111            #[inline]
112            fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
113                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
114                let mut c = cmd("SSCAN");
115                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
116                c.iter(self)
117            }
118
119            /// Incrementally iterate sorted set elements.
120            #[inline]
121            fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
122                let mut c = cmd("ZSCAN");
123                c.arg(key).cursor_arg(0);
124                c.iter(self)
125            }
126
127            /// Incrementally iterate sorted set elements for elements matching a pattern.
128            #[inline]
129            fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
130                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
131                let mut c = cmd("ZSCAN");
132                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
133                c.iter(self)
134            }
135        }
136
137        impl Cmd {
138            $(
139                $(#[$attr])*
140                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
141                pub fn $name<$lifetime, $($tyargs: $ty),*>($($argname: $argty),*) -> Self {
142                    ::std::mem::replace($body, Cmd::new())
143                }
144            )*
145        }
146
147        /// Implements common redis commands over asynchronous connections. This
148        /// allows you to send commands straight to a connection or client.
149        ///
150        /// This allows you to use nicer syntax for some common operations.
151        /// For instance this code:
152        ///
153        /// ```rust,no_run
154        /// use redis::AsyncCommands;
155        /// # async fn do_something() -> redis::RedisResult<()> {
156        /// let client = redis::Client::open("redis://127.0.0.1/")?;
157        /// let mut con = client.get_async_connection().await?;
158        /// redis::cmd("SET").arg("my_key").arg(42i32).query_async(&mut con).await?;
159        /// assert_eq!(redis::cmd("GET").arg("my_key").query_async(&mut con).await, Ok(42i32));
160        /// # Ok(()) }
161        /// ```
162        ///
163        /// Will become this:
164        ///
165        /// ```rust,no_run
166        /// use redis::AsyncCommands;
167        /// # async fn do_something() -> redis::RedisResult<()> {
168        /// use redis::Commands;
169        /// let client = redis::Client::open("redis://127.0.0.1/")?;
170        /// let mut con = client.get_async_connection().await?;
171        /// con.set("my_key", 42i32).await?;
172        /// assert_eq!(con.get("my_key").await, Ok(42i32));
173        /// # Ok(()) }
174        /// ```
175        #[cfg(feature = "aio")]
176        pub trait AsyncCommands : crate::aio::ConnectionLike + Send + Sized {
177            $(
178                $(#[$attr])*
179                #[inline]
180                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
181                fn $name<$lifetime, $($tyargs: $ty + Send + Sync + $lifetime,)* RV>(
182                    & $lifetime mut self
183                    $(, $argname: $argty)*
184                ) -> crate::types::RedisFuture<'a, RV>
185                where
186                    RV: FromRedisValue,
187                {
188                    Box::pin(async move { ($body).query_async(self).await })
189                }
190            )*
191
192            /// Incrementally iterate the keys space.
193            #[inline]
194            fn scan<RV: FromRedisValue>(&mut self) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
195                let mut c = cmd("SCAN");
196                c.cursor_arg(0);
197                Box::pin(async move { c.iter_async(self).await })
198            }
199
200            /// Incrementally iterate set elements for elements matching a pattern.
201            #[inline]
202            fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
203                let mut c = cmd("SCAN");
204                c.cursor_arg(0).arg("MATCH").arg(pattern);
205                Box::pin(async move { c.iter_async(self).await })
206            }
207
208            /// Incrementally iterate hash fields and associated values.
209            #[inline]
210            fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
211                let mut c = cmd("HSCAN");
212                c.arg(key).cursor_arg(0);
213                Box::pin(async move {c.iter_async(self).await })
214            }
215
216            /// Incrementally iterate hash fields and associated values for
217            /// field names matching a pattern.
218            #[inline]
219            fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
220                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
221                let mut c = cmd("HSCAN");
222                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
223                Box::pin(async move {c.iter_async(self).await })
224            }
225
226            /// Incrementally iterate set elements.
227            #[inline]
228            fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
229                let mut c = cmd("SSCAN");
230                c.arg(key).cursor_arg(0);
231                Box::pin(async move {c.iter_async(self).await })
232            }
233
234            /// Incrementally iterate set elements for elements matching a pattern.
235            #[inline]
236            fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
237                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
238                let mut c = cmd("SSCAN");
239                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
240                Box::pin(async move {c.iter_async(self).await })
241            }
242
243            /// Incrementally iterate sorted set elements.
244            #[inline]
245            fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
246                let mut c = cmd("ZSCAN");
247                c.arg(key).cursor_arg(0);
248                Box::pin(async move {c.iter_async(self).await })
249            }
250
251            /// Incrementally iterate sorted set elements for elements matching a pattern.
252            #[inline]
253            fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
254                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
255                let mut c = cmd("ZSCAN");
256                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
257                Box::pin(async move {c.iter_async(self).await })
258            }
259        }
260
261        /// Implements common redis commands for pipelines.  Unlike the regular
262        /// commands trait, this returns the pipeline rather than a result
263        /// directly.  Other than that it works the same however.
264        impl Pipeline {
265            $(
266                $(#[$attr])*
267                #[inline]
268                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
269                pub fn $name<$lifetime, $($tyargs: $ty),*>(
270                    &mut self $(, $argname: $argty)*
271                ) -> &mut Self {
272                    self.add_command(::std::mem::replace($body, Cmd::new()))
273                }
274            )*
275        }
276
277        // Implements common redis commands for cluster pipelines.  Unlike the regular
278        // commands trait, this returns the cluster pipeline rather than a result
279        // directly.  Other than that it works the same however.
280        #[cfg(feature = "cluster")]
281        impl ClusterPipeline {
282            $(
283                $(#[$attr])*
284                #[inline]
285                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
286                pub fn $name<$lifetime, $($tyargs: $ty),*>(
287                    &mut self $(, $argname: $argty)*
288                ) -> &mut Self {
289                    self.add_command(::std::mem::replace($body, Cmd::new()))
290                }
291            )*
292        }
293    )
294}
295
296implement_commands! {
297    'a
298    // most common operations
299
300    /// Get the value of a key.  If key is a vec this becomes an `MGET`.
301    fn get<K: ToRedisArgs>(key: K) {
302        cmd(if key.is_single_arg() { "GET" } else { "MGET" }).arg(key)
303    }
304
305    /// Gets all keys matching pattern
306    fn keys<K: ToRedisArgs>(key: K) {
307        cmd("KEYS").arg(key)
308    }
309
310    /// Set the string value of a key.
311    fn set<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
312        cmd("SET").arg(key).arg(value)
313    }
314
315    /// Sets multiple keys to their values.
316    fn set_multiple<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
317        cmd("MSET").arg(items)
318    }
319
320    /// Set the value and expiration of a key.
321    fn set_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, seconds: usize) {
322        cmd("SETEX").arg(key).arg(seconds).arg(value)
323    }
324
325    /// Set the value and expiration in milliseconds of a key.
326    fn pset_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, milliseconds: usize) {
327        cmd("PSETEX").arg(key).arg(milliseconds).arg(value)
328    }
329
330    /// Set the value of a key, only if the key does not exist
331    fn set_nx<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
332        cmd("SETNX").arg(key).arg(value)
333    }
334
335    /// Sets multiple keys to their values failing if at least one already exists.
336    fn mset_nx<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
337        cmd("MSETNX").arg(items)
338    }
339
340    /// Set the string value of a key and return its old value.
341    fn getset<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
342        cmd("GETSET").arg(key).arg(value)
343    }
344
345    /// Get a range of bytes/substring from the value of a key. Negative values provide an offset from the end of the value.
346    fn getrange<K: ToRedisArgs>(key: K, from: isize, to: isize) {
347        cmd("GETRANGE").arg(key).arg(from).arg(to)
348    }
349
350    /// Overwrite the part of the value stored in key at the specified offset.
351    fn setrange<K: ToRedisArgs, V: ToRedisArgs>(key: K, offset: isize, value: V) {
352        cmd("SETRANGE").arg(key).arg(offset).arg(value)
353    }
354
355    /// Delete one or more keys.
356    fn del<K: ToRedisArgs>(key: K) {
357        cmd("DEL").arg(key)
358    }
359
360    /// Determine if a key exists.
361    fn exists<K: ToRedisArgs>(key: K) {
362        cmd("EXISTS").arg(key)
363    }
364
365    /// Set a key's time to live in seconds.
366    fn expire<K: ToRedisArgs>(key: K, seconds: usize) {
367        cmd("EXPIRE").arg(key).arg(seconds)
368    }
369
370    /// Set the expiration for a key as a UNIX timestamp.
371    fn expire_at<K: ToRedisArgs>(key: K, ts: usize) {
372        cmd("EXPIREAT").arg(key).arg(ts)
373    }
374
375    /// Set a key's time to live in milliseconds.
376    fn pexpire<K: ToRedisArgs>(key: K, ms: usize) {
377        cmd("PEXPIRE").arg(key).arg(ms)
378    }
379
380    /// Set the expiration for a key as a UNIX timestamp in milliseconds.
381    fn pexpire_at<K: ToRedisArgs>(key: K, ts: usize) {
382        cmd("PEXPIREAT").arg(key).arg(ts)
383    }
384
385    /// Remove the expiration from a key.
386    fn persist<K: ToRedisArgs>(key: K) {
387        cmd("PERSIST").arg(key)
388    }
389
390    /// Get the expiration time of a key.
391    fn ttl<K: ToRedisArgs>(key: K) {
392        cmd("TTL").arg(key)
393    }
394
395    /// Get the expiration time of a key in milliseconds.
396    fn pttl<K: ToRedisArgs>(key: K) {
397        cmd("PTTL").arg(key)
398    }
399
400    /// Rename a key.
401    fn rename<K: ToRedisArgs>(key: K, new_key: K) {
402        cmd("RENAME").arg(key).arg(new_key)
403    }
404
405    /// Rename a key, only if the new key does not exist.
406    fn rename_nx<K: ToRedisArgs>(key: K, new_key: K) {
407        cmd("RENAMENX").arg(key).arg(new_key)
408    }
409
410    /// Unlink one or more keys.
411    fn unlink<K: ToRedisArgs>(key: K) {
412        cmd("UNLINK").arg(key)
413    }
414
415    // common string operations
416
417    /// Append a value to a key.
418    fn append<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
419        cmd("APPEND").arg(key).arg(value)
420    }
421
422    /// Increment the numeric value of a key by the given amount.  This
423    /// issues a `INCRBY` or `INCRBYFLOAT` depending on the type.
424    fn incr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
425        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
426            "INCRBYFLOAT"
427        } else {
428            "INCRBY"
429        }).arg(key).arg(delta)
430    }
431
432    /// Decrement the numeric value of a key by the given amount.
433    fn decr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
434        cmd("DECRBY").arg(key).arg(delta)
435    }
436
437    /// Sets or clears the bit at offset in the string value stored at key.
438    fn setbit<K: ToRedisArgs>(key: K, offset: usize, value: bool) {
439        cmd("SETBIT").arg(key).arg(offset).arg(if value {1} else {0})
440    }
441
442    /// Returns the bit value at offset in the string value stored at key.
443    fn getbit<K: ToRedisArgs>(key: K, offset: usize) {
444        cmd("GETBIT").arg(key).arg(offset)
445    }
446
447    /// Count set bits in a string.
448    fn bitcount<K: ToRedisArgs>(key: K) {
449        cmd("BITCOUNT").arg(key)
450    }
451
452    /// Count set bits in a string in a range.
453    fn bitcount_range<K: ToRedisArgs>(key: K, start: usize, end: usize) {
454        cmd("BITCOUNT").arg(key).arg(start).arg(end)
455    }
456
457    /// Perform a bitwise AND between multiple keys (containing string values)
458    /// and store the result in the destination key.
459    fn bit_and<K: ToRedisArgs>(dstkey: K, srckeys: K) {
460        cmd("BITOP").arg("AND").arg(dstkey).arg(srckeys)
461    }
462
463    /// Perform a bitwise OR between multiple keys (containing string values)
464    /// and store the result in the destination key.
465    fn bit_or<K: ToRedisArgs>(dstkey: K, srckeys: K) {
466        cmd("BITOP").arg("OR").arg(dstkey).arg(srckeys)
467    }
468
469    /// Perform a bitwise XOR between multiple keys (containing string values)
470    /// and store the result in the destination key.
471    fn bit_xor<K: ToRedisArgs>(dstkey: K, srckeys: K) {
472        cmd("BITOP").arg("XOR").arg(dstkey).arg(srckeys)
473    }
474
475    /// Perform a bitwise NOT of the key (containing string values)
476    /// and store the result in the destination key.
477    fn bit_not<K: ToRedisArgs>(dstkey: K, srckey: K) {
478        cmd("BITOP").arg("NOT").arg(dstkey).arg(srckey)
479    }
480
481    /// Get the length of the value stored in a key.
482    fn strlen<K: ToRedisArgs>(key: K) {
483        cmd("STRLEN").arg(key)
484    }
485
486    // hash operations
487
488    /// Gets a single (or multiple) fields from a hash.
489    fn hget<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
490        cmd(if field.is_single_arg() { "HGET" } else { "HMGET" }).arg(key).arg(field)
491    }
492
493    /// Deletes a single (or multiple) fields from a hash.
494    fn hdel<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
495        cmd("HDEL").arg(key).arg(field)
496    }
497
498    /// Sets a single field in a hash.
499    fn hset<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
500        cmd("HSET").arg(key).arg(field).arg(value)
501    }
502
503    /// Sets a single field in a hash if it does not exist.
504    fn hset_nx<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
505        cmd("HSETNX").arg(key).arg(field).arg(value)
506    }
507
508    /// Sets a multiple fields in a hash.
509    fn hset_multiple<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, items: &'a [(F, V)]) {
510        cmd("HMSET").arg(key).arg(items)
511    }
512
513    /// Increments a value.
514    fn hincr<K: ToRedisArgs, F: ToRedisArgs, D: ToRedisArgs>(key: K, field: F, delta: D) {
515        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
516            "HINCRBYFLOAT"
517        } else {
518            "HINCRBY"
519        }).arg(key).arg(field).arg(delta)
520    }
521
522    /// Checks if a field in a hash exists.
523    fn hexists<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
524        cmd("HEXISTS").arg(key).arg(field)
525    }
526
527    /// Gets all the keys in a hash.
528    fn hkeys<K: ToRedisArgs>(key: K) {
529        cmd("HKEYS").arg(key)
530    }
531
532    /// Gets all the values in a hash.
533    fn hvals<K: ToRedisArgs>(key: K) {
534        cmd("HVALS").arg(key)
535    }
536
537    /// Gets all the fields and values in a hash.
538    fn hgetall<K: ToRedisArgs>(key: K) {
539        cmd("HGETALL").arg(key)
540    }
541
542    /// Gets the length of a hash.
543    fn hlen<K: ToRedisArgs>(key: K) {
544        cmd("HLEN").arg(key)
545    }
546
547    // list operations
548    
549    /// Pop an element from a list, push it to another list
550    /// and return it; or block until one is available
551    fn blmove<K: ToRedisArgs>(srckey: K, dstkey: K, src_dir: Direction, dst_dir: Direction, timeout: usize) {
552        cmd("BLMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir).arg(timeout)
553    }
554
555    /// Pops `count` elements from the first non-empty list key from the list of 
556    /// provided key names; or blocks until one is available.
557    fn blmpop<K: ToRedisArgs>(timeout: usize, numkeys: usize, key: K, dir: Direction, count: usize){
558        cmd("BLMPOP").arg(timeout).arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
559    }
560
561    /// Remove and get the first element in a list, or block until one is available.
562    fn blpop<K: ToRedisArgs>(key: K, timeout: usize) {
563        cmd("BLPOP").arg(key).arg(timeout)
564    }
565
566    /// Remove and get the last element in a list, or block until one is available.
567    fn brpop<K: ToRedisArgs>(key: K, timeout: usize) {
568        cmd("BRPOP").arg(key).arg(timeout)
569    }
570
571    /// Pop a value from a list, push it to another list and return it;
572    /// or block until one is available.
573    fn brpoplpush<K: ToRedisArgs>(srckey: K, dstkey: K, timeout: usize) {
574        cmd("BRPOPLPUSH").arg(srckey).arg(dstkey).arg(timeout)
575    }
576
577    /// Get an element from a list by its index.
578    fn lindex<K: ToRedisArgs>(key: K, index: isize) {
579        cmd("LINDEX").arg(key).arg(index)
580    }
581
582    /// Insert an element before another element in a list.
583    fn linsert_before<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
584            key: K, pivot: P, value: V) {
585        cmd("LINSERT").arg(key).arg("BEFORE").arg(pivot).arg(value)
586    }
587
588    /// Insert an element after another element in a list.
589    fn linsert_after<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
590            key: K, pivot: P, value: V) {
591        cmd("LINSERT").arg(key).arg("AFTER").arg(pivot).arg(value)
592    }
593
594    /// Returns the length of the list stored at key.
595    fn llen<K: ToRedisArgs>(key: K) {
596        cmd("LLEN").arg(key)
597    }
598
599    /// Pop an element a list, push it to another list and return it
600    fn lmove<K: ToRedisArgs>(srckey: K, dstkey: K, src_dir: Direction, dst_dir: Direction) {
601        cmd("LMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir)
602    }
603
604    /// Pops `count` elements from the first non-empty list key from the list of 
605    /// provided key names.
606    fn lmpop<K: ToRedisArgs>( numkeys: usize, key: K, dir: Direction, count: usize) {
607        cmd("LMPOP").arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
608    }
609
610    /// Removes and returns the up to `count` first elements of the list stored at key.
611    ///
612    /// If `count` is not specified, then defaults to first element.
613    fn lpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
614        cmd("LPOP").arg(key).arg(count)
615    }
616
617    /// Returns the index of the first matching value of the list stored at key.
618    fn lpos<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: LposOptions) {
619        cmd("LPOS").arg(key).arg(value).arg(options)
620    }
621
622    /// Insert all the specified values at the head of the list stored at key.
623    fn lpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
624        cmd("LPUSH").arg(key).arg(value)
625    }
626
627    /// Inserts a value at the head of the list stored at key, only if key
628    /// already exists and holds a list.
629    fn lpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
630        cmd("LPUSHX").arg(key).arg(value)
631    }
632
633    /// Returns the specified elements of the list stored at key.
634    fn lrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
635        cmd("LRANGE").arg(key).arg(start).arg(stop)
636    }
637
638    /// Removes the first count occurrences of elements equal to value
639    /// from the list stored at key.
640    fn lrem<K: ToRedisArgs, V: ToRedisArgs>(key: K, count: isize, value: V) {
641        cmd("LREM").arg(key).arg(count).arg(value)
642    }
643
644    /// Trim an existing list so that it will contain only the specified
645    /// range of elements specified.
646    fn ltrim<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
647        cmd("LTRIM").arg(key).arg(start).arg(stop)
648    }
649
650    /// Sets the list element at index to value
651    fn lset<K: ToRedisArgs, V: ToRedisArgs>(key: K, index: isize, value: V) {
652        cmd("LSET").arg(key).arg(index).arg(value)
653    }
654
655    /// Removes and returns the up to `count` last elements of the list stored at key
656    ///
657    /// If `count` is not specified, then defaults to last element.
658    fn rpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
659        cmd("RPOP").arg(key).arg(count)
660    }
661
662    /// Pop a value from a list, push it to another list and return it.
663    fn rpoplpush<K: ToRedisArgs>(key: K, dstkey: K) {
664        cmd("RPOPLPUSH").arg(key).arg(dstkey)
665    }
666
667    /// Insert all the specified values at the tail of the list stored at key.
668    fn rpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
669        cmd("RPUSH").arg(key).arg(value)
670    }
671
672    /// Inserts value at the tail of the list stored at key, only if key
673    /// already exists and holds a list.
674    fn rpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
675        cmd("RPUSHX").arg(key).arg(value)
676    }
677
678    // set commands
679
680    /// Add one or more members to a set.
681    fn sadd<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
682        cmd("SADD").arg(key).arg(member)
683    }
684
685    /// Get the number of members in a set.
686    fn scard<K: ToRedisArgs>(key: K) {
687        cmd("SCARD").arg(key)
688    }
689
690    /// Subtract multiple sets.
691    fn sdiff<K: ToRedisArgs>(keys: K) {
692        cmd("SDIFF").arg(keys)
693    }
694
695    /// Subtract multiple sets and store the resulting set in a key.
696    fn sdiffstore<K: ToRedisArgs>(dstkey: K, keys: K) {
697        cmd("SDIFFSTORE").arg(dstkey).arg(keys)
698    }
699
700    /// Intersect multiple sets.
701    fn sinter<K: ToRedisArgs>(keys: K) {
702        cmd("SINTER").arg(keys)
703    }
704
705    /// Intersect multiple sets and store the resulting set in a key.
706    fn sinterstore<K: ToRedisArgs>(dstkey: K, keys: K) {
707        cmd("SINTERSTORE").arg(dstkey).arg(keys)
708    }
709
710    /// Determine if a given value is a member of a set.
711    fn sismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
712        cmd("SISMEMBER").arg(key).arg(member)
713    }
714
715    /// Get all the members in a set.
716    fn smembers<K: ToRedisArgs>(key: K) {
717        cmd("SMEMBERS").arg(key)
718    }
719
720    /// Move a member from one set to another.
721    fn smove<K: ToRedisArgs, M: ToRedisArgs>(srckey: K, dstkey: K, member: M) {
722        cmd("SMOVE").arg(srckey).arg(dstkey).arg(member)
723    }
724
725    /// Remove and return a random member from a set.
726    fn spop<K: ToRedisArgs>(key: K) {
727        cmd("SPOP").arg(key)
728    }
729
730    /// Get one random member from a set.
731    fn srandmember<K: ToRedisArgs>(key: K) {
732        cmd("SRANDMEMBER").arg(key)
733    }
734
735    /// Get multiple random members from a set.
736    fn srandmember_multiple<K: ToRedisArgs>(key: K, count: usize) {
737        cmd("SRANDMEMBER").arg(key).arg(count)
738    }
739
740    /// Remove one or more members from a set.
741    fn srem<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
742        cmd("SREM").arg(key).arg(member)
743    }
744
745    /// Add multiple sets.
746    fn sunion<K: ToRedisArgs>(keys: K) {
747        cmd("SUNION").arg(keys)
748    }
749
750    /// Add multiple sets and store the resulting set in a key.
751    fn sunionstore<K: ToRedisArgs>(dstkey: K, keys: K) {
752        cmd("SUNIONSTORE").arg(dstkey).arg(keys)
753    }
754
755    // sorted set commands
756
757    /// Add one member to a sorted set, or update its score if it already exists.
758    fn zadd<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, member: M, score: S) {
759        cmd("ZADD").arg(key).arg(score).arg(member)
760    }
761
762    /// Add multiple members to a sorted set, or update its score if it already exists.
763    fn zadd_multiple<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)]) {
764        cmd("ZADD").arg(key).arg(items)
765    }
766
767    /// Get the number of members in a sorted set.
768    fn zcard<K: ToRedisArgs>(key: K) {
769        cmd("ZCARD").arg(key)
770    }
771
772    /// Count the members in a sorted set with scores within the given values.
773    fn zcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
774        cmd("ZCOUNT").arg(key).arg(min).arg(max)
775    }
776
777    /// Increments the member in a sorted set at key by delta.
778    /// If the member does not exist, it is added with delta as its score.
779    fn zincr<K: ToRedisArgs, M: ToRedisArgs, D: ToRedisArgs>(key: K, member: M, delta: D) {
780        cmd("ZINCRBY").arg(key).arg(delta).arg(member)
781    }
782
783    /// Intersect multiple sorted sets and store the resulting sorted set in
784    /// a new key using SUM as aggregation function.
785    fn zinterstore<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
786        cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys)
787    }
788
789    /// Intersect multiple sorted sets and store the resulting sorted set in
790    /// a new key using MIN as aggregation function.
791    fn zinterstore_min<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
792        cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MIN")
793    }
794
795    /// Intersect multiple sorted sets and store the resulting sorted set in
796    /// a new key using MAX as aggregation function.
797    fn zinterstore_max<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
798        cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MAX")
799    }
800
801    /// Count the number of members in a sorted set between a given lexicographical range.
802    fn zlexcount<K: ToRedisArgs, L: ToRedisArgs>(key: K, min: L, max: L) {
803        cmd("ZLEXCOUNT").arg(key).arg(min).arg(max)
804    }
805
806    /// Removes and returns up to count members with the highest scores in a sorted set
807    fn zpopmax<K: ToRedisArgs>(key: K, count: isize) {
808        cmd("ZPOPMAX").arg(key).arg(count)
809    }
810
811    /// Removes and returns up to count members with the lowest scores in a sorted set
812    fn zpopmin<K: ToRedisArgs>(key: K, count: isize) {
813        cmd("ZPOPMIN").arg(key).arg(count)
814    }
815
816    /// Return up to count random members in a sorted set (or 1 if `count == None`)
817    fn zrandmember<K: ToRedisArgs>(key: K, count: Option<isize>) {
818        cmd("ZRANDMEMBER").arg(key).arg(count)
819    }
820
821    /// Return up to count random members in a sorted set with scores
822    fn zrandmember_withscores<K: ToRedisArgs>(key: K, count: isize) {
823        cmd("ZRANDMEMBER").arg(key).arg(count).arg("WITHSCORES")
824    }
825
826    /// Return a range of members in a sorted set, by index
827    fn zrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
828        cmd("ZRANGE").arg(key).arg(start).arg(stop)
829    }
830
831    /// Return a range of members in a sorted set, by index with scores.
832    fn zrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
833        cmd("ZRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
834    }
835
836    /// Return a range of members in a sorted set, by lexicographical range.
837    fn zrangebylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
838        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max)
839    }
840
841    /// Return a range of members in a sorted set, by lexicographical
842    /// range with offset and limit.
843    fn zrangebylex_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(
844            key: K, min: M, max: MM, offset: isize, count: isize) {
845        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
846    }
847
848    /// Return a range of members in a sorted set, by lexicographical range.
849    fn zrevrangebylex<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
850        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min)
851    }
852
853    /// Return a range of members in a sorted set, by lexicographical
854    /// range with offset and limit.
855    fn zrevrangebylex_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(
856            key: K, max: MM, min: M, offset: isize, count: isize) {
857        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
858    }
859
860    /// Return a range of members in a sorted set, by score.
861    fn zrangebyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
862        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max)
863    }
864
865    /// Return a range of members in a sorted set, by score with scores.
866    fn zrangebyscore_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
867        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
868    }
869
870    /// Return a range of members in a sorted set, by score with limit.
871    fn zrangebyscore_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
872            (key: K, min: M, max: MM, offset: isize, count: isize) {
873        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
874    }
875
876    /// Return a range of members in a sorted set, by score with limit with scores.
877    fn zrangebyscore_limit_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
878            (key: K, min: M, max: MM, offset: isize, count: isize) {
879        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
880            .arg("LIMIT").arg(offset).arg(count)
881    }
882
883    /// Determine the index of a member in a sorted set.
884    fn zrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
885        cmd("ZRANK").arg(key).arg(member)
886    }
887
888    /// Remove one or more members from a sorted set.
889    fn zrem<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
890        cmd("ZREM").arg(key).arg(members)
891    }
892
893    /// Remove all members in a sorted set between the given lexicographical range.
894    fn zrembylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
895        cmd("ZREMRANGEBYLEX").arg(key).arg(min).arg(max)
896    }
897
898    /// Remove all members in a sorted set within the given indexes.
899    fn zremrangebyrank<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
900        cmd("ZREMRANGEBYRANK").arg(key).arg(start).arg(stop)
901    }
902
903    /// Remove all members in a sorted set within the given scores.
904    fn zrembyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
905        cmd("ZREMRANGEBYSCORE").arg(key).arg(min).arg(max)
906    }
907
908    /// Return a range of members in a sorted set, by index, with scores
909    /// ordered from high to low.
910    fn zrevrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
911        cmd("ZREVRANGE").arg(key).arg(start).arg(stop)
912    }
913
914    /// Return a range of members in a sorted set, by index, with scores
915    /// ordered from high to low.
916    fn zrevrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
917        cmd("ZREVRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
918    }
919
920    /// Return a range of members in a sorted set, by score.
921    fn zrevrangebyscore<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
922        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min)
923    }
924
925    /// Return a range of members in a sorted set, by score with scores.
926    fn zrevrangebyscore_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
927        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
928    }
929
930    /// Return a range of members in a sorted set, by score with limit.
931    fn zrevrangebyscore_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
932            (key: K, max: MM, min: M, offset: isize, count: isize) {
933        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
934    }
935
936    /// Return a range of members in a sorted set, by score with limit with scores.
937    fn zrevrangebyscore_limit_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
938            (key: K, max: MM, min: M, offset: isize, count: isize) {
939        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
940            .arg("LIMIT").arg(offset).arg(count)
941    }
942
943    /// Determine the index of a member in a sorted set, with scores ordered from high to low.
944    fn zrevrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
945        cmd("ZREVRANK").arg(key).arg(member)
946    }
947
948    /// Get the score associated with the given member in a sorted set.
949    fn zscore<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
950        cmd("ZSCORE").arg(key).arg(member)
951    }
952
953    /// Get the scores associated with multiple members in a sorted set.
954    fn zscore_multiple<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: &'a [M]) {
955        cmd("ZMSCORE").arg(key).arg(members)
956    }
957
958    /// Unions multiple sorted sets and store the resulting sorted set in
959    /// a new key using SUM as aggregation function.
960    fn zunionstore<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
961        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys)
962    }
963
964    /// Unions multiple sorted sets and store the resulting sorted set in
965    /// a new key using MIN as aggregation function.
966    fn zunionstore_min<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
967        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MIN")
968    }
969
970    /// Unions multiple sorted sets and store the resulting sorted set in
971    /// a new key using MAX as aggregation function.
972    fn zunionstore_max<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
973        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MAX")
974    }
975
976    // hyperloglog commands
977
978    /// Adds the specified elements to the specified HyperLogLog.
979    fn pfadd<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) {
980        cmd("PFADD").arg(key).arg(element)
981    }
982
983    /// Return the approximated cardinality of the set(s) observed by the
984    /// HyperLogLog at key(s).
985    fn pfcount<K: ToRedisArgs>(key: K) {
986        cmd("PFCOUNT").arg(key)
987    }
988
989    /// Merge N different HyperLogLogs into a single one.
990    fn pfmerge<K: ToRedisArgs>(dstkey: K, srckeys: K) {
991        cmd("PFMERGE").arg(dstkey).arg(srckeys)
992    }
993
994    /// Posts a message to the given channel.
995    fn publish<K: ToRedisArgs, E: ToRedisArgs>(channel: K, message: E) {
996        cmd("PUBLISH").arg(channel).arg(message)
997    }
998
999    // ACL commands
1000
1001    /// When Redis is configured to use an ACL file (with the aclfile
1002    /// configuration option), this command will reload the ACLs from the file,
1003    /// replacing all the current ACL rules with the ones defined in the file.
1004    #[cfg(feature = "acl")]
1005    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1006    fn acl_load<>() {
1007        cmd("ACL").arg("LOAD")
1008    }
1009
1010    /// When Redis is configured to use an ACL file (with the aclfile
1011    /// configuration option), this command will save the currently defined
1012    /// ACLs from the server memory to the ACL file.
1013    #[cfg(feature = "acl")]
1014    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1015    fn acl_save<>() {
1016        cmd("ACL").arg("SAVE")
1017    }
1018
1019    /// Shows the currently active ACL rules in the Redis server.
1020    #[cfg(feature = "acl")]
1021    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1022    fn acl_list<>() {
1023        cmd("ACL").arg("LIST")
1024    }
1025
1026    /// Shows a list of all the usernames of the currently configured users in
1027    /// the Redis ACL system.
1028    #[cfg(feature = "acl")]
1029    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1030    fn acl_users<>() {
1031        cmd("ACL").arg("USERS")
1032    }
1033
1034    /// Returns all the rules defined for an existing ACL user.
1035    #[cfg(feature = "acl")]
1036    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1037    fn acl_getuser<K: ToRedisArgs>(username: K) {
1038        cmd("ACL").arg("GETUSER").arg(username)
1039    }
1040
1041    /// Creates an ACL user without any privilege.
1042    #[cfg(feature = "acl")]
1043    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1044    fn acl_setuser<K: ToRedisArgs>(username: K) {
1045        cmd("ACL").arg("SETUSER").arg(username)
1046    }
1047
1048    /// Creates an ACL user with the specified rules or modify the rules of
1049    /// an existing user.
1050    #[cfg(feature = "acl")]
1051    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1052    fn acl_setuser_rules<K: ToRedisArgs>(username: K, rules: &'a [acl::Rule]) {
1053        cmd("ACL").arg("SETUSER").arg(username).arg(rules)
1054    }
1055
1056    /// Delete all the specified ACL users and terminate all the connections
1057    /// that are authenticated with such users.
1058    #[cfg(feature = "acl")]
1059    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1060    fn acl_deluser<K: ToRedisArgs>(usernames: &'a [K]) {
1061        cmd("ACL").arg("DELUSER").arg(usernames)
1062    }
1063
1064    /// Shows the available ACL categories.
1065    #[cfg(feature = "acl")]
1066    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1067    fn acl_cat<>() {
1068        cmd("ACL").arg("CAT")
1069    }
1070
1071    /// Shows all the Redis commands in the specified category.
1072    #[cfg(feature = "acl")]
1073    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1074    fn acl_cat_categoryname<K: ToRedisArgs>(categoryname: K) {
1075        cmd("ACL").arg("CAT").arg(categoryname)
1076    }
1077
1078    /// Generates a 256-bits password starting from /dev/urandom if available.
1079    #[cfg(feature = "acl")]
1080    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1081    fn acl_genpass<>() {
1082        cmd("ACL").arg("GENPASS")
1083    }
1084
1085    /// Generates a 1-to-1024-bits password starting from /dev/urandom if available.
1086    #[cfg(feature = "acl")]
1087    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1088    fn acl_genpass_bits<>(bits: isize) {
1089        cmd("ACL").arg("GENPASS").arg(bits)
1090    }
1091
1092    /// Returns the username the current connection is authenticated with.
1093    #[cfg(feature = "acl")]
1094    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1095    fn acl_whoami<>() {
1096        cmd("ACL").arg("WHOAMI")
1097    }
1098
1099    /// Shows a list of recent ACL security events
1100    #[cfg(feature = "acl")]
1101    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1102    fn acl_log<>(count: isize) {
1103        cmd("ACL").arg("LOG").arg(count)
1104
1105    }
1106
1107    /// Clears the ACL log.
1108    #[cfg(feature = "acl")]
1109    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1110    fn acl_log_reset<>() {
1111        cmd("ACL").arg("LOG").arg("RESET")
1112    }
1113
1114    /// Returns a helpful text describing the different subcommands.
1115    #[cfg(feature = "acl")]
1116    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1117    fn acl_help<>() {
1118        cmd("ACL").arg("HELP")
1119    }
1120
1121    //
1122    // geospatial commands
1123    //
1124
1125    /// Adds the specified geospatial items to the specified key.
1126    ///
1127    /// Every member has to be written as a tuple of `(longitude, latitude,
1128    /// member_name)`. It can be a single tuple, or a vector of tuples.
1129    ///
1130    /// `longitude, latitude` can be set using [`redis::geo::Coord`][1].
1131    ///
1132    /// [1]: ./geo/struct.Coord.html
1133    ///
1134    /// Returns the number of elements added to the sorted set, not including
1135    /// elements already existing for which the score was updated.
1136    ///
1137    /// # Example
1138    ///
1139    /// ```rust,no_run
1140    /// use redis::{Commands, Connection, RedisResult};
1141    /// use redis::geo::Coord;
1142    ///
1143    /// fn add_point(con: &mut Connection) -> RedisResult<isize> {
1144    ///     con.geo_add("my_gis", (Coord::lon_lat(13.361389, 38.115556), "Palermo"))
1145    /// }
1146    ///
1147    /// fn add_point_with_tuples(con: &mut Connection) -> RedisResult<isize> {
1148    ///     con.geo_add("my_gis", ("13.361389", "38.115556", "Palermo"))
1149    /// }
1150    ///
1151    /// fn add_many_points(con: &mut Connection) -> RedisResult<isize> {
1152    ///     con.geo_add("my_gis", &[
1153    ///         ("13.361389", "38.115556", "Palermo"),
1154    ///         ("15.087269", "37.502669", "Catania")
1155    ///     ])
1156    /// }
1157    /// ```
1158    #[cfg(feature = "geospatial")]
1159    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1160    fn geo_add<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1161        cmd("GEOADD").arg(key).arg(members)
1162    }
1163
1164    /// Return the distance between two members in the geospatial index
1165    /// represented by the sorted set.
1166    ///
1167    /// If one or both the members are missing, the command returns NULL, so
1168    /// it may be convenient to parse its response as either `Option<f64>` or
1169    /// `Option<String>`.
1170    ///
1171    /// # Example
1172    ///
1173    /// ```rust,no_run
1174    /// use redis::{Commands, RedisResult};
1175    /// use redis::geo::Unit;
1176    ///
1177    /// fn get_dists(con: &mut redis::Connection) {
1178    ///     let x: RedisResult<f64> = con.geo_dist(
1179    ///         "my_gis",
1180    ///         "Palermo",
1181    ///         "Catania",
1182    ///         Unit::Kilometers
1183    ///     );
1184    ///     // x is Ok(166.2742)
1185    ///
1186    ///     let x: RedisResult<Option<f64>> = con.geo_dist(
1187    ///         "my_gis",
1188    ///         "Palermo",
1189    ///         "Atlantis",
1190    ///         Unit::Meters
1191    ///     );
1192    ///     // x is Ok(None)
1193    /// }
1194    /// ```
1195    #[cfg(feature = "geospatial")]
1196    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1197    fn geo_dist<K: ToRedisArgs, M1: ToRedisArgs, M2: ToRedisArgs>(
1198        key: K,
1199        member1: M1,
1200        member2: M2,
1201        unit: geo::Unit
1202    ) {
1203        cmd("GEODIST")
1204            .arg(key)
1205            .arg(member1)
1206            .arg(member2)
1207            .arg(unit)
1208    }
1209
1210    /// Return valid [Geohash][1] strings representing the position of one or
1211    /// more members of the geospatial index represented by the sorted set at
1212    /// key.
1213    ///
1214    /// [1]: https://en.wikipedia.org/wiki/Geohash
1215    ///
1216    /// # Example
1217    ///
1218    /// ```rust,no_run
1219    /// use redis::{Commands, RedisResult};
1220    ///
1221    /// fn get_hash(con: &mut redis::Connection) {
1222    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", "Palermo");
1223    ///     // x is vec!["sqc8b49rny0"]
1224    ///
1225    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", &["Palermo", "Catania"]);
1226    ///     // x is vec!["sqc8b49rny0", "sqdtr74hyu0"]
1227    /// }
1228    /// ```
1229    #[cfg(feature = "geospatial")]
1230    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1231    fn geo_hash<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1232        cmd("GEOHASH").arg(key).arg(members)
1233    }
1234
1235    /// Return the positions of all the specified members of the geospatial
1236    /// index represented by the sorted set at key.
1237    ///
1238    /// Every position is a pair of `(longitude, latitude)`. [`redis::geo::Coord`][1]
1239    /// can be used to convert these value in a struct.
1240    ///
1241    /// [1]: ./geo/struct.Coord.html
1242    ///
1243    /// # Example
1244    ///
1245    /// ```rust,no_run
1246    /// use redis::{Commands, RedisResult};
1247    /// use redis::geo::Coord;
1248    ///
1249    /// fn get_position(con: &mut redis::Connection) {
1250    ///     let x: RedisResult<Vec<Vec<f64>>> = con.geo_pos("my_gis", &["Palermo", "Catania"]);
1251    ///     // x is [ [ 13.361389, 38.115556 ], [ 15.087269, 37.502669 ] ];
1252    ///
1253    ///     let x: Vec<Coord<f64>> = con.geo_pos("my_gis", "Palermo").unwrap();
1254    ///     // x[0].longitude is 13.361389
1255    ///     // x[0].latitude is 38.115556
1256    /// }
1257    /// ```
1258    #[cfg(feature = "geospatial")]
1259    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1260    fn geo_pos<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1261        cmd("GEOPOS").arg(key).arg(members)
1262    }
1263
1264    /// Return the members of a sorted set populated with geospatial information
1265    /// using [`geo_add`](#method.geo_add), which are within the borders of the area
1266    /// specified with the center location and the maximum distance from the center
1267    /// (the radius).
1268    ///
1269    /// Every item in the result can be read with [`redis::geo::RadiusSearchResult`][1],
1270    /// which support the multiple formats returned by `GEORADIUS`.
1271    ///
1272    /// [1]: ./geo/struct.RadiusSearchResult.html
1273    ///
1274    /// ```rust,no_run
1275    /// use redis::{Commands, RedisResult};
1276    /// use redis::geo::{RadiusOptions, RadiusSearchResult, RadiusOrder, Unit};
1277    ///
1278    /// fn radius(con: &mut redis::Connection) -> Vec<RadiusSearchResult> {
1279    ///     let opts = RadiusOptions::default().with_dist().order(RadiusOrder::Asc);
1280    ///     con.geo_radius("my_gis", 15.90, 37.21, 51.39, Unit::Kilometers, opts).unwrap()
1281    /// }
1282    /// ```
1283    #[cfg(feature = "geospatial")]
1284    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1285    fn geo_radius<K: ToRedisArgs>(
1286        key: K,
1287        longitude: f64,
1288        latitude: f64,
1289        radius: f64,
1290        unit: geo::Unit,
1291        options: geo::RadiusOptions
1292    ) {
1293        cmd("GEORADIUS")
1294            .arg(key)
1295            .arg(longitude)
1296            .arg(latitude)
1297            .arg(radius)
1298            .arg(unit)
1299            .arg(options)
1300    }
1301
1302    /// Retrieve members selected by distance with the center of `member`. The
1303    /// member itself is always contained in the results.
1304    #[cfg(feature = "geospatial")]
1305    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1306    fn geo_radius_by_member<K: ToRedisArgs, M: ToRedisArgs>(
1307        key: K,
1308        member: M,
1309        radius: f64,
1310        unit: geo::Unit,
1311        options: geo::RadiusOptions
1312    ) {
1313        cmd("GEORADIUSBYMEMBER")
1314            .arg(key)
1315            .arg(member)
1316            .arg(radius)
1317            .arg(unit)
1318            .arg(options)
1319    }
1320
1321    //
1322    // streams commands
1323    //
1324
1325    /// Ack pending stream messages checked out by a consumer.
1326    ///
1327    /// ```text
1328    /// XACK <key> <group> <id> <id> ... <id>
1329    /// ```
1330    #[cfg(feature = "streams")]
1331    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1332    fn xack<K: ToRedisArgs, G: ToRedisArgs, I: ToRedisArgs>(
1333        key: K,
1334        group: G,
1335        ids: &'a [I]) {
1336        cmd("XACK")
1337            .arg(key)
1338            .arg(group)
1339            .arg(ids)
1340    }
1341
1342
1343    /// Add a stream message by `key`. Use `*` as the `id` for the current timestamp.
1344    ///
1345    /// ```text
1346    /// XADD key <ID or *> [field value] [field value] ...
1347    /// ```
1348    #[cfg(feature = "streams")]
1349    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1350    fn xadd<K: ToRedisArgs, ID: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(
1351        key: K,
1352        id: ID,
1353        items: &'a [(F, V)]
1354    ) {
1355        cmd("XADD").arg(key).arg(id).arg(items)
1356    }
1357
1358
1359    /// BTreeMap variant for adding a stream message by `key`.
1360    /// Use `*` as the `id` for the current timestamp.
1361    ///
1362    /// ```text
1363    /// XADD key <ID or *> [rust BTreeMap] ...
1364    /// ```
1365    #[cfg(feature = "streams")]
1366    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1367    fn xadd_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1368        key: K,
1369        id: ID,
1370        map: BTM
1371    ) {
1372        cmd("XADD").arg(key).arg(id).arg(map)
1373    }
1374
1375    /// Add a stream message while capping the stream at a maxlength.
1376    ///
1377    /// ```text
1378    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [field value] [field value] ...
1379    /// ```
1380    #[cfg(feature = "streams")]
1381    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1382    fn xadd_maxlen<
1383        K: ToRedisArgs,
1384        ID: ToRedisArgs,
1385        F: ToRedisArgs,
1386        V: ToRedisArgs
1387    >(
1388        key: K,
1389        maxlen: streams::StreamMaxlen,
1390        id: ID,
1391        items: &'a [(F, V)]
1392    ) {
1393        cmd("XADD")
1394            .arg(key)
1395            .arg(maxlen)
1396            .arg(id)
1397            .arg(items)
1398    }
1399
1400
1401    /// BTreeMap variant for adding a stream message while capping the stream at a maxlength.
1402    ///
1403    /// ```text
1404    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [rust BTreeMap] ...
1405    /// ```
1406    #[cfg(feature = "streams")]
1407    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1408    fn xadd_maxlen_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1409        key: K,
1410        maxlen: streams::StreamMaxlen,
1411        id: ID,
1412        map: BTM
1413    ) {
1414        cmd("XADD")
1415            .arg(key)
1416            .arg(maxlen)
1417            .arg(id)
1418            .arg(map)
1419    }
1420
1421
1422
1423    /// Claim pending, unacked messages, after some period of time,
1424    /// currently checked out by another consumer.
1425    ///
1426    /// This method only accepts the must-have arguments for claiming messages.
1427    /// If optional arguments are required, see `xclaim_options` below.
1428    ///
1429    /// ```text
1430    /// XCLAIM <key> <group> <consumer> <min-idle-time> [<ID-1> <ID-2>]
1431    /// ```
1432    #[cfg(feature = "streams")]
1433    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1434    fn xclaim<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs, MIT: ToRedisArgs, ID: ToRedisArgs>(
1435        key: K,
1436        group: G,
1437        consumer: C,
1438        min_idle_time: MIT,
1439        ids: &'a [ID]
1440    ) {
1441        cmd("XCLAIM")
1442            .arg(key)
1443            .arg(group)
1444            .arg(consumer)
1445            .arg(min_idle_time)
1446            .arg(ids)
1447    }
1448
1449    /// This is the optional arguments version for claiming unacked, pending messages
1450    /// currently checked out by another consumer.
1451    ///
1452    /// ```no_run
1453    /// use redis::{Connection,Commands,RedisResult};
1454    /// use redis::streams::{StreamClaimOptions,StreamClaimReply};
1455    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1456    /// let mut con = client.get_connection().unwrap();
1457    ///
1458    /// // Claim all pending messages for key "k1",
1459    /// // from group "g1", checked out by consumer "c1"
1460    /// // for 10ms with RETRYCOUNT 2 and FORCE
1461    ///
1462    /// let opts = StreamClaimOptions::default()
1463    ///     .with_force()
1464    ///     .retry(2);
1465    /// let results: RedisResult<StreamClaimReply> =
1466    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1467    ///
1468    /// // All optional arguments return a `Result<StreamClaimReply>` with one exception:
1469    /// // Passing JUSTID returns only the message `id` and omits the HashMap for each message.
1470    ///
1471    /// let opts = StreamClaimOptions::default()
1472    ///     .with_justid();
1473    /// let results: RedisResult<Vec<String>> =
1474    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1475    /// ```
1476    ///
1477    /// ```text
1478    /// XCLAIM <key> <group> <consumer> <min-idle-time> <ID-1> <ID-2>
1479    ///     [IDLE <milliseconds>] [TIME <mstime>] [RETRYCOUNT <count>]
1480    ///     [FORCE] [JUSTID]
1481    /// ```
1482    #[cfg(feature = "streams")]
1483    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1484    fn xclaim_options<
1485        K: ToRedisArgs,
1486        G: ToRedisArgs,
1487        C: ToRedisArgs,
1488        MIT: ToRedisArgs,
1489        ID: ToRedisArgs
1490    >(
1491        key: K,
1492        group: G,
1493        consumer: C,
1494        min_idle_time: MIT,
1495        ids: &'a [ID],
1496        options: streams::StreamClaimOptions
1497    ) {
1498        cmd("XCLAIM")
1499            .arg(key)
1500            .arg(group)
1501            .arg(consumer)
1502            .arg(min_idle_time)
1503            .arg(ids)
1504            .arg(options)
1505    }
1506
1507
1508    /// Deletes a list of `id`s for a given stream `key`.
1509    ///
1510    /// ```text
1511    /// XDEL <key> [<ID1> <ID2> ... <IDN>]
1512    /// ```
1513    #[cfg(feature = "streams")]
1514    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1515    fn xdel<K: ToRedisArgs, ID: ToRedisArgs>(
1516        key: K,
1517        ids: &'a [ID]
1518    ) {
1519        cmd("XDEL").arg(key).arg(ids)
1520    }
1521
1522
1523    /// This command is used for creating a consumer `group`. It expects the stream key
1524    /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
1525    /// The `id` is the starting message id all consumers should read from. Use `$` If you want
1526    /// all consumers to read from the last message added to stream.
1527    ///
1528    /// ```text
1529    /// XGROUP CREATE <key> <groupname> <id or $>
1530    /// ```
1531    #[cfg(feature = "streams")]
1532    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1533    fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1534        key: K,
1535        group: G,
1536        id: ID
1537    ) {
1538        cmd("XGROUP")
1539            .arg("CREATE")
1540            .arg(key)
1541            .arg(group)
1542            .arg(id)
1543    }
1544
1545
1546    /// This is the alternate version for creating a consumer `group`
1547    /// which makes the stream if it doesn't exist.
1548    ///
1549    /// ```text
1550    /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
1551    /// ```
1552    #[cfg(feature = "streams")]
1553    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1554    fn xgroup_create_mkstream<
1555        K: ToRedisArgs,
1556        G: ToRedisArgs,
1557        ID: ToRedisArgs
1558    >(
1559        key: K,
1560        group: G,
1561        id: ID
1562    ) {
1563        cmd("XGROUP")
1564            .arg("CREATE")
1565            .arg(key)
1566            .arg(group)
1567            .arg(id)
1568            .arg("MKSTREAM")
1569    }
1570
1571
1572    /// Alter which `id` you want consumers to begin reading from an existing
1573    /// consumer `group`.
1574    ///
1575    /// ```text
1576    /// XGROUP SETID <key> <groupname> <id or $>
1577    /// ```
1578    #[cfg(feature = "streams")]
1579    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1580    fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1581        key: K,
1582        group: G,
1583        id: ID
1584    ) {
1585        cmd("XGROUP")
1586            .arg("SETID")
1587            .arg(key)
1588            .arg(group)
1589            .arg(id)
1590    }
1591
1592
1593    /// Destroy an existing consumer `group` for a given stream `key`
1594    ///
1595    /// ```text
1596    /// XGROUP SETID <key> <groupname> <id or $>
1597    /// ```
1598    #[cfg(feature = "streams")]
1599    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1600    fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
1601        key: K,
1602        group: G
1603    ) {
1604        cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
1605    }
1606
1607    /// This deletes a `consumer` from an existing consumer `group`
1608    /// for given stream `key.
1609    ///
1610    /// ```text
1611    /// XGROUP DELCONSUMER <key> <groupname> <consumername>
1612    /// ```
1613    #[cfg(feature = "streams")]
1614    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1615    fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
1616        key: K,
1617        group: G,
1618        consumer: C
1619    ) {
1620        cmd("XGROUP")
1621            .arg("DELCONSUMER")
1622            .arg(key)
1623            .arg(group)
1624            .arg(consumer)
1625    }
1626
1627
1628    /// This returns all info details about
1629    /// which consumers have read messages for given consumer `group`.
1630    /// Take note of the StreamInfoConsumersReply return type.
1631    ///
1632    /// *It's possible this return value might not contain new fields
1633    /// added by Redis in future versions.*
1634    ///
1635    /// ```text
1636    /// XINFO CONSUMERS <key> <group>
1637    /// ```
1638    #[cfg(feature = "streams")]
1639    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1640    fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
1641        key: K,
1642        group: G
1643    ) {
1644        cmd("XINFO")
1645            .arg("CONSUMERS")
1646            .arg(key)
1647            .arg(group)
1648    }
1649
1650
1651    /// Returns all consumer `group`s created for a given stream `key`.
1652    /// Take note of the StreamInfoGroupsReply return type.
1653    ///
1654    /// *It's possible this return value might not contain new fields
1655    /// added by Redis in future versions.*
1656    ///
1657    /// ```text
1658    /// XINFO GROUPS <key>
1659    /// ```
1660    #[cfg(feature = "streams")]
1661    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1662    fn xinfo_groups<K: ToRedisArgs>(key: K) {
1663        cmd("XINFO").arg("GROUPS").arg(key)
1664    }
1665
1666
1667    /// Returns info about high-level stream details
1668    /// (first & last message `id`, length, number of groups, etc.)
1669    /// Take note of the StreamInfoStreamReply return type.
1670    ///
1671    /// *It's possible this return value might not contain new fields
1672    /// added by Redis in future versions.*
1673    ///
1674    /// ```text
1675    /// XINFO STREAM <key>
1676    /// ```
1677    #[cfg(feature = "streams")]
1678    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1679    fn xinfo_stream<K: ToRedisArgs>(key: K) {
1680        cmd("XINFO").arg("STREAM").arg(key)
1681    }
1682
1683    /// Returns the number of messages for a given stream `key`.
1684    ///
1685    /// ```text
1686    /// XLEN <key>
1687    /// ```
1688    #[cfg(feature = "streams")]
1689    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1690    fn xlen<K: ToRedisArgs>(key: K) {
1691        cmd("XLEN").arg(key)
1692    }
1693
1694
1695    /// This is a basic version of making XPENDING command calls which only
1696    /// passes a stream `key` and consumer `group` and it
1697    /// returns details about which consumers have pending messages
1698    /// that haven't been acked.
1699    ///
1700    /// You can use this method along with
1701    /// `xclaim` or `xclaim_options` for determining which messages
1702    /// need to be retried.
1703    ///
1704    /// Take note of the StreamPendingReply return type.
1705    ///
1706    /// ```text
1707    /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
1708    /// ```
1709    #[cfg(feature = "streams")]
1710    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1711    fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
1712        key: K,
1713        group: G
1714    )  {
1715        cmd("XPENDING").arg(key).arg(group)
1716    }
1717
1718
1719    /// This XPENDING version returns a list of all messages over the range.
1720    /// You can use this for paginating pending messages (but without the message HashMap).
1721    ///
1722    /// Start and end follow the same rules `xrange` args. Set start to `-`
1723    /// and end to `+` for the entire stream.
1724    ///
1725    /// Take note of the StreamPendingCountReply return type.
1726    ///
1727    /// ```text
1728    /// XPENDING <key> <group> <start> <stop> <count>
1729    /// ```
1730    #[cfg(feature = "streams")]
1731    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1732    fn xpending_count<
1733        K: ToRedisArgs,
1734        G: ToRedisArgs,
1735        S: ToRedisArgs,
1736        E: ToRedisArgs,
1737        C: ToRedisArgs
1738    >(
1739        key: K,
1740        group: G,
1741        start: S,
1742        end: E,
1743        count: C
1744    )  {
1745        cmd("XPENDING")
1746            .arg(key)
1747            .arg(group)
1748            .arg(start)
1749            .arg(end)
1750            .arg(count)
1751    }
1752
1753
1754    /// An alternate version of `xpending_count` which filters by `consumer` name.
1755    ///
1756    /// Start and end follow the same rules `xrange` args. Set start to `-`
1757    /// and end to `+` for the entire stream.
1758    ///
1759    /// Take note of the StreamPendingCountReply return type.
1760    ///
1761    /// ```text
1762    /// XPENDING <key> <group> <start> <stop> <count> <consumer>
1763    /// ```
1764    #[cfg(feature = "streams")]
1765    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1766    fn xpending_consumer_count<
1767        K: ToRedisArgs,
1768        G: ToRedisArgs,
1769        S: ToRedisArgs,
1770        E: ToRedisArgs,
1771        C: ToRedisArgs,
1772        CN: ToRedisArgs
1773    >(
1774        key: K,
1775        group: G,
1776        start: S,
1777        end: E,
1778        count: C,
1779        consumer: CN
1780    ) {
1781        cmd("XPENDING")
1782            .arg(key)
1783            .arg(group)
1784            .arg(start)
1785            .arg(end)
1786            .arg(count)
1787            .arg(consumer)
1788    }
1789
1790    /// Returns a range of messages in a given stream `key`.
1791    ///
1792    /// Set `start` to `-` to begin at the first message.
1793    /// Set `end` to `+` to end the most recent message.
1794    /// You can pass message `id` to both `start` and `end`.
1795    ///
1796    /// Take note of the StreamRangeReply return type.
1797    ///
1798    /// ```text
1799    /// XRANGE key start end
1800    /// ```
1801    #[cfg(feature = "streams")]
1802    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1803    fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
1804        key: K,
1805        start: S,
1806        end: E
1807    )  {
1808        cmd("XRANGE").arg(key).arg(start).arg(end)
1809    }
1810
1811
1812    /// A helper method for automatically returning all messages in a stream by `key`.
1813    /// **Use with caution!**
1814    ///
1815    /// ```text
1816    /// XRANGE key - +
1817    /// ```
1818    #[cfg(feature = "streams")]
1819    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1820    fn xrange_all<K: ToRedisArgs>(key: K)  {
1821        cmd("XRANGE").arg(key).arg("-").arg("+")
1822    }
1823
1824
1825    /// A method for paginating a stream by `key`.
1826    ///
1827    /// ```text
1828    /// XRANGE key start end [COUNT <n>]
1829    /// ```
1830    #[cfg(feature = "streams")]
1831    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1832    fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
1833        key: K,
1834        start: S,
1835        end: E,
1836        count: C
1837    )  {
1838        cmd("XRANGE")
1839            .arg(key)
1840            .arg(start)
1841            .arg(end)
1842            .arg("COUNT")
1843            .arg(count)
1844    }
1845
1846
1847    /// Read a list of `id`s for each stream `key`.
1848    /// This is the basic form of reading streams.
1849    /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
1850    /// see `xread_options`.
1851    ///
1852    /// ```text
1853    /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
1854    /// ```
1855    #[cfg(feature = "streams")]
1856    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1857    fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
1858        keys: &'a [K],
1859        ids: &'a [ID]
1860    ) {
1861        cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
1862    }
1863
1864    /// This method handles setting optional arguments for
1865    /// `XREAD` or `XREADGROUP` Redis commands.
1866    /// ```no_run
1867    /// use redis::{Connection,RedisResult,Commands};
1868    /// use redis::streams::{StreamReadOptions,StreamReadReply};
1869    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1870    /// let mut con = client.get_connection().unwrap();
1871    ///
1872    /// // Read 10 messages from the start of the stream,
1873    /// // without registering as a consumer group.
1874    ///
1875    /// let opts = StreamReadOptions::default()
1876    ///     .count(10);
1877    /// let results: RedisResult<StreamReadReply> =
1878    ///     con.xread_options(&["k1"], &["0"], &opts);
1879    ///
1880    /// // Read all undelivered messages for a given
1881    /// // consumer group. Be advised: the consumer group must already
1882    /// // exist before making this call. Also note: we're passing
1883    /// // '>' as the id here, which means all undelivered messages.
1884    ///
1885    /// let opts = StreamReadOptions::default()
1886    ///     .group("group-1", "consumer-1");
1887    /// let results: RedisResult<StreamReadReply> =
1888    ///     con.xread_options(&["k1"], &[">"], &opts);
1889    /// ```
1890    ///
1891    /// ```text
1892    /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
1893    ///     STREAMS key_1 key_2 ... key_N
1894    ///     ID_1 ID_2 ... ID_N
1895    ///
1896    /// XREADGROUP [BLOCK <milliseconds>] [COUNT <count>] [NOACK] [GROUP group-name consumer-name]
1897    ///     STREAMS key_1 key_2 ... key_N
1898    ///     ID_1 ID_2 ... ID_N
1899    /// ```
1900    #[cfg(feature = "streams")]
1901    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1902    fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
1903        keys: &'a [K],
1904        ids: &'a [ID],
1905        options: &'a streams::StreamReadOptions
1906    ) {
1907        cmd(if options.read_only() {
1908            "XREAD"
1909        } else {
1910            "XREADGROUP"
1911        })
1912        .arg(options)
1913        .arg("STREAMS")
1914        .arg(keys)
1915        .arg(ids)
1916    }
1917
1918    /// This is the reverse version of `xrange`.
1919    /// The same rules apply for `start` and `end` here.
1920    ///
1921    /// ```text
1922    /// XREVRANGE key end start
1923    /// ```
1924    #[cfg(feature = "streams")]
1925    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1926    fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
1927        key: K,
1928        end: E,
1929        start: S
1930    ) {
1931        cmd("XREVRANGE").arg(key).arg(end).arg(start)
1932    }
1933
1934    /// This is the reverse version of `xrange_all`.
1935    /// The same rules apply for `start` and `end` here.
1936    ///
1937    /// ```text
1938    /// XREVRANGE key + -
1939    /// ```
1940    fn xrevrange_all<K: ToRedisArgs>(key: K) {
1941        cmd("XREVRANGE").arg(key).arg("+").arg("-")
1942    }
1943
1944    /// This is the reverse version of `xrange_count`.
1945    /// The same rules apply for `start` and `end` here.
1946    ///
1947    /// ```text
1948    /// XREVRANGE key end start [COUNT <n>]
1949    /// ```
1950    #[cfg(feature = "streams")]
1951    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1952    fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
1953        key: K,
1954        end: E,
1955        start: S,
1956        count: C
1957    ) {
1958        cmd("XREVRANGE")
1959            .arg(key)
1960            .arg(end)
1961            .arg(start)
1962            .arg("COUNT")
1963            .arg(count)
1964    }
1965
1966
1967    /// Trim a stream `key` to a MAXLEN count.
1968    ///
1969    /// ```text
1970    /// XTRIM <key> MAXLEN [~|=] <count>  (Same as XADD MAXLEN option)
1971    /// ```
1972    #[cfg(feature = "streams")]
1973    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1974    fn xtrim<K: ToRedisArgs>(
1975        key: K,
1976        maxlen: streams::StreamMaxlen
1977    ) {
1978        cmd("XTRIM").arg(key).arg(maxlen)
1979    }
1980}
1981
1982/// Allows pubsub callbacks to stop receiving messages.
1983///
1984/// Arbitrary data may be returned from `Break`.
1985pub enum ControlFlow<U> {
1986    /// Continues.
1987    Continue,
1988    /// Breaks with a value.
1989    Break(U),
1990}
1991
1992/// The PubSub trait allows subscribing to one or more channels
1993/// and receiving a callback whenever a message arrives.
1994///
1995/// Each method handles subscribing to the list of keys, waiting for
1996/// messages, and unsubscribing from the same list of channels once
1997/// a ControlFlow::Break is encountered.
1998///
1999/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2000/// for calling other methods.
2001///
2002/// # Examples
2003///
2004/// ```rust,no_run
2005/// # fn do_something() -> redis::RedisResult<()> {
2006/// use redis::{PubSubCommands, ControlFlow};
2007/// let client = redis::Client::open("redis://127.0.0.1/")?;
2008/// let mut con = client.get_connection()?;
2009/// let mut count = 0;
2010/// con.subscribe(&["foo"], |msg| {
2011///     // do something with message
2012///     assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2013///
2014///     // increment messages seen counter
2015///     count += 1;
2016///     match count {
2017///         // stop after receiving 10 messages
2018///         10 => ControlFlow::Break(()),
2019///         _ => ControlFlow::Continue,
2020///     }
2021/// });
2022/// # Ok(()) }
2023/// ```
2024// TODO In the future, it would be nice to implement Try such that `?` will work
2025//      within the closure.
2026pub trait PubSubCommands: Sized {
2027    /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2028    /// closure for each message received.
2029    ///
2030    /// For every `Msg` passed to the provided closure, either
2031    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2032    /// method will not return until `ControlFlow::Break` is observed.
2033    fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2034    where
2035        F: FnMut(Msg) -> ControlFlow<U>,
2036        C: ToRedisArgs;
2037
2038    /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
2039    /// closure for each message received.
2040    ///
2041    /// For every `Msg` passed to the provided closure, either
2042    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2043    /// method will not return until `ControlFlow::Break` is observed.
2044    fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
2045    where
2046        F: FnMut(Msg) -> ControlFlow<U>,
2047        P: ToRedisArgs;
2048}
2049
2050impl<T> Commands for T where T: ConnectionLike {}
2051
2052#[cfg(feature = "aio")]
2053impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sized {}
2054
2055impl PubSubCommands for Connection {
2056    fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
2057    where
2058        F: FnMut(Msg) -> ControlFlow<U>,
2059        C: ToRedisArgs,
2060    {
2061        let mut pubsub = self.as_pubsub();
2062        pubsub.subscribe(channels)?;
2063
2064        loop {
2065            let msg = pubsub.get_message()?;
2066            match func(msg) {
2067                ControlFlow::Continue => continue,
2068                ControlFlow::Break(value) => return Ok(value),
2069            }
2070        }
2071    }
2072
2073    fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
2074    where
2075        F: FnMut(Msg) -> ControlFlow<U>,
2076        P: ToRedisArgs,
2077    {
2078        let mut pubsub = self.as_pubsub();
2079        pubsub.psubscribe(patterns)?;
2080
2081        loop {
2082            let msg = pubsub.get_message()?;
2083            match func(msg) {
2084                ControlFlow::Continue => continue,
2085                ControlFlow::Break(value) => return Ok(value),
2086            }
2087        }
2088    }
2089}
2090
2091/// Options for the [LPOS] command
2092///
2093/// https://redis.io/commands/lpos
2094///
2095/// # Example
2096///
2097/// ```rust,no_run
2098/// use redis::{Commands, RedisResult, LposOptions};
2099/// fn fetch_list_position(
2100///     con: &mut redis::Connection,
2101///     key: &str,
2102///     value: &str,
2103///     count: usize,
2104///     rank: isize,
2105///     maxlen: usize,
2106/// ) -> RedisResult<Vec<usize>> {
2107///     let opts = LposOptions::default()
2108///         .count(count)
2109///         .rank(rank)
2110///         .maxlen(maxlen);
2111///     con.lpos(key, value, opts)
2112/// }
2113/// ```
2114#[derive(Default)]
2115pub struct LposOptions {
2116    count: Option<usize>,
2117    maxlen: Option<usize>,
2118    rank: Option<isize>,
2119}
2120
2121impl LposOptions {
2122    /// Limit the results to the first N matching items.
2123    pub fn count(mut self, n: usize) -> Self {
2124        self.count = Some(n);
2125        self
2126    }
2127
2128    /// Return the value of N from the matching items.
2129    pub fn rank(mut self, n: isize) -> Self {
2130        self.rank = Some(n);
2131        self
2132    }
2133
2134    /// Limit the search to N items in the list.
2135    pub fn maxlen(mut self, n: usize) -> Self {
2136        self.maxlen = Some(n);
2137        self
2138    }
2139}
2140
2141impl ToRedisArgs for LposOptions {
2142    fn write_redis_args<W>(&self, out: &mut W)
2143    where
2144        W: ?Sized + RedisWrite,
2145    {
2146        if let Some(n) = self.count {
2147            out.write_arg(b"COUNT");
2148            out.write_arg_fmt(n);
2149        }
2150
2151        if let Some(n) = self.rank {
2152            out.write_arg(b"RANK");
2153            out.write_arg_fmt(n);
2154        }
2155
2156        if let Some(n) = self.maxlen {
2157            out.write_arg(b"MAXLEN");
2158            out.write_arg_fmt(n);
2159        }
2160    }
2161
2162    fn is_single_arg(&self) -> bool {
2163        false
2164    }
2165}
2166
2167/// Enum for the LEFT | RIGHT args used by some commands
2168pub enum Direction {
2169    Left,
2170    Right,
2171}
2172
2173impl ToRedisArgs for Direction {
2174    fn write_redis_args<W>(&self, out: &mut W)
2175    where
2176        W: ?Sized + RedisWrite,
2177    {
2178        let s: &[u8] = match self {
2179            Direction::Left => b"LEFT",
2180            Direction::Right => b"RIGHT",
2181        };
2182        out.write_arg(s);
2183    }
2184}