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