redis/commands/
mod.rs

1use crate::cmd::{cmd, Cmd, Iter};
2use crate::connection::{Connection, ConnectionLike, Msg};
3use crate::pipeline::Pipeline;
4use crate::types::{
5    ExistenceCheck, ExpireOption, Expiry, FromRedisValue, NumericBehavior, RedisResult, RedisWrite,
6    SetExpiry, ToRedisArgs,
7};
8
9#[macro_use]
10mod macros;
11
12#[cfg(feature = "json")]
13#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
14mod json;
15
16#[cfg(feature = "json")]
17pub use json::JsonCommands;
18
19#[cfg(all(feature = "json", feature = "aio"))]
20pub use json::JsonAsyncCommands;
21
22#[cfg(feature = "cluster")]
23use crate::cluster_pipeline::ClusterPipeline;
24
25#[cfg(feature = "geospatial")]
26use crate::geo;
27
28#[cfg(feature = "streams")]
29use crate::streams;
30
31#[cfg(feature = "acl")]
32use crate::acl;
33use crate::RedisConnectionInfo;
34
35#[cfg(any(feature = "cluster", feature = "cache-aio"))]
36pub(crate) fn is_readonly_cmd(cmd: &[u8]) -> bool {
37    matches!(
38        cmd,
39        b"BITCOUNT"
40            | b"BITFIELD_RO"
41            | b"BITPOS"
42            | b"DBSIZE"
43            | b"DUMP"
44            | b"EVALSHA_RO"
45            | b"EVAL_RO"
46            | b"EXISTS"
47            | b"EXPIRETIME"
48            | b"FCALL_RO"
49            | b"GEODIST"
50            | b"GEOHASH"
51            | b"GEOPOS"
52            | b"GEORADIUSBYMEMBER_RO"
53            | b"GEORADIUS_RO"
54            | b"GEOSEARCH"
55            | b"GET"
56            | b"GETBIT"
57            | b"GETRANGE"
58            | b"HEXISTS"
59            | b"HEXPIRETIME"
60            | b"HGET"
61            | b"HGETALL"
62            | b"HKEYS"
63            | b"HLEN"
64            | b"HMGET"
65            | b"HRANDFIELD"
66            | b"HPTTL"
67            | b"HPEXPIRETIME"
68            | b"HSCAN"
69            | b"HSTRLEN"
70            | b"HTTL"
71            | b"HVALS"
72            | b"KEYS"
73            | b"LCS"
74            | b"LINDEX"
75            | b"LLEN"
76            | b"LOLWUT"
77            | b"LPOS"
78            | b"LRANGE"
79            | b"MEMORY USAGE"
80            | b"MGET"
81            | b"OBJECT ENCODING"
82            | b"OBJECT FREQ"
83            | b"OBJECT IDLETIME"
84            | b"OBJECT REFCOUNT"
85            | b"PEXPIRETIME"
86            | b"PFCOUNT"
87            | b"PTTL"
88            | b"RANDOMKEY"
89            | b"SCAN"
90            | b"SCARD"
91            | b"SDIFF"
92            | b"SINTER"
93            | b"SINTERCARD"
94            | b"SISMEMBER"
95            | b"SMEMBERS"
96            | b"SMISMEMBER"
97            | b"SORT_RO"
98            | b"SRANDMEMBER"
99            | b"SSCAN"
100            | b"STRLEN"
101            | b"SUBSTR"
102            | b"SUNION"
103            | b"TOUCH"
104            | b"TTL"
105            | b"TYPE"
106            | b"XINFO CONSUMERS"
107            | b"XINFO GROUPS"
108            | b"XINFO STREAM"
109            | b"XLEN"
110            | b"XPENDING"
111            | b"XRANGE"
112            | b"XREAD"
113            | b"XREVRANGE"
114            | b"ZCARD"
115            | b"ZCOUNT"
116            | b"ZDIFF"
117            | b"ZINTER"
118            | b"ZINTERCARD"
119            | b"ZLEXCOUNT"
120            | b"ZMSCORE"
121            | b"ZRANDMEMBER"
122            | b"ZRANGE"
123            | b"ZRANGEBYLEX"
124            | b"ZRANGEBYSCORE"
125            | b"ZRANK"
126            | b"ZREVRANGE"
127            | b"ZREVRANGEBYLEX"
128            | b"ZREVRANGEBYSCORE"
129            | b"ZREVRANK"
130            | b"ZSCAN"
131            | b"ZSCORE"
132            | b"ZUNION"
133            | b"JSON.GET"
134            | b"JSON.MGET"
135    )
136}
137
138implement_commands! {
139    'a
140    // most common operations
141
142    /// Get the value of a key.  If key is a vec this becomes an `MGET`.
143    fn get<K: ToRedisArgs>(key: K) {
144        cmd(if key.num_of_args() <= 1 { "GET" } else { "MGET" }).arg(key)
145    }
146
147    /// Get values of keys
148    fn mget<K: ToRedisArgs>(key: K){
149        cmd("MGET").arg(key)
150    }
151
152    /// Gets all keys matching pattern
153    fn keys<K: ToRedisArgs>(key: K) {
154        cmd("KEYS").arg(key)
155    }
156
157    /// Set the string value of a key.
158    fn set<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
159        cmd("SET").arg(key).arg(value)
160    }
161
162    /// Set the string value of a key with options.
163    fn set_options<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: SetOptions) {
164        cmd("SET").arg(key).arg(value).arg(options)
165    }
166
167    /// Sets multiple keys to their values.
168    #[allow(deprecated)]
169    #[deprecated(since = "0.22.4", note = "Renamed to mset() to reflect Redis name")]
170    fn set_multiple<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
171        cmd("MSET").arg(items)
172    }
173
174    /// Sets multiple keys to their values.
175    fn mset<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
176        cmd("MSET").arg(items)
177    }
178
179    /// Set the value and expiration of a key.
180    fn set_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, seconds: u64) {
181        cmd("SETEX").arg(key).arg(seconds).arg(value)
182    }
183
184    /// Set the value and expiration in milliseconds of a key.
185    fn pset_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, milliseconds: u64) {
186        cmd("PSETEX").arg(key).arg(milliseconds).arg(value)
187    }
188
189    /// Set the value of a key, only if the key does not exist
190    fn set_nx<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
191        cmd("SETNX").arg(key).arg(value)
192    }
193
194    /// Sets multiple keys to their values failing if at least one already exists.
195    fn mset_nx<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
196        cmd("MSETNX").arg(items)
197    }
198
199    /// Set the string value of a key and return its old value.
200    fn getset<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
201        cmd("GETSET").arg(key).arg(value)
202    }
203
204    /// Get a range of bytes/substring from the value of a key. Negative values provide an offset from the end of the value.
205    fn getrange<K: ToRedisArgs>(key: K, from: isize, to: isize) {
206        cmd("GETRANGE").arg(key).arg(from).arg(to)
207    }
208
209    /// Overwrite the part of the value stored in key at the specified offset.
210    fn setrange<K: ToRedisArgs, V: ToRedisArgs>(key: K, offset: isize, value: V) {
211        cmd("SETRANGE").arg(key).arg(offset).arg(value)
212    }
213
214    /// Delete one or more keys.
215    fn del<K: ToRedisArgs>(key: K) {
216        cmd("DEL").arg(key)
217    }
218
219    /// Determine if a key exists.
220    fn exists<K: ToRedisArgs>(key: K) {
221        cmd("EXISTS").arg(key)
222    }
223
224    /// Determine the type of a key.
225    fn key_type<K: ToRedisArgs>(key: K) {
226        cmd("TYPE").arg(key)
227    }
228
229    /// Set a key's time to live in seconds.
230    fn expire<K: ToRedisArgs>(key: K, seconds: i64) {
231        cmd("EXPIRE").arg(key).arg(seconds)
232    }
233
234    /// Set the expiration for a key as a UNIX timestamp.
235    fn expire_at<K: ToRedisArgs>(key: K, ts: i64) {
236        cmd("EXPIREAT").arg(key).arg(ts)
237    }
238
239    /// Set a key's time to live in milliseconds.
240    fn pexpire<K: ToRedisArgs>(key: K, ms: i64) {
241        cmd("PEXPIRE").arg(key).arg(ms)
242    }
243
244    /// Set the expiration for a key as a UNIX timestamp in milliseconds.
245    fn pexpire_at<K: ToRedisArgs>(key: K, ts: i64) {
246        cmd("PEXPIREAT").arg(key).arg(ts)
247    }
248
249    /// Get the absolute Unix expiration timestamp in seconds.
250    fn expire_time<K: ToRedisArgs>(key: K) {
251        cmd("EXPIRETIME").arg(key)
252    }
253
254    /// Get the absolute Unix expiration timestamp in milliseconds.
255    fn pexpire_time<K: ToRedisArgs>(key: K) {
256        cmd("PEXPIRETIME").arg(key)
257    }
258
259    /// Remove the expiration from a key.
260    fn persist<K: ToRedisArgs>(key: K) {
261        cmd("PERSIST").arg(key)
262    }
263
264    /// Get the time to live for a key in seconds.
265    fn ttl<K: ToRedisArgs>(key: K) {
266        cmd("TTL").arg(key)
267    }
268
269    /// Get the time to live for a key in milliseconds.
270    fn pttl<K: ToRedisArgs>(key: K) {
271        cmd("PTTL").arg(key)
272    }
273
274    /// Get the value of a key and set expiration
275    fn get_ex<K: ToRedisArgs>(key: K, expire_at: Expiry) {
276        let (option, time_arg) = match expire_at {
277            Expiry::EX(sec) => ("EX", Some(sec)),
278            Expiry::PX(ms) => ("PX", Some(ms)),
279            Expiry::EXAT(timestamp_sec) => ("EXAT", Some(timestamp_sec)),
280            Expiry::PXAT(timestamp_ms) => ("PXAT", Some(timestamp_ms)),
281            Expiry::PERSIST => ("PERSIST", None),
282        };
283
284        cmd("GETEX").arg(key).arg(option).arg(time_arg)
285    }
286
287    /// Get the value of a key and delete it
288    fn get_del<K: ToRedisArgs>(key: K) {
289        cmd("GETDEL").arg(key)
290    }
291
292    /// Rename a key.
293    fn rename<K: ToRedisArgs, N: ToRedisArgs>(key: K, new_key: N) {
294        cmd("RENAME").arg(key).arg(new_key)
295    }
296
297    /// Rename a key, only if the new key does not exist.
298    fn rename_nx<K: ToRedisArgs, N: ToRedisArgs>(key: K, new_key: N) {
299        cmd("RENAMENX").arg(key).arg(new_key)
300    }
301
302    /// Unlink one or more keys.
303    fn unlink<K: ToRedisArgs>(key: K) {
304        cmd("UNLINK").arg(key)
305    }
306
307    // common string operations
308
309    /// Append a value to a key.
310    fn append<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
311        cmd("APPEND").arg(key).arg(value)
312    }
313
314    /// Increment the numeric value of a key by the given amount.  This
315    /// issues a `INCRBY` or `INCRBYFLOAT` depending on the type.
316    fn incr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
317        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
318            "INCRBYFLOAT"
319        } else {
320            "INCRBY"
321        }).arg(key).arg(delta)
322    }
323
324    /// Decrement the numeric value of a key by the given amount.
325    fn decr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
326        cmd("DECRBY").arg(key).arg(delta)
327    }
328
329    /// Sets or clears the bit at offset in the string value stored at key.
330    fn setbit<K: ToRedisArgs>(key: K, offset: usize, value: bool) {
331        cmd("SETBIT").arg(key).arg(offset).arg(i32::from(value))
332    }
333
334    /// Returns the bit value at offset in the string value stored at key.
335    fn getbit<K: ToRedisArgs>(key: K, offset: usize) {
336        cmd("GETBIT").arg(key).arg(offset)
337    }
338
339    /// Count set bits in a string.
340    fn bitcount<K: ToRedisArgs>(key: K) {
341        cmd("BITCOUNT").arg(key)
342    }
343
344    /// Count set bits in a string in a range.
345    fn bitcount_range<K: ToRedisArgs>(key: K, start: usize, end: usize) {
346        cmd("BITCOUNT").arg(key).arg(start).arg(end)
347    }
348
349    /// Perform a bitwise AND between multiple keys (containing string values)
350    /// and store the result in the destination key.
351    fn bit_and<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S) {
352        cmd("BITOP").arg("AND").arg(dstkey).arg(srckeys)
353    }
354
355    /// Perform a bitwise OR between multiple keys (containing string values)
356    /// and store the result in the destination key.
357    fn bit_or<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S) {
358        cmd("BITOP").arg("OR").arg(dstkey).arg(srckeys)
359    }
360
361    /// Perform a bitwise XOR between multiple keys (containing string values)
362    /// and store the result in the destination key.
363    fn bit_xor<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S) {
364        cmd("BITOP").arg("XOR").arg(dstkey).arg(srckeys)
365    }
366
367    /// Perform a bitwise NOT of the key (containing string values)
368    /// and store the result in the destination key.
369    fn bit_not<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckey: S) {
370        cmd("BITOP").arg("NOT").arg(dstkey).arg(srckey)
371    }
372
373    /// Get the length of the value stored in a key.
374    fn strlen<K: ToRedisArgs>(key: K) {
375        cmd("STRLEN").arg(key)
376    }
377
378    // hash operations
379
380    /// Gets a single (or multiple) fields from a hash.
381    fn hget<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
382        cmd(if field.num_of_args() <= 1 { "HGET" } else { "HMGET" }).arg(key).arg(field)
383    }
384
385    /// Deletes a single (or multiple) fields from a hash.
386    fn hdel<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
387        cmd("HDEL").arg(key).arg(field)
388    }
389
390    /// Sets a single field in a hash.
391    fn hset<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
392        cmd("HSET").arg(key).arg(field).arg(value)
393    }
394
395    /// Sets a single field in a hash if it does not exist.
396    fn hset_nx<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
397        cmd("HSETNX").arg(key).arg(field).arg(value)
398    }
399
400    /// Sets multiple fields in a hash.
401    fn hset_multiple<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, items: &'a [(F, V)]) {
402        cmd("HMSET").arg(key).arg(items)
403    }
404
405    /// Increments a value.
406    fn hincr<K: ToRedisArgs, F: ToRedisArgs, D: ToRedisArgs>(key: K, field: F, delta: D) {
407        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
408            "HINCRBYFLOAT"
409        } else {
410            "HINCRBY"
411        }).arg(key).arg(field).arg(delta)
412    }
413
414    /// Checks if a field in a hash exists.
415    fn hexists<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
416        cmd("HEXISTS").arg(key).arg(field)
417    }
418
419    /// Get one or more fields' TTL in seconds.
420    fn httl<K: ToRedisArgs, F: ToRedisArgs>(key: K, fields: F) {
421        cmd("HTTL").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
422    }
423
424    /// Get one or more fields' TTL in milliseconds.
425    fn hpttl<K: ToRedisArgs, F: ToRedisArgs>(key: K, fields: F) {
426        cmd("HPTTL").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
427    }
428
429    /// Set one or more fields' time to live in seconds.
430    fn hexpire<K: ToRedisArgs, F: ToRedisArgs>(key: K, seconds: i64, opt: ExpireOption, fields: F) {
431       cmd("HEXPIRE").arg(key).arg(seconds).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
432    }
433
434    /// Set the expiration for one or more fields as a UNIX timestamp in milliseconds.
435    fn hexpire_at<K: ToRedisArgs, F: ToRedisArgs>(key: K, ts: i64, opt: ExpireOption, fields: F) {
436        cmd("HEXPIREAT").arg(key).arg(ts).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
437    }
438
439    /// Returns the absolute Unix expiration timestamp in seconds.
440    fn hexpire_time<K: ToRedisArgs, F: ToRedisArgs>(key: K, fields: F) {
441        cmd("HEXPIRETIME").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
442    }
443
444    /// Remove the expiration from a key.
445    fn hpersist<K: ToRedisArgs, F :ToRedisArgs>(key: K, fields: F) {
446        cmd("HPERSIST").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
447    }
448
449    /// Set one or more fields' time to live in milliseconds.
450    fn hpexpire<K: ToRedisArgs, F: ToRedisArgs>(key: K, milliseconds: i64, opt: ExpireOption, fields: F) {
451        cmd("HPEXPIRE").arg(key).arg(milliseconds).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
452    }
453
454    /// Set the expiration for one or more fields as a UNIX timestamp in milliseconds.
455    fn hpexpire_at<K: ToRedisArgs, F: ToRedisArgs>(key: K, ts: i64,  opt: ExpireOption, fields: F) {
456        cmd("HPEXPIREAT").arg(key).arg(ts).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
457    }
458
459    /// Returns the absolute Unix expiration timestamp in seconds.
460    fn hpexpire_time<K: ToRedisArgs, F: ToRedisArgs>(key: K, fields: F) {
461        cmd("HPEXPIRETIME").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
462    }
463
464    /// Gets all the keys in a hash.
465    fn hkeys<K: ToRedisArgs>(key: K) {
466        cmd("HKEYS").arg(key)
467    }
468
469    /// Gets all the values in a hash.
470    fn hvals<K: ToRedisArgs>(key: K) {
471        cmd("HVALS").arg(key)
472    }
473
474    /// Gets all the fields and values in a hash.
475    fn hgetall<K: ToRedisArgs>(key: K) {
476        cmd("HGETALL").arg(key)
477    }
478
479    /// Gets the length of a hash.
480    fn hlen<K: ToRedisArgs>(key: K) {
481        cmd("HLEN").arg(key)
482    }
483
484    // list operations
485
486    /// Pop an element from a list, push it to another list
487    /// and return it; or block until one is available
488    fn blmove<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction, timeout: f64) {
489        cmd("BLMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir).arg(timeout)
490    }
491
492    /// Pops `count` elements from the first non-empty list key from the list of
493    /// provided key names; or blocks until one is available.
494    fn blmpop<K: ToRedisArgs>(timeout: f64, numkeys: usize, key: K, dir: Direction, count: usize){
495        cmd("BLMPOP").arg(timeout).arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
496    }
497
498    /// Remove and get the first element in a list, or block until one is available.
499    fn blpop<K: ToRedisArgs>(key: K, timeout: f64) {
500        cmd("BLPOP").arg(key).arg(timeout)
501    }
502
503    /// Remove and get the last element in a list, or block until one is available.
504    fn brpop<K: ToRedisArgs>(key: K, timeout: f64) {
505        cmd("BRPOP").arg(key).arg(timeout)
506    }
507
508    /// Pop a value from a list, push it to another list and return it;
509    /// or block until one is available.
510    fn brpoplpush<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, timeout: f64) {
511        cmd("BRPOPLPUSH").arg(srckey).arg(dstkey).arg(timeout)
512    }
513
514    /// Get an element from a list by its index.
515    fn lindex<K: ToRedisArgs>(key: K, index: isize) {
516        cmd("LINDEX").arg(key).arg(index)
517    }
518
519    /// Insert an element before another element in a list.
520    fn linsert_before<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
521            key: K, pivot: P, value: V) {
522        cmd("LINSERT").arg(key).arg("BEFORE").arg(pivot).arg(value)
523    }
524
525    /// Insert an element after another element in a list.
526    fn linsert_after<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
527            key: K, pivot: P, value: V) {
528        cmd("LINSERT").arg(key).arg("AFTER").arg(pivot).arg(value)
529    }
530
531    /// Returns the length of the list stored at key.
532    fn llen<K: ToRedisArgs>(key: K) {
533        cmd("LLEN").arg(key)
534    }
535
536    /// Pop an element a list, push it to another list and return it
537    fn lmove<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction) {
538        cmd("LMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir)
539    }
540
541    /// Pops `count` elements from the first non-empty list key from the list of
542    /// provided key names.
543    fn lmpop<K: ToRedisArgs>( numkeys: usize, key: K, dir: Direction, count: usize) {
544        cmd("LMPOP").arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
545    }
546
547    /// Removes and returns the up to `count` first elements of the list stored at key.
548    ///
549    /// If `count` is not specified, then defaults to first element.
550    fn lpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
551        cmd("LPOP").arg(key).arg(count)
552    }
553
554    /// Returns the index of the first matching value of the list stored at key.
555    fn lpos<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: LposOptions) {
556        cmd("LPOS").arg(key).arg(value).arg(options)
557    }
558
559    /// Insert all the specified values at the head of the list stored at key.
560    fn lpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
561        cmd("LPUSH").arg(key).arg(value)
562    }
563
564    /// Inserts a value at the head of the list stored at key, only if key
565    /// already exists and holds a list.
566    fn lpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
567        cmd("LPUSHX").arg(key).arg(value)
568    }
569
570    /// Returns the specified elements of the list stored at key.
571    fn lrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
572        cmd("LRANGE").arg(key).arg(start).arg(stop)
573    }
574
575    /// Removes the first count occurrences of elements equal to value
576    /// from the list stored at key.
577    fn lrem<K: ToRedisArgs, V: ToRedisArgs>(key: K, count: isize, value: V) {
578        cmd("LREM").arg(key).arg(count).arg(value)
579    }
580
581    /// Trim an existing list so that it will contain only the specified
582    /// range of elements specified.
583    fn ltrim<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
584        cmd("LTRIM").arg(key).arg(start).arg(stop)
585    }
586
587    /// Sets the list element at index to value
588    fn lset<K: ToRedisArgs, V: ToRedisArgs>(key: K, index: isize, value: V) {
589        cmd("LSET").arg(key).arg(index).arg(value)
590    }
591
592    /// Sends a ping to the server
593    fn ping<>() {
594         &mut cmd("PING")
595    }
596
597    /// Sends a ping with a message to the server
598    fn ping_message<K: ToRedisArgs>(message: K) {
599         cmd("PING").arg(message)
600    }
601
602    /// Removes and returns the up to `count` last elements of the list stored at key
603    ///
604    /// If `count` is not specified, then defaults to last element.
605    fn rpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
606        cmd("RPOP").arg(key).arg(count)
607    }
608
609    /// Pop a value from a list, push it to another list and return it.
610    fn rpoplpush<K: ToRedisArgs, D: ToRedisArgs>(key: K, dstkey: D) {
611        cmd("RPOPLPUSH").arg(key).arg(dstkey)
612    }
613
614    /// Insert all the specified values at the tail of the list stored at key.
615    fn rpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
616        cmd("RPUSH").arg(key).arg(value)
617    }
618
619    /// Inserts value at the tail of the list stored at key, only if key
620    /// already exists and holds a list.
621    fn rpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
622        cmd("RPUSHX").arg(key).arg(value)
623    }
624
625    // set commands
626
627    /// Add one or more members to a set.
628    fn sadd<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
629        cmd("SADD").arg(key).arg(member)
630    }
631
632    /// Get the number of members in a set.
633    fn scard<K: ToRedisArgs>(key: K) {
634        cmd("SCARD").arg(key)
635    }
636
637    /// Subtract multiple sets.
638    fn sdiff<K: ToRedisArgs>(keys: K) {
639        cmd("SDIFF").arg(keys)
640    }
641
642    /// Subtract multiple sets and store the resulting set in a key.
643    fn sdiffstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
644        cmd("SDIFFSTORE").arg(dstkey).arg(keys)
645    }
646
647    /// Intersect multiple sets.
648    fn sinter<K: ToRedisArgs>(keys: K) {
649        cmd("SINTER").arg(keys)
650    }
651
652    /// Intersect multiple sets and store the resulting set in a key.
653    fn sinterstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
654        cmd("SINTERSTORE").arg(dstkey).arg(keys)
655    }
656
657    /// Determine if a given value is a member of a set.
658    fn sismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
659        cmd("SISMEMBER").arg(key).arg(member)
660    }
661
662    /// Determine if given values are members of a set.
663    fn smismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
664        cmd("SMISMEMBER").arg(key).arg(members)
665    }
666
667    /// Get all the members in a set.
668    fn smembers<K: ToRedisArgs>(key: K) {
669        cmd("SMEMBERS").arg(key)
670    }
671
672    /// Move a member from one set to another.
673    fn smove<S: ToRedisArgs, D: ToRedisArgs, M: ToRedisArgs>(srckey: S, dstkey: D, member: M) {
674        cmd("SMOVE").arg(srckey).arg(dstkey).arg(member)
675    }
676
677    /// Remove and return a random member from a set.
678    fn spop<K: ToRedisArgs>(key: K) {
679        cmd("SPOP").arg(key)
680    }
681
682    /// Get one random member from a set.
683    fn srandmember<K: ToRedisArgs>(key: K) {
684        cmd("SRANDMEMBER").arg(key)
685    }
686
687    /// Get multiple random members from a set.
688    fn srandmember_multiple<K: ToRedisArgs>(key: K, count: usize) {
689        cmd("SRANDMEMBER").arg(key).arg(count)
690    }
691
692    /// Remove one or more members from a set.
693    fn srem<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
694        cmd("SREM").arg(key).arg(member)
695    }
696
697    /// Add multiple sets.
698    fn sunion<K: ToRedisArgs>(keys: K) {
699        cmd("SUNION").arg(keys)
700    }
701
702    /// Add multiple sets and store the resulting set in a key.
703    fn sunionstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
704        cmd("SUNIONSTORE").arg(dstkey).arg(keys)
705    }
706
707    // sorted set commands
708
709    /// Add one member to a sorted set, or update its score if it already exists.
710    fn zadd<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, member: M, score: S) {
711        cmd("ZADD").arg(key).arg(score).arg(member)
712    }
713
714    /// Add multiple members to a sorted set, or update its score if it already exists.
715    fn zadd_multiple<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)]) {
716        cmd("ZADD").arg(key).arg(items)
717    }
718
719    /// Get the number of members in a sorted set.
720    fn zcard<K: ToRedisArgs>(key: K) {
721        cmd("ZCARD").arg(key)
722    }
723
724    /// Count the members in a sorted set with scores within the given values.
725    fn zcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
726        cmd("ZCOUNT").arg(key).arg(min).arg(max)
727    }
728
729    /// Increments the member in a sorted set at key by delta.
730    /// If the member does not exist, it is added with delta as its score.
731    fn zincr<K: ToRedisArgs, M: ToRedisArgs, D: ToRedisArgs>(key: K, member: M, delta: D) {
732        cmd("ZINCRBY").arg(key).arg(delta).arg(member)
733    }
734
735    /// Intersect multiple sorted sets and store the resulting sorted set in
736    /// a new key using SUM as aggregation function.
737    fn zinterstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
738        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys)
739    }
740
741    /// Intersect multiple sorted sets and store the resulting sorted set in
742    /// a new key using MIN as aggregation function.
743    fn zinterstore_min<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
744        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN")
745    }
746
747    /// Intersect multiple sorted sets and store the resulting sorted set in
748    /// a new key using MAX as aggregation function.
749    fn zinterstore_max<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
750        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX")
751    }
752
753    /// [`Commands::zinterstore`], but with the ability to specify a
754    /// multiplication factor for each sorted set by pairing one with each key
755    /// in a tuple.
756    fn zinterstore_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
757        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
758        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("WEIGHTS").arg(weights)
759    }
760
761    /// [`Commands::zinterstore_min`], but with the ability to specify a
762    /// multiplication factor for each sorted set by pairing one with each key
763    /// in a tuple.
764    fn zinterstore_min_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
765        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
766        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN").arg("WEIGHTS").arg(weights)
767    }
768
769    /// [`Commands::zinterstore_max`], but with the ability to specify a
770    /// multiplication factor for each sorted set by pairing one with each key
771    /// in a tuple.
772    fn zinterstore_max_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
773        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
774        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX").arg("WEIGHTS").arg(weights)
775    }
776
777    /// Count the number of members in a sorted set between a given lexicographical range.
778    fn zlexcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
779        cmd("ZLEXCOUNT").arg(key).arg(min).arg(max)
780    }
781
782    /// Removes and returns the member with the highest score in a sorted set.
783    /// Blocks until a member is available otherwise.
784    fn bzpopmax<K: ToRedisArgs>(key: K, timeout: f64) {
785        cmd("BZPOPMAX").arg(key).arg(timeout)
786    }
787
788    /// Removes and returns up to count members with the highest scores in a sorted set
789    fn zpopmax<K: ToRedisArgs>(key: K, count: isize) {
790        cmd("ZPOPMAX").arg(key).arg(count)
791    }
792
793    /// Removes and returns the member with the lowest score in a sorted set.
794    /// Blocks until a member is available otherwise.
795    fn bzpopmin<K: ToRedisArgs>(key: K, timeout: f64) {
796        cmd("BZPOPMIN").arg(key).arg(timeout)
797    }
798
799    /// Removes and returns up to count members with the lowest scores in a sorted set
800    fn zpopmin<K: ToRedisArgs>(key: K, count: isize) {
801        cmd("ZPOPMIN").arg(key).arg(count)
802    }
803
804    /// Removes and returns up to count members with the highest scores,
805    /// from the first non-empty sorted set in the provided list of key names.
806    /// Blocks until a member is available otherwise.
807    fn bzmpop_max<K: ToRedisArgs>(timeout: f64, keys: K, count: isize) {
808        cmd("BZMPOP").arg(timeout).arg(keys.num_of_args()).arg(keys).arg("MAX").arg("COUNT").arg(count)
809    }
810
811    /// Removes and returns up to count members with the highest scores,
812    /// from the first non-empty sorted set in the provided list of key names.
813    fn zmpop_max<K: ToRedisArgs>(keys: K, count: isize) {
814        cmd("ZMPOP").arg(keys.num_of_args()).arg(keys).arg("MAX").arg("COUNT").arg(count)
815    }
816
817    /// Removes and returns up to count members with the lowest scores,
818    /// from the first non-empty sorted set in the provided list of key names.
819    /// Blocks until a member is available otherwise.
820    fn bzmpop_min<K: ToRedisArgs>(timeout: f64, keys: K, count: isize) {
821        cmd("BZMPOP").arg(timeout).arg(keys.num_of_args()).arg(keys).arg("MIN").arg("COUNT").arg(count)
822    }
823
824    /// Removes and returns up to count members with the lowest scores,
825    /// from the first non-empty sorted set in the provided list of key names.
826    fn zmpop_min<K: ToRedisArgs>(keys: K, count: isize) {
827        cmd("ZMPOP").arg(keys.num_of_args()).arg(keys).arg("MIN").arg("COUNT").arg(count)
828    }
829
830    /// Return up to count random members in a sorted set (or 1 if `count == None`)
831    fn zrandmember<K: ToRedisArgs>(key: K, count: Option<isize>) {
832        cmd("ZRANDMEMBER").arg(key).arg(count)
833    }
834
835    /// Return up to count random members in a sorted set with scores
836    fn zrandmember_withscores<K: ToRedisArgs>(key: K, count: isize) {
837        cmd("ZRANDMEMBER").arg(key).arg(count).arg("WITHSCORES")
838    }
839
840    /// Return a range of members in a sorted set, by index
841    fn zrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
842        cmd("ZRANGE").arg(key).arg(start).arg(stop)
843    }
844
845    /// Return a range of members in a sorted set, by index with scores.
846    fn zrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
847        cmd("ZRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
848    }
849
850    /// Return a range of members in a sorted set, by lexicographical range.
851    fn zrangebylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
852        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max)
853    }
854
855    /// Return a range of members in a sorted set, by lexicographical
856    /// range with offset and limit.
857    fn zrangebylex_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(
858            key: K, min: M, max: MM, offset: isize, count: isize) {
859        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
860    }
861
862    /// Return a range of members in a sorted set, by lexicographical range.
863    fn zrevrangebylex<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
864        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min)
865    }
866
867    /// Return a range of members in a sorted set, by lexicographical
868    /// range with offset and limit.
869    fn zrevrangebylex_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(
870            key: K, max: MM, min: M, offset: isize, count: isize) {
871        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
872    }
873
874    /// Return a range of members in a sorted set, by score.
875    fn zrangebyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
876        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max)
877    }
878
879    /// Return a range of members in a sorted set, by score with scores.
880    fn zrangebyscore_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
881        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
882    }
883
884    /// Return a range of members in a sorted set, by score with limit.
885    fn zrangebyscore_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
886            (key: K, min: M, max: MM, offset: isize, count: isize) {
887        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
888    }
889
890    /// Return a range of members in a sorted set, by score with limit with scores.
891    fn zrangebyscore_limit_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
892            (key: K, min: M, max: MM, offset: isize, count: isize) {
893        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
894            .arg("LIMIT").arg(offset).arg(count)
895    }
896
897    /// Determine the index of a member in a sorted set.
898    fn zrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
899        cmd("ZRANK").arg(key).arg(member)
900    }
901
902    /// Remove one or more members from a sorted set.
903    fn zrem<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
904        cmd("ZREM").arg(key).arg(members)
905    }
906
907    /// Remove all members in a sorted set between the given lexicographical range.
908    fn zrembylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
909        cmd("ZREMRANGEBYLEX").arg(key).arg(min).arg(max)
910    }
911
912    /// Remove all members in a sorted set within the given indexes.
913    fn zremrangebyrank<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
914        cmd("ZREMRANGEBYRANK").arg(key).arg(start).arg(stop)
915    }
916
917    /// Remove all members in a sorted set within the given scores.
918    fn zrembyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
919        cmd("ZREMRANGEBYSCORE").arg(key).arg(min).arg(max)
920    }
921
922    /// Return a range of members in a sorted set, by index, with scores
923    /// ordered from high to low.
924    fn zrevrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
925        cmd("ZREVRANGE").arg(key).arg(start).arg(stop)
926    }
927
928    /// Return a range of members in a sorted set, by index, with scores
929    /// ordered from high to low.
930    fn zrevrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
931        cmd("ZREVRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
932    }
933
934    /// Return a range of members in a sorted set, by score.
935    fn zrevrangebyscore<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
936        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min)
937    }
938
939    /// Return a range of members in a sorted set, by score with scores.
940    fn zrevrangebyscore_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
941        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
942    }
943
944    /// Return a range of members in a sorted set, by score with limit.
945    fn zrevrangebyscore_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
946            (key: K, max: MM, min: M, offset: isize, count: isize) {
947        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
948    }
949
950    /// Return a range of members in a sorted set, by score with limit with scores.
951    fn zrevrangebyscore_limit_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
952            (key: K, max: MM, min: M, offset: isize, count: isize) {
953        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
954            .arg("LIMIT").arg(offset).arg(count)
955    }
956
957    /// Determine the index of a member in a sorted set, with scores ordered from high to low.
958    fn zrevrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
959        cmd("ZREVRANK").arg(key).arg(member)
960    }
961
962    /// Get the score associated with the given member in a sorted set.
963    fn zscore<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
964        cmd("ZSCORE").arg(key).arg(member)
965    }
966
967    /// Get the scores associated with multiple members in a sorted set.
968    fn zscore_multiple<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: &'a [M]) {
969        cmd("ZMSCORE").arg(key).arg(members)
970    }
971
972    /// Unions multiple sorted sets and store the resulting sorted set in
973    /// a new key using SUM as aggregation function.
974    fn zunionstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
975        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys)
976    }
977
978    /// Unions multiple sorted sets and store the resulting sorted set in
979    /// a new key using MIN as aggregation function.
980    fn zunionstore_min<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
981        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN")
982    }
983
984    /// Unions multiple sorted sets and store the resulting sorted set in
985    /// a new key using MAX as aggregation function.
986    fn zunionstore_max<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K) {
987        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX")
988    }
989
990    /// [`Commands::zunionstore`], but with the ability to specify a
991    /// multiplication factor for each sorted set by pairing one with each key
992    /// in a tuple.
993    fn zunionstore_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
994        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
995        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("WEIGHTS").arg(weights)
996    }
997
998    /// [`Commands::zunionstore_min`], but with the ability to specify a
999    /// multiplication factor for each sorted set by pairing one with each key
1000    /// in a tuple.
1001    fn zunionstore_min_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
1002        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
1003        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN").arg("WEIGHTS").arg(weights)
1004    }
1005
1006    /// [`Commands::zunionstore_max`], but with the ability to specify a
1007    /// multiplication factor for each sorted set by pairing one with each key
1008    /// in a tuple.
1009    fn zunionstore_max_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) {
1010        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> (&K, &W) {(key, weight)}).unzip();
1011        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX").arg("WEIGHTS").arg(weights)
1012    }
1013
1014    // hyperloglog commands
1015
1016    /// Adds the specified elements to the specified HyperLogLog.
1017    fn pfadd<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) {
1018        cmd("PFADD").arg(key).arg(element)
1019    }
1020
1021    /// Return the approximated cardinality of the set(s) observed by the
1022    /// HyperLogLog at key(s).
1023    fn pfcount<K: ToRedisArgs>(key: K) {
1024        cmd("PFCOUNT").arg(key)
1025    }
1026
1027    /// Merge N different HyperLogLogs into a single one.
1028    fn pfmerge<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S) {
1029        cmd("PFMERGE").arg(dstkey).arg(srckeys)
1030    }
1031
1032    /// Posts a message to the given channel.
1033    fn publish<K: ToRedisArgs, E: ToRedisArgs>(channel: K, message: E) {
1034        cmd("PUBLISH").arg(channel).arg(message)
1035    }
1036
1037    /// Posts a message to the given sharded channel.
1038    fn spublish<K: ToRedisArgs, E: ToRedisArgs>(channel: K, message: E) {
1039        cmd("SPUBLISH").arg(channel).arg(message)
1040    }
1041
1042    // Object commands
1043
1044    /// Returns the encoding of a key.
1045    fn object_encoding<K: ToRedisArgs>(key: K) {
1046        cmd("OBJECT").arg("ENCODING").arg(key)
1047    }
1048
1049    /// Returns the time in seconds since the last access of a key.
1050    fn object_idletime<K: ToRedisArgs>(key: K) {
1051        cmd("OBJECT").arg("IDLETIME").arg(key)
1052    }
1053
1054    /// Returns the logarithmic access frequency counter of a key.
1055    fn object_freq<K: ToRedisArgs>(key: K) {
1056        cmd("OBJECT").arg("FREQ").arg(key)
1057    }
1058
1059    /// Returns the reference count of a key.
1060    fn object_refcount<K: ToRedisArgs>(key: K) {
1061        cmd("OBJECT").arg("REFCOUNT").arg(key)
1062    }
1063
1064    /// Returns the name of the current connection as set by CLIENT SETNAME.
1065    fn client_getname<>() {
1066        cmd("CLIENT").arg("GETNAME")
1067    }
1068
1069    /// Returns the ID of the current connection.
1070    fn client_id<>() {
1071        cmd("CLIENT").arg("ID")
1072    }
1073
1074    /// Command assigns a name to the current connection.
1075    fn client_setname<K: ToRedisArgs>(connection_name: K) {
1076        cmd("CLIENT").arg("SETNAME").arg(connection_name)
1077    }
1078
1079    // ACL commands
1080
1081    /// When Redis is configured to use an ACL file (with the aclfile
1082    /// configuration option), this command will reload the ACLs from the file,
1083    /// replacing all the current ACL rules with the ones defined in the file.
1084    #[cfg(feature = "acl")]
1085    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1086    fn acl_load<>() {
1087        cmd("ACL").arg("LOAD")
1088    }
1089
1090    /// When Redis is configured to use an ACL file (with the aclfile
1091    /// configuration option), this command will save the currently defined
1092    /// ACLs from the server memory to the ACL file.
1093    #[cfg(feature = "acl")]
1094    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1095    fn acl_save<>() {
1096        cmd("ACL").arg("SAVE")
1097    }
1098
1099    /// Shows the currently active ACL rules in the Redis server.
1100    #[cfg(feature = "acl")]
1101    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1102    fn acl_list<>() {
1103        cmd("ACL").arg("LIST")
1104    }
1105
1106    /// Shows a list of all the usernames of the currently configured users in
1107    /// the Redis ACL system.
1108    #[cfg(feature = "acl")]
1109    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1110    fn acl_users<>() {
1111        cmd("ACL").arg("USERS")
1112    }
1113
1114    /// Returns all the rules defined for an existing ACL user.
1115    #[cfg(feature = "acl")]
1116    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1117    fn acl_getuser<K: ToRedisArgs>(username: K) {
1118        cmd("ACL").arg("GETUSER").arg(username)
1119    }
1120
1121    /// Creates an ACL user without any privilege.
1122    #[cfg(feature = "acl")]
1123    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1124    fn acl_setuser<K: ToRedisArgs>(username: K) {
1125        cmd("ACL").arg("SETUSER").arg(username)
1126    }
1127
1128    /// Creates an ACL user with the specified rules or modify the rules of
1129    /// an existing user.
1130    #[cfg(feature = "acl")]
1131    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1132    fn acl_setuser_rules<K: ToRedisArgs>(username: K, rules: &'a [acl::Rule]) {
1133        cmd("ACL").arg("SETUSER").arg(username).arg(rules)
1134    }
1135
1136    /// Delete all the specified ACL users and terminate all the connections
1137    /// that are authenticated with such users.
1138    #[cfg(feature = "acl")]
1139    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1140    fn acl_deluser<K: ToRedisArgs>(usernames: &'a [K]) {
1141        cmd("ACL").arg("DELUSER").arg(usernames)
1142    }
1143
1144    /// Simulate the execution of a given command by a given user.
1145    #[cfg(feature = "acl")]
1146    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1147    fn acl_dryrun<K: ToRedisArgs, C: ToRedisArgs, A: ToRedisArgs>(username: K, command: C, args: A) {
1148        cmd("ACL").arg("DRYRUN").arg(username).arg(command).arg(args)
1149    }
1150
1151    /// Shows the available ACL categories.
1152    #[cfg(feature = "acl")]
1153    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1154    fn acl_cat<>() {
1155        cmd("ACL").arg("CAT")
1156    }
1157
1158    /// Shows all the Redis commands in the specified category.
1159    #[cfg(feature = "acl")]
1160    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1161    fn acl_cat_categoryname<K: ToRedisArgs>(categoryname: K) {
1162        cmd("ACL").arg("CAT").arg(categoryname)
1163    }
1164
1165    /// Generates a 256-bits password starting from /dev/urandom if available.
1166    #[cfg(feature = "acl")]
1167    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1168    fn acl_genpass<>() {
1169        cmd("ACL").arg("GENPASS")
1170    }
1171
1172    /// Generates a 1-to-1024-bits password starting from /dev/urandom if available.
1173    #[cfg(feature = "acl")]
1174    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1175    fn acl_genpass_bits<>(bits: isize) {
1176        cmd("ACL").arg("GENPASS").arg(bits)
1177    }
1178
1179    /// Returns the username the current connection is authenticated with.
1180    #[cfg(feature = "acl")]
1181    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1182    fn acl_whoami<>() {
1183        cmd("ACL").arg("WHOAMI")
1184    }
1185
1186    /// Shows a list of recent ACL security events
1187    #[cfg(feature = "acl")]
1188    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1189    fn acl_log<>(count: isize) {
1190        cmd("ACL").arg("LOG").arg(count)
1191
1192    }
1193
1194    /// Clears the ACL log.
1195    #[cfg(feature = "acl")]
1196    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1197    fn acl_log_reset<>() {
1198        cmd("ACL").arg("LOG").arg("RESET")
1199    }
1200
1201    /// Returns a helpful text describing the different subcommands.
1202    #[cfg(feature = "acl")]
1203    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1204    fn acl_help<>() {
1205        cmd("ACL").arg("HELP")
1206    }
1207
1208    //
1209    // geospatial commands
1210    //
1211
1212    /// Adds the specified geospatial items to the specified key.
1213    ///
1214    /// Every member has to be written as a tuple of `(longitude, latitude,
1215    /// member_name)`. It can be a single tuple, or a vector of tuples.
1216    ///
1217    /// `longitude, latitude` can be set using [`redis::geo::Coord`][1].
1218    ///
1219    /// [1]: ./geo/struct.Coord.html
1220    ///
1221    /// Returns the number of elements added to the sorted set, not including
1222    /// elements already existing for which the score was updated.
1223    ///
1224    /// # Example
1225    ///
1226    /// ```rust,no_run
1227    /// use redis::{Commands, Connection, RedisResult};
1228    /// use redis::geo::Coord;
1229    ///
1230    /// fn add_point(con: &mut Connection) -> RedisResult<isize> {
1231    ///     con.geo_add("my_gis", (Coord::lon_lat(13.361389, 38.115556), "Palermo"))
1232    /// }
1233    ///
1234    /// fn add_point_with_tuples(con: &mut Connection) -> RedisResult<isize> {
1235    ///     con.geo_add("my_gis", ("13.361389", "38.115556", "Palermo"))
1236    /// }
1237    ///
1238    /// fn add_many_points(con: &mut Connection) -> RedisResult<isize> {
1239    ///     con.geo_add("my_gis", &[
1240    ///         ("13.361389", "38.115556", "Palermo"),
1241    ///         ("15.087269", "37.502669", "Catania")
1242    ///     ])
1243    /// }
1244    /// ```
1245    #[cfg(feature = "geospatial")]
1246    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1247    fn geo_add<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1248        cmd("GEOADD").arg(key).arg(members)
1249    }
1250
1251    /// Return the distance between two members in the geospatial index
1252    /// represented by the sorted set.
1253    ///
1254    /// If one or both the members are missing, the command returns NULL, so
1255    /// it may be convenient to parse its response as either `Option<f64>` or
1256    /// `Option<String>`.
1257    ///
1258    /// # Example
1259    ///
1260    /// ```rust,no_run
1261    /// use redis::{Commands, RedisResult};
1262    /// use redis::geo::Unit;
1263    ///
1264    /// fn get_dists(con: &mut redis::Connection) {
1265    ///     let x: RedisResult<f64> = con.geo_dist(
1266    ///         "my_gis",
1267    ///         "Palermo",
1268    ///         "Catania",
1269    ///         Unit::Kilometers
1270    ///     );
1271    ///     // x is Ok(166.2742)
1272    ///
1273    ///     let x: RedisResult<Option<f64>> = con.geo_dist(
1274    ///         "my_gis",
1275    ///         "Palermo",
1276    ///         "Atlantis",
1277    ///         Unit::Meters
1278    ///     );
1279    ///     // x is Ok(None)
1280    /// }
1281    /// ```
1282    #[cfg(feature = "geospatial")]
1283    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1284    fn geo_dist<K: ToRedisArgs, M1: ToRedisArgs, M2: ToRedisArgs>(
1285        key: K,
1286        member1: M1,
1287        member2: M2,
1288        unit: geo::Unit
1289    ) {
1290        cmd("GEODIST")
1291            .arg(key)
1292            .arg(member1)
1293            .arg(member2)
1294            .arg(unit)
1295    }
1296
1297    /// Return valid [Geohash][1] strings representing the position of one or
1298    /// more members of the geospatial index represented by the sorted set at
1299    /// key.
1300    ///
1301    /// [1]: https://en.wikipedia.org/wiki/Geohash
1302    ///
1303    /// # Example
1304    ///
1305    /// ```rust,no_run
1306    /// use redis::{Commands, RedisResult};
1307    ///
1308    /// fn get_hash(con: &mut redis::Connection) {
1309    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", "Palermo");
1310    ///     // x is vec!["sqc8b49rny0"]
1311    ///
1312    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", &["Palermo", "Catania"]);
1313    ///     // x is vec!["sqc8b49rny0", "sqdtr74hyu0"]
1314    /// }
1315    /// ```
1316    #[cfg(feature = "geospatial")]
1317    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1318    fn geo_hash<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1319        cmd("GEOHASH").arg(key).arg(members)
1320    }
1321
1322    /// Return the positions of all the specified members of the geospatial
1323    /// index represented by the sorted set at key.
1324    ///
1325    /// Every position is a pair of `(longitude, latitude)`. [`redis::geo::Coord`][1]
1326    /// can be used to convert these value in a struct.
1327    ///
1328    /// [1]: ./geo/struct.Coord.html
1329    ///
1330    /// # Example
1331    ///
1332    /// ```rust,no_run
1333    /// use redis::{Commands, RedisResult};
1334    /// use redis::geo::Coord;
1335    ///
1336    /// fn get_position(con: &mut redis::Connection) {
1337    ///     let x: RedisResult<Vec<Vec<f64>>> = con.geo_pos("my_gis", &["Palermo", "Catania"]);
1338    ///     // x is [ [ 13.361389, 38.115556 ], [ 15.087269, 37.502669 ] ];
1339    ///
1340    ///     let x: Vec<Coord<f64>> = con.geo_pos("my_gis", "Palermo").unwrap();
1341    ///     // x[0].longitude is 13.361389
1342    ///     // x[0].latitude is 38.115556
1343    /// }
1344    /// ```
1345    #[cfg(feature = "geospatial")]
1346    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1347    fn geo_pos<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1348        cmd("GEOPOS").arg(key).arg(members)
1349    }
1350
1351    /// Return the members of a sorted set populated with geospatial information
1352    /// using [`geo_add`](#method.geo_add), which are within the borders of the area
1353    /// specified with the center location and the maximum distance from the center
1354    /// (the radius).
1355    ///
1356    /// Every item in the result can be read with [`redis::geo::RadiusSearchResult`][1],
1357    /// which support the multiple formats returned by `GEORADIUS`.
1358    ///
1359    /// [1]: ./geo/struct.RadiusSearchResult.html
1360    ///
1361    /// ```rust,no_run
1362    /// use redis::{Commands, RedisResult};
1363    /// use redis::geo::{RadiusOptions, RadiusSearchResult, RadiusOrder, Unit};
1364    ///
1365    /// fn radius(con: &mut redis::Connection) -> Vec<RadiusSearchResult> {
1366    ///     let opts = RadiusOptions::default().with_dist().order(RadiusOrder::Asc);
1367    ///     con.geo_radius("my_gis", 15.90, 37.21, 51.39, Unit::Kilometers, opts).unwrap()
1368    /// }
1369    /// ```
1370    #[cfg(feature = "geospatial")]
1371    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1372    fn geo_radius<K: ToRedisArgs>(
1373        key: K,
1374        longitude: f64,
1375        latitude: f64,
1376        radius: f64,
1377        unit: geo::Unit,
1378        options: geo::RadiusOptions
1379    ) {
1380        cmd("GEORADIUS")
1381            .arg(key)
1382            .arg(longitude)
1383            .arg(latitude)
1384            .arg(radius)
1385            .arg(unit)
1386            .arg(options)
1387    }
1388
1389    /// Retrieve members selected by distance with the center of `member`. The
1390    /// member itself is always contained in the results.
1391    #[cfg(feature = "geospatial")]
1392    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1393    fn geo_radius_by_member<K: ToRedisArgs, M: ToRedisArgs>(
1394        key: K,
1395        member: M,
1396        radius: f64,
1397        unit: geo::Unit,
1398        options: geo::RadiusOptions
1399    ) {
1400        cmd("GEORADIUSBYMEMBER")
1401            .arg(key)
1402            .arg(member)
1403            .arg(radius)
1404            .arg(unit)
1405            .arg(options)
1406    }
1407
1408    //
1409    // streams commands
1410    //
1411
1412    /// Ack pending stream messages checked out by a consumer.
1413    ///
1414    /// ```text
1415    /// XACK <key> <group> <id> <id> ... <id>
1416    /// ```
1417    #[cfg(feature = "streams")]
1418    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1419    fn xack<K: ToRedisArgs, G: ToRedisArgs, I: ToRedisArgs>(
1420        key: K,
1421        group: G,
1422        ids: &'a [I]) {
1423        cmd("XACK")
1424            .arg(key)
1425            .arg(group)
1426            .arg(ids)
1427    }
1428
1429
1430    /// Add a stream message by `key`. Use `*` as the `id` for the current timestamp.
1431    ///
1432    /// ```text
1433    /// XADD key <ID or *> [field value] [field value] ...
1434    /// ```
1435    #[cfg(feature = "streams")]
1436    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1437    fn xadd<K: ToRedisArgs, ID: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(
1438        key: K,
1439        id: ID,
1440        items: &'a [(F, V)]
1441    ) {
1442        cmd("XADD").arg(key).arg(id).arg(items)
1443    }
1444
1445
1446    /// BTreeMap variant for adding a stream message by `key`.
1447    /// Use `*` as the `id` for the current timestamp.
1448    ///
1449    /// ```text
1450    /// XADD key <ID or *> [rust BTreeMap] ...
1451    /// ```
1452    #[cfg(feature = "streams")]
1453    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1454    fn xadd_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1455        key: K,
1456        id: ID,
1457        map: BTM
1458    ) {
1459        cmd("XADD").arg(key).arg(id).arg(map)
1460    }
1461
1462
1463    /// Add a stream message with options.
1464    ///
1465    /// Items can be any list type, e.g.
1466    /// ```rust
1467    /// // static items
1468    /// let items = &[("key", "val"), ("key2", "val2")];
1469    /// # use std::collections::BTreeMap;
1470    /// // A map (Can be BTreeMap, HashMap, etc)
1471    /// let mut map: BTreeMap<&str, &str> = BTreeMap::new();
1472    /// map.insert("ab", "cd");
1473    /// map.insert("ef", "gh");
1474    /// map.insert("ij", "kl");
1475    /// ```
1476    ///
1477    /// ```text
1478    /// XADD key [NOMKSTREAM] [<MAXLEN|MINID> [~|=] threshold [LIMIT count]] <* | ID> field value [field value] ...
1479    /// ```
1480    #[cfg(feature = "streams")]
1481    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1482    fn xadd_options<
1483        K: ToRedisArgs, ID: ToRedisArgs, I: ToRedisArgs
1484    >(
1485        key: K,
1486        id: ID,
1487        items: I,
1488        options: &'a streams::StreamAddOptions
1489    ) {
1490        cmd("XADD")
1491            .arg(key)
1492            .arg(options)
1493            .arg(id)
1494            .arg(items)
1495    }
1496
1497
1498    /// Add a stream message while capping the stream at a maxlength.
1499    ///
1500    /// ```text
1501    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [field value] [field value] ...
1502    /// ```
1503    #[cfg(feature = "streams")]
1504    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1505    fn xadd_maxlen<
1506        K: ToRedisArgs,
1507        ID: ToRedisArgs,
1508        F: ToRedisArgs,
1509        V: ToRedisArgs
1510    >(
1511        key: K,
1512        maxlen: streams::StreamMaxlen,
1513        id: ID,
1514        items: &'a [(F, V)]
1515    ) {
1516        cmd("XADD")
1517            .arg(key)
1518            .arg(maxlen)
1519            .arg(id)
1520            .arg(items)
1521    }
1522
1523
1524    /// BTreeMap variant for adding a stream message while capping the stream at a maxlength.
1525    ///
1526    /// ```text
1527    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [rust BTreeMap] ...
1528    /// ```
1529    #[cfg(feature = "streams")]
1530    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1531    fn xadd_maxlen_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1532        key: K,
1533        maxlen: streams::StreamMaxlen,
1534        id: ID,
1535        map: BTM
1536    ) {
1537        cmd("XADD")
1538            .arg(key)
1539            .arg(maxlen)
1540            .arg(id)
1541            .arg(map)
1542    }
1543
1544    /// Perform a combined xpending and xclaim flow.
1545    ///
1546    /// ```no_run
1547    /// use redis::{Connection,Commands,RedisResult};
1548    /// use redis::streams::{StreamAutoClaimOptions, StreamAutoClaimReply};
1549    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1550    /// let mut con = client.get_connection().unwrap();
1551    ///
1552    /// let opts = StreamAutoClaimOptions::default();
1553    /// let results : RedisResult<StreamAutoClaimReply> = con.xautoclaim_options("k1", "g1", "c1", 10, "0-0", opts);
1554    /// ```
1555    ///
1556    /// ```text
1557    /// XAUTOCLAIM <key> <group> <consumer> <min-idle-time> <start> [COUNT <count>] [JUSTID]
1558    /// ```
1559    #[cfg(feature = "streams")]
1560    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1561    fn xautoclaim_options<
1562        K: ToRedisArgs,
1563        G: ToRedisArgs,
1564        C: ToRedisArgs,
1565        MIT: ToRedisArgs,
1566        S: ToRedisArgs
1567    >(
1568        key: K,
1569        group: G,
1570        consumer: C,
1571        min_idle_time: MIT,
1572        start: S,
1573        options: streams::StreamAutoClaimOptions
1574    ) {
1575        cmd("XAUTOCLAIM")
1576            .arg(key)
1577            .arg(group)
1578            .arg(consumer)
1579            .arg(min_idle_time)
1580            .arg(start)
1581            .arg(options)
1582    }
1583
1584    /// Claim pending, unacked messages, after some period of time,
1585    /// currently checked out by another consumer.
1586    ///
1587    /// This method only accepts the must-have arguments for claiming messages.
1588    /// If optional arguments are required, see `xclaim_options` below.
1589    ///
1590    /// ```text
1591    /// XCLAIM <key> <group> <consumer> <min-idle-time> [<ID-1> <ID-2>]
1592    /// ```
1593    #[cfg(feature = "streams")]
1594    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1595    fn xclaim<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs, MIT: ToRedisArgs, ID: ToRedisArgs>(
1596        key: K,
1597        group: G,
1598        consumer: C,
1599        min_idle_time: MIT,
1600        ids: &'a [ID]
1601    ) {
1602        cmd("XCLAIM")
1603            .arg(key)
1604            .arg(group)
1605            .arg(consumer)
1606            .arg(min_idle_time)
1607            .arg(ids)
1608    }
1609
1610    /// This is the optional arguments version for claiming unacked, pending messages
1611    /// currently checked out by another consumer.
1612    ///
1613    /// ```no_run
1614    /// use redis::{Connection,Commands,RedisResult};
1615    /// use redis::streams::{StreamClaimOptions,StreamClaimReply};
1616    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1617    /// let mut con = client.get_connection().unwrap();
1618    ///
1619    /// // Claim all pending messages for key "k1",
1620    /// // from group "g1", checked out by consumer "c1"
1621    /// // for 10ms with RETRYCOUNT 2 and FORCE
1622    ///
1623    /// let opts = StreamClaimOptions::default()
1624    ///     .with_force()
1625    ///     .retry(2);
1626    /// let results: RedisResult<StreamClaimReply> =
1627    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1628    ///
1629    /// // All optional arguments return a `Result<StreamClaimReply>` with one exception:
1630    /// // Passing JUSTID returns only the message `id` and omits the HashMap for each message.
1631    ///
1632    /// let opts = StreamClaimOptions::default()
1633    ///     .with_justid();
1634    /// let results: RedisResult<Vec<String>> =
1635    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1636    /// ```
1637    ///
1638    /// ```text
1639    /// XCLAIM <key> <group> <consumer> <min-idle-time> <ID-1> <ID-2>
1640    ///     [IDLE <milliseconds>] [TIME <mstime>] [RETRYCOUNT <count>]
1641    ///     [FORCE] [JUSTID] [LASTID <lastid>]
1642    /// ```
1643    #[cfg(feature = "streams")]
1644    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1645    fn xclaim_options<
1646        K: ToRedisArgs,
1647        G: ToRedisArgs,
1648        C: ToRedisArgs,
1649        MIT: ToRedisArgs,
1650        ID: ToRedisArgs
1651    >(
1652        key: K,
1653        group: G,
1654        consumer: C,
1655        min_idle_time: MIT,
1656        ids: &'a [ID],
1657        options: streams::StreamClaimOptions
1658    ) {
1659        cmd("XCLAIM")
1660            .arg(key)
1661            .arg(group)
1662            .arg(consumer)
1663            .arg(min_idle_time)
1664            .arg(ids)
1665            .arg(options)
1666    }
1667
1668
1669    /// Deletes a list of `id`s for a given stream `key`.
1670    ///
1671    /// ```text
1672    /// XDEL <key> [<ID1> <ID2> ... <IDN>]
1673    /// ```
1674    #[cfg(feature = "streams")]
1675    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1676    fn xdel<K: ToRedisArgs, ID: ToRedisArgs>(
1677        key: K,
1678        ids: &'a [ID]
1679    ) {
1680        cmd("XDEL").arg(key).arg(ids)
1681    }
1682
1683
1684    /// This command is used for creating a consumer `group`. It expects the stream key
1685    /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
1686    /// The `id` is the starting message id all consumers should read from. Use `$` If you want
1687    /// all consumers to read from the last message added to stream.
1688    ///
1689    /// ```text
1690    /// XGROUP CREATE <key> <groupname> <id or $>
1691    /// ```
1692    #[cfg(feature = "streams")]
1693    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1694    fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1695        key: K,
1696        group: G,
1697        id: ID
1698    ) {
1699        cmd("XGROUP")
1700            .arg("CREATE")
1701            .arg(key)
1702            .arg(group)
1703            .arg(id)
1704    }
1705
1706    /// This creates a `consumer` explicitly (vs implicit via XREADGROUP)
1707    /// for given stream `key.
1708    ///
1709    /// The return value is either a 0 or a 1 for the number of consumers created
1710    /// 0 means the consumer already exists
1711    ///
1712    /// ```text
1713    /// XGROUP CREATECONSUMER <key> <groupname> <consumername>
1714    /// ```
1715    #[cfg(feature = "streams")]
1716    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1717    fn xgroup_createconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
1718        key: K,
1719        group: G,
1720        consumer: C
1721    ) {
1722        cmd("XGROUP")
1723            .arg("CREATECONSUMER")
1724            .arg(key)
1725            .arg(group)
1726            .arg(consumer)
1727    }
1728
1729    /// This is the alternate version for creating a consumer `group`
1730    /// which makes the stream if it doesn't exist.
1731    ///
1732    /// ```text
1733    /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
1734    /// ```
1735    #[cfg(feature = "streams")]
1736    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1737    fn xgroup_create_mkstream<
1738        K: ToRedisArgs,
1739        G: ToRedisArgs,
1740        ID: ToRedisArgs
1741    >(
1742        key: K,
1743        group: G,
1744        id: ID
1745    ) {
1746        cmd("XGROUP")
1747            .arg("CREATE")
1748            .arg(key)
1749            .arg(group)
1750            .arg(id)
1751            .arg("MKSTREAM")
1752    }
1753
1754
1755    /// Alter which `id` you want consumers to begin reading from an existing
1756    /// consumer `group`.
1757    ///
1758    /// ```text
1759    /// XGROUP SETID <key> <groupname> <id or $>
1760    /// ```
1761    #[cfg(feature = "streams")]
1762    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1763    fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1764        key: K,
1765        group: G,
1766        id: ID
1767    ) {
1768        cmd("XGROUP")
1769            .arg("SETID")
1770            .arg(key)
1771            .arg(group)
1772            .arg(id)
1773    }
1774
1775
1776    /// Destroy an existing consumer `group` for a given stream `key`
1777    ///
1778    /// ```text
1779    /// XGROUP SETID <key> <groupname> <id or $>
1780    /// ```
1781    #[cfg(feature = "streams")]
1782    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1783    fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
1784        key: K,
1785        group: G
1786    ) {
1787        cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
1788    }
1789
1790    /// This deletes a `consumer` from an existing consumer `group`
1791    /// for given stream `key.
1792    ///
1793    /// ```text
1794    /// XGROUP DELCONSUMER <key> <groupname> <consumername>
1795    /// ```
1796    #[cfg(feature = "streams")]
1797    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1798    fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
1799        key: K,
1800        group: G,
1801        consumer: C
1802    ) {
1803        cmd("XGROUP")
1804            .arg("DELCONSUMER")
1805            .arg(key)
1806            .arg(group)
1807            .arg(consumer)
1808    }
1809
1810
1811    /// This returns all info details about
1812    /// which consumers have read messages for given consumer `group`.
1813    /// Take note of the StreamInfoConsumersReply return type.
1814    ///
1815    /// *It's possible this return value might not contain new fields
1816    /// added by Redis in future versions.*
1817    ///
1818    /// ```text
1819    /// XINFO CONSUMERS <key> <group>
1820    /// ```
1821    #[cfg(feature = "streams")]
1822    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1823    fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
1824        key: K,
1825        group: G
1826    ) {
1827        cmd("XINFO")
1828            .arg("CONSUMERS")
1829            .arg(key)
1830            .arg(group)
1831    }
1832
1833
1834    /// Returns all consumer `group`s created for a given stream `key`.
1835    /// Take note of the StreamInfoGroupsReply return type.
1836    ///
1837    /// *It's possible this return value might not contain new fields
1838    /// added by Redis in future versions.*
1839    ///
1840    /// ```text
1841    /// XINFO GROUPS <key>
1842    /// ```
1843    #[cfg(feature = "streams")]
1844    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1845    fn xinfo_groups<K: ToRedisArgs>(key: K) {
1846        cmd("XINFO").arg("GROUPS").arg(key)
1847    }
1848
1849
1850    /// Returns info about high-level stream details
1851    /// (first & last message `id`, length, number of groups, etc.)
1852    /// Take note of the StreamInfoStreamReply return type.
1853    ///
1854    /// *It's possible this return value might not contain new fields
1855    /// added by Redis in future versions.*
1856    ///
1857    /// ```text
1858    /// XINFO STREAM <key>
1859    /// ```
1860    #[cfg(feature = "streams")]
1861    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1862    fn xinfo_stream<K: ToRedisArgs>(key: K) {
1863        cmd("XINFO").arg("STREAM").arg(key)
1864    }
1865
1866    /// Returns the number of messages for a given stream `key`.
1867    ///
1868    /// ```text
1869    /// XLEN <key>
1870    /// ```
1871    #[cfg(feature = "streams")]
1872    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1873    fn xlen<K: ToRedisArgs>(key: K) {
1874        cmd("XLEN").arg(key)
1875    }
1876
1877
1878    /// This is a basic version of making XPENDING command calls which only
1879    /// passes a stream `key` and consumer `group` and it
1880    /// returns details about which consumers have pending messages
1881    /// that haven't been acked.
1882    ///
1883    /// You can use this method along with
1884    /// `xclaim` or `xclaim_options` for determining which messages
1885    /// need to be retried.
1886    ///
1887    /// Take note of the StreamPendingReply return type.
1888    ///
1889    /// ```text
1890    /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
1891    /// ```
1892    #[cfg(feature = "streams")]
1893    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1894    fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
1895        key: K,
1896        group: G
1897    )  {
1898        cmd("XPENDING").arg(key).arg(group)
1899    }
1900
1901
1902    /// This XPENDING version returns a list of all messages over the range.
1903    /// You can use this for paginating pending messages (but without the message HashMap).
1904    ///
1905    /// Start and end follow the same rules `xrange` args. Set start to `-`
1906    /// and end to `+` for the entire stream.
1907    ///
1908    /// Take note of the StreamPendingCountReply return type.
1909    ///
1910    /// ```text
1911    /// XPENDING <key> <group> <start> <stop> <count>
1912    /// ```
1913    #[cfg(feature = "streams")]
1914    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1915    fn xpending_count<
1916        K: ToRedisArgs,
1917        G: ToRedisArgs,
1918        S: ToRedisArgs,
1919        E: ToRedisArgs,
1920        C: ToRedisArgs
1921    >(
1922        key: K,
1923        group: G,
1924        start: S,
1925        end: E,
1926        count: C
1927    )  {
1928        cmd("XPENDING")
1929            .arg(key)
1930            .arg(group)
1931            .arg(start)
1932            .arg(end)
1933            .arg(count)
1934    }
1935
1936
1937    /// An alternate version of `xpending_count` which filters by `consumer` name.
1938    ///
1939    /// Start and end follow the same rules `xrange` args. Set start to `-`
1940    /// and end to `+` for the entire stream.
1941    ///
1942    /// Take note of the StreamPendingCountReply return type.
1943    ///
1944    /// ```text
1945    /// XPENDING <key> <group> <start> <stop> <count> <consumer>
1946    /// ```
1947    #[cfg(feature = "streams")]
1948    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1949    fn xpending_consumer_count<
1950        K: ToRedisArgs,
1951        G: ToRedisArgs,
1952        S: ToRedisArgs,
1953        E: ToRedisArgs,
1954        C: ToRedisArgs,
1955        CN: ToRedisArgs
1956    >(
1957        key: K,
1958        group: G,
1959        start: S,
1960        end: E,
1961        count: C,
1962        consumer: CN
1963    ) {
1964        cmd("XPENDING")
1965            .arg(key)
1966            .arg(group)
1967            .arg(start)
1968            .arg(end)
1969            .arg(count)
1970            .arg(consumer)
1971    }
1972
1973    /// Returns a range of messages in a given stream `key`.
1974    ///
1975    /// Set `start` to `-` to begin at the first message.
1976    /// Set `end` to `+` to end the most recent message.
1977    /// You can pass message `id` to both `start` and `end`.
1978    ///
1979    /// Take note of the StreamRangeReply return type.
1980    ///
1981    /// ```text
1982    /// XRANGE key start end
1983    /// ```
1984    #[cfg(feature = "streams")]
1985    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1986    fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
1987        key: K,
1988        start: S,
1989        end: E
1990    )  {
1991        cmd("XRANGE").arg(key).arg(start).arg(end)
1992    }
1993
1994
1995    /// A helper method for automatically returning all messages in a stream by `key`.
1996    /// **Use with caution!**
1997    ///
1998    /// ```text
1999    /// XRANGE key - +
2000    /// ```
2001    #[cfg(feature = "streams")]
2002    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2003    fn xrange_all<K: ToRedisArgs>(key: K)  {
2004        cmd("XRANGE").arg(key).arg("-").arg("+")
2005    }
2006
2007
2008    /// A method for paginating a stream by `key`.
2009    ///
2010    /// ```text
2011    /// XRANGE key start end [COUNT <n>]
2012    /// ```
2013    #[cfg(feature = "streams")]
2014    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2015    fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
2016        key: K,
2017        start: S,
2018        end: E,
2019        count: C
2020    )  {
2021        cmd("XRANGE")
2022            .arg(key)
2023            .arg(start)
2024            .arg(end)
2025            .arg("COUNT")
2026            .arg(count)
2027    }
2028
2029
2030    /// Read a list of `id`s for each stream `key`.
2031    /// This is the basic form of reading streams.
2032    /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
2033    /// see `xread_options`.
2034    ///
2035    /// ```text
2036    /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
2037    /// ```
2038    #[cfg(feature = "streams")]
2039    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2040    fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
2041        keys: &'a [K],
2042        ids: &'a [ID]
2043    ) {
2044        cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
2045    }
2046
2047    /// This method handles setting optional arguments for
2048    /// `XREAD` or `XREADGROUP` Redis commands.
2049    /// ```no_run
2050    /// use redis::{Connection,RedisResult,Commands};
2051    /// use redis::streams::{StreamReadOptions,StreamReadReply};
2052    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2053    /// let mut con = client.get_connection().unwrap();
2054    ///
2055    /// // Read 10 messages from the start of the stream,
2056    /// // without registering as a consumer group.
2057    ///
2058    /// let opts = StreamReadOptions::default()
2059    ///     .count(10);
2060    /// let results: RedisResult<StreamReadReply> =
2061    ///     con.xread_options(&["k1"], &["0"], &opts);
2062    ///
2063    /// // Read all undelivered messages for a given
2064    /// // consumer group. Be advised: the consumer group must already
2065    /// // exist before making this call. Also note: we're passing
2066    /// // '>' as the id here, which means all undelivered messages.
2067    ///
2068    /// let opts = StreamReadOptions::default()
2069    ///     .group("group-1", "consumer-1");
2070    /// let results: RedisResult<StreamReadReply> =
2071    ///     con.xread_options(&["k1"], &[">"], &opts);
2072    /// ```
2073    ///
2074    /// ```text
2075    /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
2076    ///     STREAMS key_1 key_2 ... key_N
2077    ///     ID_1 ID_2 ... ID_N
2078    ///
2079    /// XREADGROUP [GROUP group-name consumer-name] [BLOCK <milliseconds>] [COUNT <count>] [NOACK]
2080    ///     STREAMS key_1 key_2 ... key_N
2081    ///     ID_1 ID_2 ... ID_N
2082    /// ```
2083    #[cfg(feature = "streams")]
2084    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2085    fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
2086        keys: &'a [K],
2087        ids: &'a [ID],
2088        options: &'a streams::StreamReadOptions
2089    ) {
2090        cmd(if options.read_only() {
2091            "XREAD"
2092        } else {
2093            "XREADGROUP"
2094        })
2095        .arg(options)
2096        .arg("STREAMS")
2097        .arg(keys)
2098        .arg(ids)
2099    }
2100
2101    /// This is the reverse version of `xrange`.
2102    /// The same rules apply for `start` and `end` here.
2103    ///
2104    /// ```text
2105    /// XREVRANGE key end start
2106    /// ```
2107    #[cfg(feature = "streams")]
2108    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2109    fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
2110        key: K,
2111        end: E,
2112        start: S
2113    ) {
2114        cmd("XREVRANGE").arg(key).arg(end).arg(start)
2115    }
2116
2117    /// This is the reverse version of `xrange_all`.
2118    /// The same rules apply for `start` and `end` here.
2119    ///
2120    /// ```text
2121    /// XREVRANGE key + -
2122    /// ```
2123    fn xrevrange_all<K: ToRedisArgs>(key: K) {
2124        cmd("XREVRANGE").arg(key).arg("+").arg("-")
2125    }
2126
2127    /// This is the reverse version of `xrange_count`.
2128    /// The same rules apply for `start` and `end` here.
2129    ///
2130    /// ```text
2131    /// XREVRANGE key end start [COUNT <n>]
2132    /// ```
2133    #[cfg(feature = "streams")]
2134    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2135    fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
2136        key: K,
2137        end: E,
2138        start: S,
2139        count: C
2140    ) {
2141        cmd("XREVRANGE")
2142            .arg(key)
2143            .arg(end)
2144            .arg(start)
2145            .arg("COUNT")
2146            .arg(count)
2147    }
2148
2149    /// Trim a stream `key` to a MAXLEN count.
2150    ///
2151    /// ```text
2152    /// XTRIM <key> MAXLEN [~|=] <count>  (Same as XADD MAXLEN option)
2153    /// ```
2154    #[cfg(feature = "streams")]
2155    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2156    fn xtrim<K: ToRedisArgs>(
2157        key: K,
2158        maxlen: streams::StreamMaxlen
2159    ) {
2160        cmd("XTRIM").arg(key).arg(maxlen)
2161    }
2162
2163     /// Trim a stream `key` with full options
2164     ///
2165     /// ```text
2166     /// XTRIM <key> <MAXLEN|MINID> [~|=] <threshold> [LIMIT <count>]  (Same as XADD MAXID|MINID options)
2167     /// ```
2168    #[cfg(feature = "streams")]
2169    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2170    fn xtrim_options<K: ToRedisArgs>(
2171        key: K,
2172        options: &'a streams::StreamTrimOptions
2173    ) {
2174        cmd("XTRIM").arg(key).arg(options)
2175    }
2176
2177    // script commands
2178
2179    /// Adds a prepared script command to the pipeline.
2180    ///
2181    /// Note: unlike a call to [`invoke`](crate::ScriptInvocation::invoke), if the script isn't loaded during the pipeline operation,
2182    /// it will not automatically be loaded and retried. The script can be loaded using the
2183    /// [`load`](crate::ScriptInvocation::load) operation.
2184    #[cfg_attr(feature = "script", doc = r##"
2185
2186# Examples:
2187
2188```rust,no_run
2189# fn do_something() -> redis::RedisResult<()> {
2190# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2191# let mut con = client.get_connection().unwrap();
2192let script = redis::Script::new(r"
2193    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2194");
2195script.prepare_invoke().load(&mut con)?;
2196let (a, b): (isize, isize) = redis::pipe()
2197    .invoke_script(script.arg(1).arg(2))
2198    .invoke_script(script.arg(2).arg(3))
2199    .query(&mut con)?;
2200
2201assert_eq!(a, 3);
2202assert_eq!(b, 5);
2203# Ok(()) }
2204```
2205"##)]
2206    #[cfg(feature = "script")]
2207    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2208    fn invoke_script<>(invocation: &'a crate::ScriptInvocation<'a>) {
2209        &mut invocation.eval_cmd()
2210    }
2211
2212    // cleanup commands
2213
2214    /// Deletes all the keys of all databases
2215    ///
2216    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2217    /// of your Redis server.
2218    ///
2219    /// To enforce a flush mode, use [`Commands::flushall_options`].
2220    ///
2221    /// ```text
2222    /// FLUSHALL
2223    /// ```
2224    fn flushall<>() {
2225        &mut cmd("FLUSHALL")
2226    }
2227
2228    /// Deletes all the keys of all databases with options
2229    ///
2230    /// ```text
2231    /// FLUSHALL [ASYNC|SYNC]
2232    /// ```
2233    fn flushall_options<>(options: &'a FlushAllOptions) {
2234        cmd("FLUSHALL").arg(options)
2235    }
2236
2237    /// Deletes all the keys of the current database
2238    ///
2239    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2240    /// of your Redis server.
2241    ///
2242    /// To enforce a flush mode, use [`Commands::flushdb_options`].
2243    ///
2244    /// ```text
2245    /// FLUSHDB
2246    /// ```
2247    fn flushdb<>() {
2248        &mut cmd("FLUSHDB")
2249    }
2250
2251    /// Deletes all the keys of the current database with options
2252    ///
2253    /// ```text
2254    /// FLUSHDB [ASYNC|SYNC]
2255    /// ```
2256    fn flushdb_options<>(options: &'a FlushDbOptions) {
2257        cmd("FLUSHDB").arg(options)
2258    }
2259}
2260
2261/// Allows pubsub callbacks to stop receiving messages.
2262///
2263/// Arbitrary data may be returned from `Break`.
2264pub enum ControlFlow<U> {
2265    /// Continues.
2266    Continue,
2267    /// Breaks with a value.
2268    Break(U),
2269}
2270
2271/// The PubSub trait allows subscribing to one or more channels
2272/// and receiving a callback whenever a message arrives.
2273///
2274/// Each method handles subscribing to the list of keys, waiting for
2275/// messages, and unsubscribing from the same list of channels once
2276/// a ControlFlow::Break is encountered.
2277///
2278/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2279/// for calling other methods.
2280///
2281/// # Examples
2282///
2283/// ```rust,no_run
2284/// # fn do_something() -> redis::RedisResult<()> {
2285/// use redis::{PubSubCommands, ControlFlow};
2286/// let client = redis::Client::open("redis://127.0.0.1/")?;
2287/// let mut con = client.get_connection()?;
2288/// let mut count = 0;
2289/// con.subscribe(&["foo"], |msg| {
2290///     // do something with message
2291///     assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2292///
2293///     // increment messages seen counter
2294///     count += 1;
2295///     match count {
2296///         // stop after receiving 10 messages
2297///         10 => ControlFlow::Break(()),
2298///         _ => ControlFlow::Continue,
2299///     }
2300/// })?;
2301/// # Ok(()) }
2302/// ```
2303// TODO In the future, it would be nice to implement Try such that `?` will work
2304//      within the closure.
2305pub trait PubSubCommands: Sized {
2306    /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2307    /// closure for each message received.
2308    ///
2309    /// For every `Msg` passed to the provided closure, either
2310    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2311    /// method will not return until `ControlFlow::Break` is observed.
2312    fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2313    where
2314        F: FnMut(Msg) -> ControlFlow<U>,
2315        C: ToRedisArgs;
2316
2317    /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
2318    /// closure for each message received.
2319    ///
2320    /// For every `Msg` passed to the provided closure, either
2321    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2322    /// method will not return until `ControlFlow::Break` is observed.
2323    fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
2324    where
2325        F: FnMut(Msg) -> ControlFlow<U>,
2326        P: ToRedisArgs;
2327}
2328
2329impl<T> Commands for T where T: ConnectionLike {}
2330
2331#[cfg(feature = "aio")]
2332impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
2333
2334impl PubSubCommands for Connection {
2335    fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
2336    where
2337        F: FnMut(Msg) -> ControlFlow<U>,
2338        C: ToRedisArgs,
2339    {
2340        let mut pubsub = self.as_pubsub();
2341        pubsub.subscribe(channels)?;
2342
2343        loop {
2344            let msg = pubsub.get_message()?;
2345            match func(msg) {
2346                ControlFlow::Continue => continue,
2347                ControlFlow::Break(value) => return Ok(value),
2348            }
2349        }
2350    }
2351
2352    fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
2353    where
2354        F: FnMut(Msg) -> ControlFlow<U>,
2355        P: ToRedisArgs,
2356    {
2357        let mut pubsub = self.as_pubsub();
2358        pubsub.psubscribe(patterns)?;
2359
2360        loop {
2361            let msg = pubsub.get_message()?;
2362            match func(msg) {
2363                ControlFlow::Continue => continue,
2364                ControlFlow::Break(value) => return Ok(value),
2365            }
2366        }
2367    }
2368}
2369
2370/// Options for the [SCAN](https://redis.io/commands/scan) command
2371///
2372/// # Example
2373///
2374/// ```rust
2375/// use redis::{Commands, RedisResult, ScanOptions, Iter};
2376/// fn force_fetching_every_matching_key<'a, T: redis::FromRedisValue>(
2377///     con: &'a mut redis::Connection,
2378///     pattern: &'a str,
2379///     count: usize,
2380/// ) -> RedisResult<Iter<'a, T>> {
2381///     let opts = ScanOptions::default()
2382///         .with_pattern(pattern)
2383///         .with_count(count);
2384///     con.scan_options(opts)
2385/// }
2386/// ```
2387#[derive(Default)]
2388pub struct ScanOptions {
2389    pattern: Option<String>,
2390    count: Option<usize>,
2391    scan_type: Option<String>,
2392}
2393
2394impl ScanOptions {
2395    /// Limit the results to the first N matching items.
2396    pub fn with_count(mut self, n: usize) -> Self {
2397        self.count = Some(n);
2398        self
2399    }
2400
2401    /// Pattern for scan
2402    pub fn with_pattern(mut self, p: impl Into<String>) -> Self {
2403        self.pattern = Some(p.into());
2404        self
2405    }
2406
2407    /// Limit the results to those with the given Redis type
2408    pub fn with_type(mut self, t: impl Into<String>) -> Self {
2409        self.scan_type = Some(t.into());
2410        self
2411    }
2412}
2413
2414impl ToRedisArgs for ScanOptions {
2415    fn write_redis_args<W>(&self, out: &mut W)
2416    where
2417        W: ?Sized + RedisWrite,
2418    {
2419        if let Some(p) = &self.pattern {
2420            out.write_arg(b"MATCH");
2421            out.write_arg_fmt(p);
2422        }
2423
2424        if let Some(n) = self.count {
2425            out.write_arg(b"COUNT");
2426            out.write_arg_fmt(n);
2427        }
2428
2429        if let Some(t) = &self.scan_type {
2430            out.write_arg(b"TYPE");
2431            out.write_arg_fmt(t);
2432        }
2433    }
2434
2435    fn num_of_args(&self) -> usize {
2436        let mut len = 0;
2437        if self.pattern.is_some() {
2438            len += 2;
2439        }
2440        if self.count.is_some() {
2441            len += 2;
2442        }
2443        if self.scan_type.is_some() {
2444            len += 2;
2445        }
2446        len
2447    }
2448}
2449
2450/// Options for the [LPOS](https://redis.io/commands/lpos) command
2451///
2452/// # Example
2453///
2454/// ```rust,no_run
2455/// use redis::{Commands, RedisResult, LposOptions};
2456/// fn fetch_list_position(
2457///     con: &mut redis::Connection,
2458///     key: &str,
2459///     value: &str,
2460///     count: usize,
2461///     rank: isize,
2462///     maxlen: usize,
2463/// ) -> RedisResult<Vec<usize>> {
2464///     let opts = LposOptions::default()
2465///         .count(count)
2466///         .rank(rank)
2467///         .maxlen(maxlen);
2468///     con.lpos(key, value, opts)
2469/// }
2470/// ```
2471#[derive(Default)]
2472pub struct LposOptions {
2473    count: Option<usize>,
2474    maxlen: Option<usize>,
2475    rank: Option<isize>,
2476}
2477
2478impl LposOptions {
2479    /// Limit the results to the first N matching items.
2480    pub fn count(mut self, n: usize) -> Self {
2481        self.count = Some(n);
2482        self
2483    }
2484
2485    /// Return the value of N from the matching items.
2486    pub fn rank(mut self, n: isize) -> Self {
2487        self.rank = Some(n);
2488        self
2489    }
2490
2491    /// Limit the search to N items in the list.
2492    pub fn maxlen(mut self, n: usize) -> Self {
2493        self.maxlen = Some(n);
2494        self
2495    }
2496}
2497
2498impl ToRedisArgs for LposOptions {
2499    fn write_redis_args<W>(&self, out: &mut W)
2500    where
2501        W: ?Sized + RedisWrite,
2502    {
2503        if let Some(n) = self.count {
2504            out.write_arg(b"COUNT");
2505            out.write_arg_fmt(n);
2506        }
2507
2508        if let Some(n) = self.rank {
2509            out.write_arg(b"RANK");
2510            out.write_arg_fmt(n);
2511        }
2512
2513        if let Some(n) = self.maxlen {
2514            out.write_arg(b"MAXLEN");
2515            out.write_arg_fmt(n);
2516        }
2517    }
2518
2519    fn num_of_args(&self) -> usize {
2520        let mut len = 0;
2521        if self.count.is_some() {
2522            len += 2;
2523        }
2524        if self.rank.is_some() {
2525            len += 2;
2526        }
2527        if self.maxlen.is_some() {
2528            len += 2;
2529        }
2530        len
2531    }
2532}
2533
2534/// Enum for the LEFT | RIGHT args used by some commands
2535pub enum Direction {
2536    /// Targets the first element (head) of the list
2537    Left,
2538    /// Targets the last element (tail) of the list
2539    Right,
2540}
2541
2542impl ToRedisArgs for Direction {
2543    fn write_redis_args<W>(&self, out: &mut W)
2544    where
2545        W: ?Sized + RedisWrite,
2546    {
2547        let s: &[u8] = match self {
2548            Direction::Left => b"LEFT",
2549            Direction::Right => b"RIGHT",
2550        };
2551        out.write_arg(s);
2552    }
2553}
2554
2555/// Options for the [SET](https://redis.io/commands/set) command
2556///
2557/// # Example
2558/// ```rust,no_run
2559/// use redis::{Commands, RedisResult, SetOptions, SetExpiry, ExistenceCheck};
2560/// fn set_key_value(
2561///     con: &mut redis::Connection,
2562///     key: &str,
2563///     value: &str,
2564/// ) -> RedisResult<Vec<usize>> {
2565///     let opts = SetOptions::default()
2566///         .conditional_set(ExistenceCheck::NX)
2567///         .get(true)
2568///         .with_expiration(SetExpiry::EX(60));
2569///     con.set_options(key, value, opts)
2570/// }
2571/// ```
2572#[derive(Clone, Copy, Default)]
2573pub struct SetOptions {
2574    conditional_set: Option<ExistenceCheck>,
2575    get: bool,
2576    expiration: Option<SetExpiry>,
2577}
2578
2579impl SetOptions {
2580    /// Set the existence check for the SET command
2581    pub fn conditional_set(mut self, existence_check: ExistenceCheck) -> Self {
2582        self.conditional_set = Some(existence_check);
2583        self
2584    }
2585
2586    /// Set the GET option for the SET command
2587    pub fn get(mut self, get: bool) -> Self {
2588        self.get = get;
2589        self
2590    }
2591
2592    /// Set the expiration for the SET command
2593    pub fn with_expiration(mut self, expiration: SetExpiry) -> Self {
2594        self.expiration = Some(expiration);
2595        self
2596    }
2597}
2598
2599impl ToRedisArgs for SetOptions {
2600    fn write_redis_args<W>(&self, out: &mut W)
2601    where
2602        W: ?Sized + RedisWrite,
2603    {
2604        if let Some(ref conditional_set) = self.conditional_set {
2605            match conditional_set {
2606                ExistenceCheck::NX => {
2607                    out.write_arg(b"NX");
2608                }
2609                ExistenceCheck::XX => {
2610                    out.write_arg(b"XX");
2611                }
2612            }
2613        }
2614        if self.get {
2615            out.write_arg(b"GET");
2616        }
2617        if let Some(ref expiration) = self.expiration {
2618            match expiration {
2619                SetExpiry::EX(secs) => {
2620                    out.write_arg(b"EX");
2621                    out.write_arg(format!("{}", secs).as_bytes());
2622                }
2623                SetExpiry::PX(millis) => {
2624                    out.write_arg(b"PX");
2625                    out.write_arg(format!("{}", millis).as_bytes());
2626                }
2627                SetExpiry::EXAT(unix_time) => {
2628                    out.write_arg(b"EXAT");
2629                    out.write_arg(format!("{}", unix_time).as_bytes());
2630                }
2631                SetExpiry::PXAT(unix_time) => {
2632                    out.write_arg(b"PXAT");
2633                    out.write_arg(format!("{}", unix_time).as_bytes());
2634                }
2635                SetExpiry::KEEPTTL => {
2636                    out.write_arg(b"KEEPTTL");
2637                }
2638            }
2639        }
2640    }
2641}
2642
2643/// Options for the [FLUSHALL](https://redis.io/commands/flushall) command
2644///
2645/// # Example
2646/// ```rust,no_run
2647/// use redis::{Commands, RedisResult, FlushAllOptions};
2648/// fn flushall_sync(
2649///     con: &mut redis::Connection,
2650/// ) -> RedisResult<()> {
2651///     let opts = FlushAllOptions{blocking: true};
2652///     con.flushall_options(&opts)
2653/// }
2654/// ```
2655#[derive(Clone, Copy, Default)]
2656pub struct FlushAllOptions {
2657    /// Blocking (`SYNC`) waits for completion, non-blocking (`ASYNC`) runs in the background
2658    pub blocking: bool,
2659}
2660
2661impl FlushAllOptions {
2662    /// Set whether to run blocking (`SYNC`) or non-blocking (`ASYNC`) flush
2663    pub fn blocking(mut self, blocking: bool) -> Self {
2664        self.blocking = blocking;
2665        self
2666    }
2667}
2668
2669impl ToRedisArgs for FlushAllOptions {
2670    fn write_redis_args<W>(&self, out: &mut W)
2671    where
2672        W: ?Sized + RedisWrite,
2673    {
2674        if self.blocking {
2675            out.write_arg(b"SYNC");
2676        } else {
2677            out.write_arg(b"ASYNC");
2678        };
2679    }
2680}
2681
2682/// Options for the [FLUSHDB](https://redis.io/commands/flushdb) command
2683pub type FlushDbOptions = FlushAllOptions;
2684
2685/// Creates HELLO command for RESP3 with RedisConnectionInfo
2686pub fn resp3_hello(connection_info: &RedisConnectionInfo) -> Cmd {
2687    let mut hello_cmd = cmd("HELLO");
2688    hello_cmd.arg("3");
2689    if let Some(password) = &connection_info.password {
2690        let username: &str = match connection_info.username.as_ref() {
2691            None => "default",
2692            Some(username) => username,
2693        };
2694        hello_cmd.arg("AUTH").arg(username).arg(password);
2695    }
2696
2697    hello_cmd
2698}