redis/commands/
mod.rs

1#![allow(unused_parens)]
2
3use crate::cmd::{cmd, Cmd, Iter};
4use crate::connection::{Connection, ConnectionLike, Msg};
5use crate::pipeline::Pipeline;
6use crate::types::{
7    ExistenceCheck, ExpireOption, Expiry, FieldExistenceCheck, FromRedisValue, IntegerReplyOrNoOp,
8    NumericBehavior, RedisResult, RedisWrite, SetExpiry, ToRedisArgs, ToSingleRedisArg,
9    ValueComparison,
10};
11
12#[cfg(feature = "vector-sets")]
13use crate::types::Value;
14
15#[cfg(feature = "vector-sets")]
16use serde::ser::Serialize;
17use std::collections::HashSet;
18
19#[macro_use]
20mod macros;
21
22#[cfg(feature = "json")]
23#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
24mod json;
25
26#[cfg(feature = "json")]
27pub use json::JsonCommands;
28
29#[cfg(all(feature = "json", feature = "aio"))]
30pub use json::JsonAsyncCommands;
31
32#[cfg(feature = "cluster")]
33use crate::cluster_handling::sync_connection::ClusterPipeline;
34
35#[cfg(feature = "geospatial")]
36pub mod geo;
37
38#[cfg(feature = "streams")]
39pub mod streams;
40
41#[cfg(feature = "acl")]
42pub mod acl;
43use crate::RedisConnectionInfo;
44
45#[cfg(feature = "vector-sets")]
46#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
47pub mod vector_sets;
48
49#[cfg(any(feature = "cluster", feature = "cache-aio"))]
50enum Properties {
51    ReadOnlyCacheable,
52    ReadOnly,
53    Neither,
54}
55
56#[cfg(any(feature = "cluster", feature = "cache-aio"))]
57fn command_properties(cmd: &[u8]) -> Properties {
58    match cmd {
59        // ReadonlyCacheable: Commands that operate on concrete keys and return cacheable values
60        b"BITCOUNT" | b"BITFIELD_RO" | b"BITPOS" | b"DUMP" | b"EXISTS" | b"GEODIST"
61        | b"GEOHASH" | b"GEOPOS" | b"GET" | b"GETBIT" | b"GETRANGE" | b"HEXISTS" | b"HGET"
62        | b"HGETALL" | b"HKEYS" | b"HLEN" | b"HMGET" | b"HSTRLEN" | b"HVALS" | b"JSON.ARRINDEX"
63        | b"JSON.ARRLEN" | b"JSON.GET" | b"JSON.OBJLEN" | b"JSON.OBJKEYS" | b"JSON.MGET"
64        | b"JSON.RESP" | b"JSON.STRLEN" | b"JSON.TYPE" | b"LCS" | b"LINDEX" | b"LLEN" | b"LPOS"
65        | b"LRANGE" | b"MGET" | b"SCARD" | b"SDIFF" | b"SINTER" | b"SINTERCARD" | b"SISMEMBER"
66        | b"SMEMBERS" | b"SMISMEMBER" | b"STRLEN" | b"SUBSTR" | b"SUNION" | b"TYPE" | b"ZCARD"
67        | b"ZCOUNT" | b"ZDIFF" | b"ZINTER" | b"ZINTERCARD" | b"ZLEXCOUNT" | b"ZMSCORE"
68        | b"ZRANGE" | b"ZRANGEBYLEX" | b"ZRANGEBYSCORE" | b"ZRANK" | b"ZREVRANGE"
69        | b"ZREVRANGEBYLEX" | b"ZREVRANGEBYSCORE" | b"ZREVRANK" | b"ZSCORE" | b"ZUNION" => {
70            Properties::ReadOnlyCacheable
71        }
72
73        b"ACL CAT"
74        | b"ACL DELUSER"
75        | b"ACL DRYRUN"
76        | b"ACL GENPASS"
77        | b"ACL GETUSER"
78        | b"ACL HELP"
79        | b"ACL LIST"
80        | b"ACL LOAD"
81        | b"ACL LOG"
82        | b"ACL SAVE"
83        | b"ACL SETUSER"
84        | b"ACL USERS"
85        | b"ACL WHOAMI"
86        | b"AUTH"
87        | b"BGREWRITEAOF"
88        | b"BGSAVE"
89        | b"PFCOUNT"
90        | b"CLIENT ID"
91        | b"CLIENT CACHING"
92        | b"CLIENT CAPA"
93        | b"CLIENT GETNAME"
94        | b"CLIENT GETREDIR"
95        | b"CLIENT HELP"
96        | b"CLIENT INFO"
97        | b"CLIENT KILL"
98        | b"CLIENT LIST"
99        | b"CLIENT NO-EVICT"
100        | b"CLIENT NO-TOUCH"
101        | b"CLIENT PAUSE"
102        | b"CLIENT REPLY"
103        | b"CLIENT SETINFO"
104        | b"CLIENT SETNAME"
105        | b"CLIENT TRACKING"
106        | b"CLIENT TRACKINGINFO"
107        | b"CLIENT UNBLOCK"
108        | b"CLIENT UNPAUSE"
109        | b"CLUSTER COUNT-FAILURE-REPORTS"
110        | b"CLUSTER COUNTKEYSINSLOT"
111        | b"CLUSTER FAILOVER"
112        | b"CLUSTER GETKEYSINSLOT"
113        | b"CLUSTER HELP"
114        | b"CLUSTER INFO"
115        | b"CLUSTER KEYSLOT"
116        | b"CLUSTER LINKS"
117        | b"CLUSTER MYID"
118        | b"CLUSTER MYSHARDID"
119        | b"CLUSTER NODES"
120        | b"CLUSTER REPLICATE"
121        | b"CLUSTER SAVECONFIG"
122        | b"CLUSTER SHARDS"
123        | b"CLUSTER SLOTS"
124        | b"COMMAND COUNT"
125        | b"COMMAND DOCS"
126        | b"COMMAND GETKEYS"
127        | b"COMMAND GETKEYSANDFLAGS"
128        | b"COMMAND HELP"
129        | b"COMMAND INFO"
130        | b"COMMAND LIST"
131        | b"CONFIG GET"
132        | b"CONFIG HELP"
133        | b"CONFIG RESETSTAT"
134        | b"CONFIG REWRITE"
135        | b"CONFIG SET"
136        | b"DBSIZE"
137        | b"ECHO"
138        | b"EVAL_RO"
139        | b"EVALSHA_RO"
140        | b"EXPIRETIME"
141        | b"FCALL_RO"
142        | b"FT.AGGREGATE"
143        | b"FT.EXPLAIN"
144        | b"FT.EXPLAINCLI"
145        | b"FT.INFO"
146        | b"FT.PROFILE"
147        | b"FT.SEARCH"
148        | b"FT._ALIASLIST"
149        | b"FT._LIST"
150        | b"FUNCTION DUMP"
151        | b"FUNCTION HELP"
152        | b"FUNCTION KILL"
153        | b"FUNCTION LIST"
154        | b"FUNCTION STATS"
155        | b"GEORADIUSBYMEMBER_RO"
156        | b"GEORADIUS_RO"
157        | b"GEOSEARCH"
158        | b"HELLO"
159        | b"HRANDFIELD"
160        | b"HSCAN"
161        | b"INFO"
162        | b"JSON.DEBUG"
163        | b"KEYS"
164        | b"LASTSAVE"
165        | b"LATENCY DOCTOR"
166        | b"LATENCY GRAPH"
167        | b"LATENCY HELP"
168        | b"LATENCY HISTOGRAM"
169        | b"LATENCY HISTORY"
170        | b"LATENCY LATEST"
171        | b"LATENCY RESET"
172        | b"LOLWUT"
173        | b"MEMORY DOCTOR"
174        | b"MEMORY HELP"
175        | b"MEMORY MALLOC-STATS"
176        | b"MEMORY PURGE"
177        | b"MEMORY STATS"
178        | b"MEMORY USAGE"
179        | b"MODULE HELP"
180        | b"MODULE LIST"
181        | b"MODULE LOAD"
182        | b"MODULE LOADEX"
183        | b"MODULE UNLOAD"
184        | b"OBJECT ENCODING"
185        | b"OBJECT FREQ"
186        | b"OBJECT HELP"
187        | b"OBJECT IDLETIME"
188        | b"OBJECT REFCOUNT"
189        | b"PEXPIRETIME"
190        | b"PING"
191        | b"PTTL"
192        | b"PUBLISH"
193        | b"PUBSUB CHANNELS"
194        | b"PUBSUB HELP"
195        | b"PUBSUB NUMPAT"
196        | b"PUBSUB NUMSUB"
197        | b"PUBSUB SHARDCHANNELS"
198        | b"PUBSUB SHARDNUMSUB"
199        | b"RANDOMKEY"
200        | b"REPLICAOF"
201        | b"RESET"
202        | b"ROLE"
203        | b"SAVE"
204        | b"SCAN"
205        | b"SCRIPT DEBUG"
206        | b"SCRIPT EXISTS"
207        | b"SCRIPT FLUSH"
208        | b"SCRIPT KILL"
209        | b"SCRIPT LOAD"
210        | b"SCRIPT SHOW"
211        | b"SELECT"
212        | b"SHUTDOWN"
213        | b"SLOWLOG GET"
214        | b"SLOWLOG HELP"
215        | b"SLOWLOG LEN"
216        | b"SLOWLOG RESET"
217        | b"SORT_RO"
218        | b"SPUBLISH"
219        | b"SRANDMEMBER"
220        | b"SSCAN"
221        | b"SSUBSCRIBE"
222        | b"SUBSCRIBE"
223        | b"SUNSUBSCRIBE"
224        | b"TIME"
225        | b"TOUCH"
226        | b"TTL"
227        | b"UNSUBSCRIBE"
228        | b"XINFO CONSUMERS"
229        | b"XINFO GROUPS"
230        | b"XINFO STREAM"
231        | b"XLEN"
232        | b"XPENDING"
233        | b"XRANGE"
234        | b"XREAD"
235        | b"XREVRANGE"
236        | b"ZRANDMEMBER"
237        | b"ZSCAN" => Properties::ReadOnly,
238        _ => Properties::Neither,
239    }
240}
241
242#[cfg(feature = "cluster")]
243pub(crate) fn is_readonly_cmd(cmd: &[u8]) -> bool {
244    matches!(
245        command_properties(cmd),
246        Properties::ReadOnly | Properties::ReadOnlyCacheable
247    )
248}
249
250#[cfg(feature = "cache-aio")]
251pub(crate) fn is_cachable_cmd(cmd: &[u8]) -> bool {
252    matches!(command_properties(cmd), Properties::ReadOnlyCacheable)
253}
254
255// Note - Brackets are needed around return types for purposes of macro branching.
256implement_commands! {
257    'a
258    // most common operations
259
260    /// Get the value of a key.  If key is a vec this becomes an `MGET` (if using `TypedCommands`, you should specifically use `mget` to get the correct return type.
261    /// [Redis Docs](https://redis.io/commands/get/)
262    fn get<K: ToSingleRedisArg >(key: K) -> (Option<String>) {
263        cmd("GET").arg(key)
264    }
265
266    /// Get values of keys
267    /// [Redis Docs](https://redis.io/commands/MGET)
268    fn mget<K: ToRedisArgs>(key: K) -> (Vec<Option<String>>) {
269        cmd("MGET").arg(key)
270    }
271
272    /// Gets all keys matching pattern
273    /// [Redis Docs](https://redis.io/commands/KEYS)
274    fn keys<K: ToSingleRedisArg>(key: K) -> (Vec<String>) {
275        cmd("KEYS").arg(key)
276    }
277
278    /// Set the string value of a key.
279    /// [Redis Docs](https://redis.io/commands/SET)
280    fn set<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V) -> (()) {
281        cmd("SET").arg(key).arg(value)
282    }
283
284    /// Set the string value of a key with options.
285    /// [Redis Docs](https://redis.io/commands/SET)
286    fn set_options<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V, options: SetOptions) -> (Option<String>) {
287        cmd("SET").arg(key).arg(value).arg(options)
288    }
289
290    /// Sets multiple keys to their values.
291    /// [Redis Docs](https://redis.io/commands/MSET)
292    fn mset<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) -> (()) {
293        cmd("MSET").arg(items)
294    }
295
296    /// Set the value and expiration of a key.
297    /// [Redis Docs](https://redis.io/commands/SETEX)
298    fn set_ex<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V, seconds: u64) -> (()) {
299        cmd("SETEX").arg(key).arg(seconds).arg(value)
300    }
301
302    /// Set the value and expiration in milliseconds of a key.
303    /// [Redis Docs](https://redis.io/commands/PSETEX)
304    fn pset_ex<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V, milliseconds: u64) -> (()) {
305        cmd("PSETEX").arg(key).arg(milliseconds).arg(value)
306    }
307
308    /// Set the value of a key, only if the key does not exist
309    /// [Redis Docs](https://redis.io/commands/SETNX)
310    fn set_nx<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V) -> (bool) {
311        cmd("SETNX").arg(key).arg(value)
312    }
313
314    /// Sets multiple keys to their values failing if at least one already exists.
315    /// [Redis Docs](https://redis.io/commands/MSETNX)
316    fn mset_nx<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) -> (bool) {
317        cmd("MSETNX").arg(items)
318    }
319
320    /// Sets the given keys to their respective values.
321    /// This command is an extension of the MSETNX that adds expiration and XX options.
322    /// [Redis Docs](https://redis.io/commands/MSETEX)
323    fn mset_ex<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)], options: MSetOptions) -> (bool) {
324        cmd("MSETEX").arg(items.len()).arg(items).arg(options)
325    }
326
327    /// Set the string value of a key and return its old value.
328    /// [Redis Docs](https://redis.io/commands/GETSET)
329    fn getset<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V) -> (Option<String>) {
330        cmd("GETSET").arg(key).arg(value)
331    }
332
333    /// Get a range of bytes/substring from the value of a key. Negative values provide an offset from the end of the value.
334    /// Redis returns an empty string if the key doesn't exist, not Nil
335    /// [Redis Docs](https://redis.io/commands/GETRANGE)
336    fn getrange<K: ToSingleRedisArg>(key: K, from: isize, to: isize) -> (String) {
337        cmd("GETRANGE").arg(key).arg(from).arg(to)
338    }
339
340    /// Overwrite the part of the value stored in key at the specified offset.
341    /// [Redis Docs](https://redis.io/commands/SETRANGE)
342    fn setrange<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, offset: isize, value: V) -> (usize) {
343        cmd("SETRANGE").arg(key).arg(offset).arg(value)
344    }
345
346    /// Delete one or more keys.
347    /// Returns the number of keys deleted.
348    /// [Redis Docs](https://redis.io/commands/DEL)
349    fn del<K: ToRedisArgs>(key: K) -> (usize) {
350        cmd("DEL").arg(key)
351    }
352
353    /// Conditionally removes the specified key. A key is ignored if it does not exist.
354    /// IFEQ `match-value` - Delete the key only if its value is equal to `match-value`
355    /// IFNE `match-value` - Delete the key only if its value is not equal to `match-value`
356    /// IFDEQ `match-digest` - Delete the key only if the digest of its value is equal to `match-digest`
357    /// IFDNE `match-digest` - Delete the key only if the digest of its value is not equal to `match-digest`
358    /// [Redis Docs](https://redis.io/commands/DELEX)
359    fn del_ex<K: ToSingleRedisArg>(key: K, value_comparison: ValueComparison) -> (usize) {
360        cmd("DELEX").arg(key).arg(value_comparison)
361    }
362
363    /// Get the hex signature of the value stored in the specified key.
364    /// For the digest, Redis will use [XXH3](https://xxhash.com)
365    /// [Redis Docs](https://redis.io/commands/DIGEST)
366    fn digest<K: ToSingleRedisArg>(key: K) -> (Option<String>) {
367        cmd("DIGEST").arg(key)
368    }
369
370    /// Determine if a key exists.
371    /// [Redis Docs](https://redis.io/commands/EXISTS)
372    fn exists<K: ToRedisArgs>(key: K) -> (bool) {
373        cmd("EXISTS").arg(key)
374    }
375
376    /// Determine the type of key.
377    /// [Redis Docs](https://redis.io/commands/TYPE)
378    fn key_type<K: ToSingleRedisArg>(key: K) -> (crate::types::ValueType) {
379        cmd("TYPE").arg(key)
380    }
381
382    /// Set a key's time to live in seconds.
383    /// Returns whether expiration was set.
384    /// [Redis Docs](https://redis.io/commands/EXPIRE)
385    fn expire<K: ToSingleRedisArg>(key: K, seconds: i64) -> (bool) {
386        cmd("EXPIRE").arg(key).arg(seconds)
387    }
388
389    /// Set the expiration for a key as a UNIX timestamp.
390    /// Returns whether expiration was set.
391    /// [Redis Docs](https://redis.io/commands/EXPIREAT)
392    fn expire_at<K: ToSingleRedisArg>(key: K, ts: i64) -> (bool) {
393        cmd("EXPIREAT").arg(key).arg(ts)
394    }
395
396    /// Set a key's time to live in milliseconds.
397    /// Returns whether expiration was set.
398    /// [Redis Docs](https://redis.io/commands/PEXPIRE)
399    fn pexpire<K: ToSingleRedisArg>(key: K, ms: i64) -> (bool) {
400        cmd("PEXPIRE").arg(key).arg(ms)
401    }
402
403    /// Set the expiration for a key as a UNIX timestamp in milliseconds.
404    /// Returns whether expiration was set.
405    /// [Redis Docs](https://redis.io/commands/PEXPIREAT)
406    fn pexpire_at<K: ToSingleRedisArg>(key: K, ts: i64) -> (bool) {
407        cmd("PEXPIREAT").arg(key).arg(ts)
408    }
409
410    /// Get the absolute Unix expiration timestamp in seconds.
411    /// Returns `ExistsButNotRelevant` if key exists but has no expiration time.
412    /// [Redis Docs](https://redis.io/commands/EXPIRETIME)
413    fn expire_time<K: ToSingleRedisArg>(key: K) -> (IntegerReplyOrNoOp) {
414        cmd("EXPIRETIME").arg(key)
415    }
416
417    /// Get the absolute Unix expiration timestamp in milliseconds.
418    /// Returns `ExistsButNotRelevant` if key exists but has no expiration time.
419    /// [Redis Docs](https://redis.io/commands/PEXPIRETIME)
420    fn pexpire_time<K: ToSingleRedisArg>(key: K) -> (IntegerReplyOrNoOp) {
421        cmd("PEXPIRETIME").arg(key)
422    }
423
424    /// Remove the expiration from a key.
425    /// Returns whether a timeout was removed.
426    /// [Redis Docs](https://redis.io/commands/PERSIST)
427    fn persist<K: ToSingleRedisArg>(key: K) -> (bool) {
428        cmd("PERSIST").arg(key)
429    }
430
431    /// Get the time to live for a key in seconds.
432    /// Returns `ExistsButNotRelevant` if key exists but has no expiration time.
433    /// [Redis Docs](https://redis.io/commands/TTL)
434    fn ttl<K: ToSingleRedisArg>(key: K) -> (IntegerReplyOrNoOp) {
435        cmd("TTL").arg(key)
436    }
437
438    /// Get the time to live for a key in milliseconds.
439    /// Returns `ExistsButNotRelevant` if key exists but has no expiration time.
440    /// [Redis Docs](https://redis.io/commands/PTTL)
441    fn pttl<K: ToSingleRedisArg>(key: K) -> (IntegerReplyOrNoOp) {
442        cmd("PTTL").arg(key)
443    }
444
445    /// Get the value of a key and set expiration
446    /// [Redis Docs](https://redis.io/commands/GETEX)
447    fn get_ex<K: ToSingleRedisArg>(key: K, expire_at: Expiry) -> (Option<String>) {
448        cmd("GETEX").arg(key).arg(expire_at)
449    }
450
451    /// Get the value of a key and delete it
452    /// [Redis Docs](https://redis.io/commands/GETDEL)
453    fn get_del<K: ToSingleRedisArg>(key: K) -> (Option<String>) {
454        cmd("GETDEL").arg(key)
455    }
456
457    /// Copy the value from one key to another, returning whether the copy was successful.
458    /// [Redis Docs](https://redis.io/commands/COPY)
459    fn copy<KSrc: ToSingleRedisArg, KDst: ToSingleRedisArg, Db: ToString>(
460        source: KSrc,
461        destination: KDst,
462        options: CopyOptions<Db>
463    ) -> (bool) {
464        cmd("COPY").arg(source).arg(destination).arg(options)
465    }
466
467    /// Rename a key.
468    /// Errors if key does not exist.
469    /// [Redis Docs](https://redis.io/commands/RENAME)
470    fn rename<K: ToSingleRedisArg, N: ToSingleRedisArg>(key: K, new_key: N) -> (()) {
471        cmd("RENAME").arg(key).arg(new_key)
472    }
473
474    /// Rename a key, only if the new key does not exist.
475    /// Errors if key does not exist.
476    /// Returns whether the key was renamed, or false if the new key already exists.
477    /// [Redis Docs](https://redis.io/commands/RENAMENX)
478    fn rename_nx<K: ToSingleRedisArg, N: ToSingleRedisArg>(key: K, new_key: N) -> (bool) {
479        cmd("RENAMENX").arg(key).arg(new_key)
480    }
481
482    /// Unlink one or more keys. This is a non-blocking version of `DEL`.
483    /// Returns number of keys unlinked.
484    /// [Redis Docs](https://redis.io/commands/UNLINK)
485    fn unlink<K: ToRedisArgs>(key: K) -> (usize) {
486        cmd("UNLINK").arg(key)
487    }
488
489    // common string operations
490
491    /// Append a value to a key.
492    /// Returns length of string after operation.
493    /// [Redis Docs](https://redis.io/commands/APPEND)
494    fn append<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V) -> (usize) {
495        cmd("APPEND").arg(key).arg(value)
496    }
497
498    /// Increment the numeric value of a key by the given amount.  This
499    /// issues a `INCRBY` or `INCRBYFLOAT` depending on the type.
500    /// If the key does not exist, it is set to 0 before performing the operation.
501    fn incr<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, delta: V) -> (isize) {
502        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
503            "INCRBYFLOAT"
504        } else {
505            "INCRBY"
506        }).arg(key).arg(delta)
507    }
508
509    /// Decrement the numeric value of a key by the given amount.
510    /// If the key does not exist, it is set to 0 before performing the operation.
511    /// [Redis Docs](https://redis.io/commands/DECRBY)
512    fn decr<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, delta: V) -> (isize) {
513        cmd("DECRBY").arg(key).arg(delta)
514    }
515
516    /// Sets or clears the bit at offset in the string value stored at key.
517    /// Returns the original bit value stored at offset.
518    /// [Redis Docs](https://redis.io/commands/SETBIT)
519    fn setbit<K: ToSingleRedisArg>(key: K, offset: usize, value: bool) -> (bool) {
520        cmd("SETBIT").arg(key).arg(offset).arg(i32::from(value))
521    }
522
523    /// Returns the bit value at offset in the string value stored at key.
524    /// [Redis Docs](https://redis.io/commands/GETBIT)
525    fn getbit<K: ToSingleRedisArg>(key: K, offset: usize) -> (bool) {
526        cmd("GETBIT").arg(key).arg(offset)
527    }
528
529    /// Count set bits in a string.
530    /// Returns 0 if key does not exist.
531    /// [Redis Docs](https://redis.io/commands/BITCOUNT)
532    fn bitcount<K: ToSingleRedisArg>(key: K) -> (usize) {
533        cmd("BITCOUNT").arg(key)
534    }
535
536    /// Count set bits in a string in a range.
537    /// Returns 0 if key does not exist.
538    /// [Redis Docs](https://redis.io/commands/BITCOUNT)
539    fn bitcount_range<K: ToSingleRedisArg>(key: K, start: usize, end: usize) -> (usize) {
540        cmd("BITCOUNT").arg(key).arg(start).arg(end)
541    }
542
543    /// Perform a bitwise AND between multiple keys (containing string values)
544    /// and store the result in the destination key.
545    /// Returns size of destination string after operation.
546    /// [Redis Docs](https://redis.io/commands/BITOP)
547    fn bit_and<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
548        cmd("BITOP").arg("AND").arg(dstkey).arg(srckeys)
549    }
550
551    /// Perform a bitwise OR between multiple keys (containing string values)
552    /// and store the result in the destination key.
553    /// Returns size of destination string after operation.
554    /// [Redis Docs](https://redis.io/commands/BITOP)
555    fn bit_or<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
556        cmd("BITOP").arg("OR").arg(dstkey).arg(srckeys)
557    }
558
559    /// Perform a bitwise XOR between multiple keys (containing string values)
560    /// and store the result in the destination key.
561    /// Returns size of destination string after operation.
562    /// [Redis Docs](https://redis.io/commands/BITOP)
563    fn bit_xor<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
564        cmd("BITOP").arg("XOR").arg(dstkey).arg(srckeys)
565    }
566
567    /// Perform a bitwise NOT of the key (containing string values)
568    /// and store the result in the destination key.
569    /// Returns size of destination string after operation.
570    /// [Redis Docs](https://redis.io/commands/BITOP)
571    fn bit_not<D: ToSingleRedisArg, S: ToSingleRedisArg>(dstkey: D, srckey: S) -> (usize) {
572        cmd("BITOP").arg("NOT").arg(dstkey).arg(srckey)
573    }
574
575    /// DIFF(X, Y1, Y2, …) \
576    /// Perform a **set difference** to extract the members of X that are not members of any of Y1, Y2,…. \
577    /// Logical representation: X  ∧ ¬(Y1 ∨ Y2 ∨ …) \
578    /// [Redis Docs](https://redis.io/commands/BITOP)
579    fn bit_diff<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
580        cmd("BITOP").arg("DIFF").arg(dstkey).arg(srckeys)
581    }
582
583    /// DIFF1(X, Y1, Y2, …) (Relative complement difference) \
584    /// Perform a **relative complement set difference** to extract the members of one or more of Y1, Y2,… that are not members of X. \
585    /// Logical representation: ¬X  ∧ (Y1 ∨ Y2 ∨ …) \
586    /// [Redis Docs](https://redis.io/commands/BITOP)
587    fn bit_diff1<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
588        cmd("BITOP").arg("DIFF1").arg(dstkey).arg(srckeys)
589    }
590
591    /// ANDOR(X, Y1, Y2, …) \
592    /// Perform an **"intersection of union(s)"** operation to extract the members of X that are also members of one or more of Y1, Y2,…. \
593    /// Logical representation: X ∧ (Y1 ∨ Y2 ∨ …) \
594    /// [Redis Docs](https://redis.io/commands/BITOP)
595    fn bit_and_or<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
596        cmd("BITOP").arg("ANDOR").arg(dstkey).arg(srckeys)
597    }
598
599    /// ONE(X, Y1, Y2, …) \
600    /// Perform an **"exclusive membership"** operation to extract the members of exactly **one** of X, Y1, Y2, …. \
601    /// Logical representation: (X ∨ Y1 ∨ Y2 ∨ …) ∧ ¬((X ∧ Y1) ∨ (X ∧ Y2) ∨ (Y1 ∧ Y2) ∨ (Y1 ∧ Y3) ∨ …) \
602    /// [Redis Docs](https://redis.io/commands/BITOP)
603    fn bit_one<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (usize) {
604        cmd("BITOP").arg("ONE").arg(dstkey).arg(srckeys)
605    }
606
607    /// Get the length of the value stored in a key.
608    /// 0 if key does not exist.
609    /// [Redis Docs](https://redis.io/commands/STRLEN)
610    fn strlen<K: ToSingleRedisArg>(key: K) -> (usize) {
611        cmd("STRLEN").arg(key)
612    }
613
614    // hash operations
615
616    /// Gets a single (or multiple) fields from a hash.
617    fn hget<K: ToSingleRedisArg, F: ToSingleRedisArg>(key: K, field: F) -> (Option<String>) {
618        cmd("HGET").arg(key).arg(field)
619    }
620
621    /// Gets multiple fields from a hash.
622    /// [Redis Docs](https://redis.io/commands/HMGET)
623    fn hmget<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<String>) {
624        cmd("HMGET").arg(key).arg(fields)
625    }
626
627    /// Get the value of one or more fields of a given hash key, and optionally set their expiration
628    /// [Redis Docs](https://redis.io/commands/HGETEX)
629    fn hget_ex<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F, expire_at: Expiry) -> (Vec<String>) {
630        cmd("HGETEX").arg(key).arg(expire_at).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
631    }
632
633    /// Deletes a single (or multiple) fields from a hash.
634    /// Returns number of fields deleted.
635    /// [Redis Docs](https://redis.io/commands/HDEL)
636    fn hdel<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, field: F) -> (usize) {
637        cmd("HDEL").arg(key).arg(field)
638    }
639
640    /// Get and delete the value of one or more fields of a given hash key
641    /// [Redis Docs](https://redis.io/commands/HGETDEL)
642    fn hget_del<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<Option<String>>) {
643        cmd("HGETDEL").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
644    }
645
646    /// Sets a single field in a hash.
647    /// Returns number of fields added.
648    /// [Redis Docs](https://redis.io/commands/HSET)
649    fn hset<K: ToSingleRedisArg, F: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, field: F, value: V) -> (usize) {
650        cmd("HSET").arg(key).arg(field).arg(value)
651    }
652
653    /// Set the value of one or more fields of a given hash key, and optionally set their expiration
654    /// [Redis Docs](https://redis.io/commands/HSETEX)
655    fn hset_ex<K: ToSingleRedisArg, F: ToRedisArgs, V: ToRedisArgs>(key: K, hash_field_expiration_options: &'a HashFieldExpirationOptions, fields_values: &'a [(F, V)]) -> (bool) {
656        cmd("HSETEX").arg(key).arg(hash_field_expiration_options).arg("FIELDS").arg(fields_values.len()).arg(fields_values)
657    }
658
659    /// Sets a single field in a hash if it does not exist.
660    /// Returns whether the field was added.
661    /// [Redis Docs](https://redis.io/commands/HSETNX)
662    fn hset_nx<K: ToSingleRedisArg, F: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, field: F, value: V) -> (bool) {
663        cmd("HSETNX").arg(key).arg(field).arg(value)
664    }
665
666    /// Sets multiple fields in a hash.
667    /// [Redis Docs](https://redis.io/commands/HMSET)
668    fn hset_multiple<K: ToSingleRedisArg, F: ToRedisArgs, V: ToRedisArgs>(key: K, items: &'a [(F, V)]) -> (()) {
669        cmd("HMSET").arg(key).arg(items)
670    }
671
672    /// Increments a value.
673    /// Returns the new value of the field after incrementation.
674    fn hincr<K: ToSingleRedisArg, F: ToSingleRedisArg, D: ToSingleRedisArg>(key: K, field: F, delta: D) -> (f64) {
675        cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
676            "HINCRBYFLOAT"
677        } else {
678            "HINCRBY"
679        }).arg(key).arg(field).arg(delta)
680    }
681
682    /// Checks if a field in a hash exists.
683    /// [Redis Docs](https://redis.io/commands/HEXISTS)
684    fn hexists<K: ToSingleRedisArg, F: ToSingleRedisArg>(key: K, field: F) -> (bool) {
685        cmd("HEXISTS").arg(key).arg(field)
686    }
687
688    /// Get one or more fields' TTL in seconds.
689    /// [Redis Docs](https://redis.io/commands/HTTL)
690    fn httl<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
691        cmd("HTTL").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
692    }
693
694    /// Get one or more fields' TTL in milliseconds.
695    /// [Redis Docs](https://redis.io/commands/HPTTL)
696    fn hpttl<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
697        cmd("HPTTL").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
698    }
699
700    /// Set one or more fields' time to live in seconds.
701    /// Returns an array where each element corresponds to the field at the same index in the fields argument.
702    /// Each element of the array is either:
703    /// 0 if the specified condition has not been met.
704    /// 1 if the expiration time was updated.
705    /// 2 if called with 0 seconds.
706    /// Errors if provided key exists but is not a hash.
707    /// [Redis Docs](https://redis.io/commands/HEXPIRE)
708    fn hexpire<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, seconds: i64, opt: ExpireOption, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
709       cmd("HEXPIRE").arg(key).arg(seconds).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
710    }
711
712
713    /// Set the expiration for one or more fields as a UNIX timestamp in seconds.
714    /// Returns an array where each element corresponds to the field at the same index in the fields argument.
715    /// Each element of the array is either:
716    /// 0 if the specified condition has not been met.
717    /// 1 if the expiration time was updated.
718    /// 2 if called with a time in the past.
719    /// Errors if provided key exists but is not a hash.
720    /// [Redis Docs](https://redis.io/commands/HEXPIREAT)
721    fn hexpire_at<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, ts: i64, opt: ExpireOption, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
722        cmd("HEXPIREAT").arg(key).arg(ts).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
723    }
724
725    /// Returns the absolute Unix expiration timestamp in seconds.
726    /// [Redis Docs](https://redis.io/commands/HEXPIRETIME)
727    fn hexpire_time<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
728        cmd("HEXPIRETIME").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
729    }
730
731    /// Remove the expiration from a key.
732    /// Returns 1 if the expiration was removed.
733    /// [Redis Docs](https://redis.io/commands/HPERSIST)
734    fn hpersist<K: ToSingleRedisArg, F :ToRedisArgs>(key: K, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
735        cmd("HPERSIST").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
736    }
737
738    /// Set one or more fields' time to live in milliseconds.
739    /// Returns an array where each element corresponds to the field at the same index in the fields argument.
740    /// Each element of the array is either:
741    /// 0 if the specified condition has not been met.
742    /// 1 if the expiration time was updated.
743    /// 2 if called with 0 seconds.
744    /// Errors if provided key exists but is not a hash.
745    /// [Redis Docs](https://redis.io/commands/HPEXPIRE)
746    fn hpexpire<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, milliseconds: i64, opt: ExpireOption, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
747        cmd("HPEXPIRE").arg(key).arg(milliseconds).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
748    }
749
750    /// Set the expiration for one or more fields as a UNIX timestamp in milliseconds.
751    /// Returns an array where each element corresponds to the field at the same index in the fields argument.
752    /// Each element of the array is either:
753    /// 0 if the specified condition has not been met.
754    /// 1 if the expiration time was updated.
755    /// 2 if called with a time in the past.
756    /// Errors if provided key exists but is not a hash.
757    /// [Redis Docs](https://redis.io/commands/HPEXPIREAT)
758    fn hpexpire_at<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, ts: i64,  opt: ExpireOption, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
759        cmd("HPEXPIREAT").arg(key).arg(ts).arg(opt).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
760    }
761
762    /// Returns the absolute Unix expiration timestamp in seconds.
763    /// [Redis Docs](https://redis.io/commands/HPEXPIRETIME)
764    fn hpexpire_time<K: ToSingleRedisArg, F: ToRedisArgs>(key: K, fields: F) -> (Vec<IntegerReplyOrNoOp>) {
765        cmd("HPEXPIRETIME").arg(key).arg("FIELDS").arg(fields.num_of_args()).arg(fields)
766    }
767
768    /// Gets all the keys in a hash.
769    /// [Redis Docs](https://redis.io/commands/HKEYS)
770    fn hkeys<K: ToSingleRedisArg>(key: K) -> (Vec<String>) {
771        cmd("HKEYS").arg(key)
772    }
773
774    /// Gets all the values in a hash.
775    /// [Redis Docs](https://redis.io/commands/HVALS)
776    fn hvals<K: ToSingleRedisArg>(key: K) -> (Vec<String>) {
777        cmd("HVALS").arg(key)
778    }
779
780    /// Gets all the fields and values in a hash.
781    /// [Redis Docs](https://redis.io/commands/HGETALL)
782    fn hgetall<K: ToSingleRedisArg>(key: K) -> (std::collections::HashMap<String, String>) {
783        cmd("HGETALL").arg(key)
784    }
785
786    /// Gets the length of a hash.
787    /// Returns 0 if key does not exist.
788    /// [Redis Docs](https://redis.io/commands/HLEN)
789    fn hlen<K: ToSingleRedisArg>(key: K) -> (usize) {
790        cmd("HLEN").arg(key)
791    }
792
793    // list operations
794
795    /// Pop an element from a list, push it to another list
796    /// and return it; or block until one is available
797    /// [Redis Docs](https://redis.io/commands/BLMOVE)
798    fn blmove<S: ToSingleRedisArg, D: ToSingleRedisArg>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction, timeout: f64) -> (Option<String>) {
799        cmd("BLMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir).arg(timeout)
800    }
801
802    /// Pops `count` elements from the first non-empty list key from the list of
803    /// provided key names; or blocks until one is available.
804    /// [Redis Docs](https://redis.io/commands/BLMPOP)
805    fn blmpop<K: ToRedisArgs>(timeout: f64, numkeys: usize, key: K, dir: Direction, count: usize) -> (Option<[String; 2]>) {
806        cmd("BLMPOP").arg(timeout).arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
807    }
808
809    /// Remove and get the first element in a list, or block until one is available.
810    /// [Redis Docs](https://redis.io/commands/BLPOP)
811    fn blpop<K: ToRedisArgs>(key: K, timeout: f64) -> (Option<[String; 2]>) {
812        cmd("BLPOP").arg(key).arg(timeout)
813    }
814
815    /// Remove and get the last element in a list, or block until one is available.
816    /// [Redis Docs](https://redis.io/commands/BRPOP)
817    fn brpop<K: ToRedisArgs>(key: K, timeout: f64) -> (Option<[String; 2]>) {
818        cmd("BRPOP").arg(key).arg(timeout)
819    }
820
821    /// Pop a value from a list, push it to another list and return it;
822    /// or block until one is available.
823    /// [Redis Docs](https://redis.io/commands/BRPOPLPUSH)
824    fn brpoplpush<S: ToSingleRedisArg, D: ToSingleRedisArg>(srckey: S, dstkey: D, timeout: f64) -> (Option<String>) {
825        cmd("BRPOPLPUSH").arg(srckey).arg(dstkey).arg(timeout)
826    }
827
828    /// Get an element from a list by its index.
829    /// [Redis Docs](https://redis.io/commands/LINDEX)
830    fn lindex<K: ToSingleRedisArg>(key: K, index: isize) -> (Option<String>) {
831        cmd("LINDEX").arg(key).arg(index)
832    }
833
834    /// Insert an element before another element in a list.
835    /// [Redis Docs](https://redis.io/commands/LINSERT)
836    fn linsert_before<K: ToSingleRedisArg, P: ToSingleRedisArg, V: ToSingleRedisArg>(
837            key: K, pivot: P, value: V) -> (isize) {
838        cmd("LINSERT").arg(key).arg("BEFORE").arg(pivot).arg(value)
839    }
840
841    /// Insert an element after another element in a list.
842    /// [Redis Docs](https://redis.io/commands/LINSERT)
843    fn linsert_after<K: ToSingleRedisArg, P: ToSingleRedisArg, V: ToSingleRedisArg>(
844            key: K, pivot: P, value: V) -> (isize) {
845        cmd("LINSERT").arg(key).arg("AFTER").arg(pivot).arg(value)
846    }
847
848    /// Returns the length of the list stored at key.
849    /// [Redis Docs](https://redis.io/commands/LLEN)
850    fn llen<K: ToSingleRedisArg>(key: K) -> (usize) {
851        cmd("LLEN").arg(key)
852    }
853
854    /// Pop an element a list, push it to another list and return it
855    /// [Redis Docs](https://redis.io/commands/LMOVE)
856    fn lmove<S: ToSingleRedisArg, D: ToSingleRedisArg>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction) -> (String) {
857        cmd("LMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir)
858    }
859
860    /// Pops `count` elements from the first non-empty list key from the list of
861    /// provided key names.
862    /// [Redis Docs](https://redis.io/commands/LMPOP)
863    fn lmpop<K: ToRedisArgs>( numkeys: usize, key: K, dir: Direction, count: usize) -> (Option<(String, Vec<String>)>) {
864        cmd("LMPOP").arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
865    }
866
867    /// Removes and returns the up to `count` first elements of the list stored at key.
868    ///
869    /// If `count` is not specified, then defaults to first element.
870    /// [Redis Docs](https://redis.io/commands/LPOP)
871    fn lpop<K: ToSingleRedisArg>(key: K, count: Option<core::num::NonZeroUsize>) -> Generic {
872        cmd("LPOP").arg(key).arg(count)
873    }
874
875    /// Returns the index of the first matching value of the list stored at key.
876    /// [Redis Docs](https://redis.io/commands/LPOS)
877    fn lpos<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, value: V, options: LposOptions) -> Generic {
878        cmd("LPOS").arg(key).arg(value).arg(options)
879    }
880
881    /// Insert all the specified values at the head of the list stored at key.
882    /// [Redis Docs](https://redis.io/commands/LPUSH)
883    fn lpush<K: ToSingleRedisArg, V: ToRedisArgs>(key: K, value: V) -> (usize) {
884        cmd("LPUSH").arg(key).arg(value)
885    }
886
887    /// Inserts a value at the head of the list stored at key, only if key
888    /// already exists and holds a list.
889    /// [Redis Docs](https://redis.io/commands/LPUSHX)
890    fn lpush_exists<K: ToSingleRedisArg, V: ToRedisArgs>(key: K, value: V) -> (usize) {
891        cmd("LPUSHX").arg(key).arg(value)
892    }
893
894    /// Returns the specified elements of the list stored at key.
895    /// [Redis Docs](https://redis.io/commands/LRANGE)
896    fn lrange<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (Vec<String>) {
897        cmd("LRANGE").arg(key).arg(start).arg(stop)
898    }
899
900    /// Removes the first count occurrences of elements equal to value
901    /// from the list stored at key.
902    /// [Redis Docs](https://redis.io/commands/LREM)
903    fn lrem<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, count: isize, value: V) -> (usize) {
904        cmd("LREM").arg(key).arg(count).arg(value)
905    }
906
907    /// Trim an existing list so that it will contain only the specified
908    /// range of elements specified.
909    /// [Redis Docs](https://redis.io/commands/LTRIM)
910    fn ltrim<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (()) {
911        cmd("LTRIM").arg(key).arg(start).arg(stop)
912    }
913
914    /// Sets the list element at index to value
915    /// [Redis Docs](https://redis.io/commands/LSET)
916    fn lset<K: ToSingleRedisArg, V: ToSingleRedisArg>(key: K, index: isize, value: V) -> (()) {
917        cmd("LSET").arg(key).arg(index).arg(value)
918    }
919
920    /// Sends a ping to the server
921    /// [Redis Docs](https://redis.io/commands/PING)
922    fn ping<>() -> (String) {
923         &mut cmd("PING")
924    }
925
926    /// Sends a ping with a message to the server
927    /// [Redis Docs](https://redis.io/commands/PING)
928    fn ping_message<K: ToSingleRedisArg>(message: K) -> (String) {
929         cmd("PING").arg(message)
930    }
931
932    /// Removes and returns the up to `count` last elements of the list stored at key
933    ///
934    /// If `count` is not specified, then defaults to last element.
935    /// [Redis Docs](https://redis.io/commands/RPOP)
936    fn rpop<K: ToSingleRedisArg>(key: K, count: Option<core::num::NonZeroUsize>) -> Generic {
937        cmd("RPOP").arg(key).arg(count)
938    }
939
940    /// Pop a value from a list, push it to another list and return it.
941    /// [Redis Docs](https://redis.io/commands/RPOPLPUSH)
942    fn rpoplpush<K: ToSingleRedisArg, D: ToSingleRedisArg>(key: K, dstkey: D) -> (Option<String>) {
943        cmd("RPOPLPUSH").arg(key).arg(dstkey)
944    }
945
946    /// Insert all the specified values at the tail of the list stored at key.
947    /// [Redis Docs](https://redis.io/commands/RPUSH)
948    fn rpush<K: ToSingleRedisArg, V: ToRedisArgs>(key: K, value: V) -> (usize) {
949        cmd("RPUSH").arg(key).arg(value)
950    }
951
952    /// Inserts value at the tail of the list stored at key, only if key
953    /// already exists and holds a list.
954    /// [Redis Docs](https://redis.io/commands/RPUSHX)
955    fn rpush_exists<K: ToSingleRedisArg, V: ToRedisArgs>(key: K, value: V) -> (usize) {
956        cmd("RPUSHX").arg(key).arg(value)
957    }
958
959    // set commands
960
961    /// Add one or more members to a set.
962    /// [Redis Docs](https://redis.io/commands/SADD)
963    fn sadd<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, member: M) -> (usize) {
964        cmd("SADD").arg(key).arg(member)
965    }
966
967    /// Get the number of members in a set.
968    /// [Redis Docs](https://redis.io/commands/SCARD)
969    fn scard<K: ToSingleRedisArg>(key: K) -> (usize) {
970        cmd("SCARD").arg(key)
971    }
972
973    /// Subtract multiple sets.
974    /// [Redis Docs](https://redis.io/commands/SDIFF)
975    fn sdiff<K: ToRedisArgs>(keys: K) -> (HashSet<String>) {
976        cmd("SDIFF").arg(keys)
977    }
978
979    /// Subtract multiple sets and store the resulting set in a key.
980    /// [Redis Docs](https://redis.io/commands/SDIFFSTORE)
981    fn sdiffstore<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
982        cmd("SDIFFSTORE").arg(dstkey).arg(keys)
983    }
984
985    /// Intersect multiple sets.
986    /// [Redis Docs](https://redis.io/commands/SINTER)
987    fn sinter<K: ToRedisArgs>(keys: K) -> (HashSet<String>) {
988        cmd("SINTER").arg(keys)
989    }
990
991    /// Intersect multiple sets and store the resulting set in a key.
992    /// [Redis Docs](https://redis.io/commands/SINTERSTORE)
993    fn sinterstore<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
994        cmd("SINTERSTORE").arg(dstkey).arg(keys)
995    }
996
997    /// Determine if a given value is a member of a set.
998    /// [Redis Docs](https://redis.io/commands/SISMEMBER)
999    fn sismember<K: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M) -> (bool) {
1000        cmd("SISMEMBER").arg(key).arg(member)
1001    }
1002
1003    /// Determine if given values are members of a set.
1004    /// [Redis Docs](https://redis.io/commands/SMISMEMBER)
1005    fn smismember<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: M) -> (Vec<bool>) {
1006        cmd("SMISMEMBER").arg(key).arg(members)
1007    }
1008
1009    /// Get all the members in a set.
1010    /// [Redis Docs](https://redis.io/commands/SMEMBERS)
1011    fn smembers<K: ToSingleRedisArg>(key: K) -> (HashSet<String>) {
1012        cmd("SMEMBERS").arg(key)
1013    }
1014
1015    /// Move a member from one set to another.
1016    /// [Redis Docs](https://redis.io/commands/SMOVE)
1017    fn smove<S: ToSingleRedisArg, D: ToSingleRedisArg, M: ToSingleRedisArg>(srckey: S, dstkey: D, member: M) -> (bool) {
1018        cmd("SMOVE").arg(srckey).arg(dstkey).arg(member)
1019    }
1020
1021    /// Remove and return a random member from a set.
1022    /// [Redis Docs](https://redis.io/commands/SPOP)
1023    fn spop<K: ToSingleRedisArg>(key: K) -> Generic {
1024        cmd("SPOP").arg(key)
1025    }
1026
1027    /// Get one random member from a set.
1028    /// [Redis Docs](https://redis.io/commands/SRANDMEMBER)
1029    fn srandmember<K: ToSingleRedisArg>(key: K) -> (Option<String>) {
1030        cmd("SRANDMEMBER").arg(key)
1031    }
1032
1033    /// Get multiple random members from a set.
1034    /// [Redis Docs](https://redis.io/commands/SRANDMEMBER)
1035    fn srandmember_multiple<K: ToSingleRedisArg>(key: K, count: isize) -> (Vec<String>) {
1036        cmd("SRANDMEMBER").arg(key).arg(count)
1037    }
1038
1039    /// Remove one or more members from a set.
1040    /// [Redis Docs](https://redis.io/commands/SREM)
1041    fn srem<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, member: M) -> (usize) {
1042        cmd("SREM").arg(key).arg(member)
1043    }
1044
1045    /// Add multiple sets.
1046    /// [Redis Docs](https://redis.io/commands/SUNION)
1047    fn sunion<K: ToRedisArgs>(keys: K) -> (HashSet<String>) {
1048        cmd("SUNION").arg(keys)
1049    }
1050
1051    /// Add multiple sets and store the resulting set in a key.
1052    /// [Redis Docs](https://redis.io/commands/SUNIONSTORE)
1053    fn sunionstore<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1054        cmd("SUNIONSTORE").arg(dstkey).arg(keys)
1055    }
1056
1057    // sorted set commands
1058
1059    /// Add one member to a sorted set, or update its score if it already exists.
1060    /// [Redis Docs](https://redis.io/commands/ZADD)
1061    fn zadd<K: ToSingleRedisArg, S: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M, score: S) -> usize{
1062        cmd("ZADD").arg(key).arg(score).arg(member)
1063    }
1064
1065    /// Add multiple members to a sorted set, or update its score if it already exists.
1066    /// [Redis Docs](https://redis.io/commands/ZADD)
1067    fn zadd_multiple<K: ToSingleRedisArg, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)]) -> (usize) {
1068        cmd("ZADD").arg(key).arg(items)
1069    }
1070
1071     /// Add one member to a sorted set, or update its score if it already exists.
1072     /// [Redis Docs](https://redis.io/commands/ZADD)
1073    fn zadd_options<K: ToSingleRedisArg, S: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M, score: S, options:&'a SortedSetAddOptions) -> usize{
1074        cmd("ZADD").arg(key).arg(options).arg(score).arg(member)
1075    }
1076
1077    /// Add multiple members to a sorted set, or update its score if it already exists.
1078    /// [Redis Docs](https://redis.io/commands/ZADD)
1079    fn zadd_multiple_options<K: ToSingleRedisArg, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)], options:&'a SortedSetAddOptions) -> (usize) {
1080        cmd("ZADD").arg(key).arg(options).arg(items)
1081    }
1082
1083    /// Get the number of members in a sorted set.
1084    /// [Redis Docs](https://redis.io/commands/ZCARD)
1085    fn zcard<K: ToSingleRedisArg>(key: K) -> (usize) {
1086        cmd("ZCARD").arg(key)
1087    }
1088
1089    /// Count the members in a sorted set with scores within the given values.
1090    /// [Redis Docs](https://redis.io/commands/ZCOUNT)
1091    fn zcount<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (usize) {
1092        cmd("ZCOUNT").arg(key).arg(min).arg(max)
1093    }
1094
1095    /// Increments the member in a sorted set at key by delta.
1096    /// If the member does not exist, it is added with delta as its score.
1097    /// [Redis Docs](https://redis.io/commands/ZINCRBY)
1098    fn zincr<K: ToSingleRedisArg, M: ToSingleRedisArg, D: ToSingleRedisArg>(key: K, member: M, delta: D) -> (f64) {
1099        cmd("ZINCRBY").arg(key).arg(delta).arg(member)
1100    }
1101
1102    /// Intersect multiple sorted sets and store the resulting sorted set in
1103    /// a new key using SUM as aggregation function.
1104    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1105    fn zinterstore<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1106        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys)
1107    }
1108
1109    /// Intersect multiple sorted sets and store the resulting sorted set in
1110    /// a new key using MIN as aggregation function.
1111    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1112    fn zinterstore_min<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1113        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN")
1114    }
1115
1116    /// Intersect multiple sorted sets and store the resulting sorted set in
1117    /// a new key using MAX as aggregation function.
1118    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1119    fn zinterstore_max<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1120        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX")
1121    }
1122
1123    /// [`Commands::zinterstore`], but with the ability to specify a
1124    /// multiplication factor for each sorted set by pairing one with each key
1125    /// in a tuple.
1126    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1127    fn zinterstore_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1128        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1129        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("WEIGHTS").arg(weights)
1130    }
1131
1132    /// [`Commands::zinterstore_min`], but with the ability to specify a
1133    /// multiplication factor for each sorted set by pairing one with each key
1134    /// in a tuple.
1135    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1136    fn zinterstore_min_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1137        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1138        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN").arg("WEIGHTS").arg(weights)
1139    }
1140
1141    /// [`Commands::zinterstore_max`], but with the ability to specify a
1142    /// multiplication factor for each sorted set by pairing one with each key
1143    /// in a tuple.
1144    /// [Redis Docs](https://redis.io/commands/ZINTERSTORE)
1145    fn zinterstore_max_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1146        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1147        cmd("ZINTERSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX").arg("WEIGHTS").arg(weights)
1148    }
1149
1150    /// Count the number of members in a sorted set between a given lexicographical range.
1151    /// [Redis Docs](https://redis.io/commands/ZLEXCOUNT)
1152    fn zlexcount<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (usize) {
1153        cmd("ZLEXCOUNT").arg(key).arg(min).arg(max)
1154    }
1155
1156    /// Removes and returns the member with the highest score in a sorted set.
1157    /// Blocks until a member is available otherwise.
1158    /// [Redis Docs](https://redis.io/commands/BZPOPMAX)
1159    fn bzpopmax<K: ToRedisArgs>(key: K, timeout: f64) -> (Option<(String, String, f64)>) {
1160        cmd("BZPOPMAX").arg(key).arg(timeout)
1161    }
1162
1163    /// Removes and returns up to count members with the highest scores in a sorted set
1164    /// [Redis Docs](https://redis.io/commands/ZPOPMAX)
1165    fn zpopmax<K: ToSingleRedisArg>(key: K, count: isize) -> (Vec<String>) {
1166        cmd("ZPOPMAX").arg(key).arg(count)
1167    }
1168
1169    /// Removes and returns the member with the lowest score in a sorted set.
1170    /// Blocks until a member is available otherwise.
1171    /// [Redis Docs](https://redis.io/commands/BZPOPMIN)
1172    fn bzpopmin<K: ToRedisArgs>(key: K, timeout: f64) -> (Option<(String, String, f64)>) {
1173        cmd("BZPOPMIN").arg(key).arg(timeout)
1174    }
1175
1176    /// Removes and returns up to count members with the lowest scores in a sorted set
1177    /// [Redis Docs](https://redis.io/commands/ZPOPMIN)
1178    fn zpopmin<K: ToSingleRedisArg>(key: K, count: isize) -> (Vec<String>) {
1179        cmd("ZPOPMIN").arg(key).arg(count)
1180    }
1181
1182    /// Removes and returns up to count members with the highest scores,
1183    /// from the first non-empty sorted set in the provided list of key names.
1184    /// Blocks until a member is available otherwise.
1185    /// [Redis Docs](https://redis.io/commands/BZMPOP)
1186    fn bzmpop_max<K: ToRedisArgs>(timeout: f64, keys: K, count: isize) -> (Option<(String, Vec<(String, f64)>)>) {
1187        cmd("BZMPOP").arg(timeout).arg(keys.num_of_args()).arg(keys).arg("MAX").arg("COUNT").arg(count)
1188    }
1189
1190    /// Removes and returns up to count members with the highest scores,
1191    /// from the first non-empty sorted set in the provided list of key names.
1192    /// [Redis Docs](https://redis.io/commands/ZMPOP)
1193    fn zmpop_max<K: ToRedisArgs>(keys: K, count: isize) -> (Option<(String, Vec<(String, f64)>)>) {
1194        cmd("ZMPOP").arg(keys.num_of_args()).arg(keys).arg("MAX").arg("COUNT").arg(count)
1195    }
1196
1197    /// Removes and returns up to count members with the lowest scores,
1198    /// from the first non-empty sorted set in the provided list of key names.
1199    /// Blocks until a member is available otherwise.
1200    /// [Redis Docs](https://redis.io/commands/BZMPOP)
1201    fn bzmpop_min<K: ToRedisArgs>(timeout: f64, keys: K, count: isize) -> (Option<(String, Vec<(String, f64)>)>) {
1202        cmd("BZMPOP").arg(timeout).arg(keys.num_of_args()).arg(keys).arg("MIN").arg("COUNT").arg(count)
1203    }
1204
1205    /// Removes and returns up to count members with the lowest scores,
1206    /// from the first non-empty sorted set in the provided list of key names.
1207    /// [Redis Docs](https://redis.io/commands/ZMPOP)
1208    fn zmpop_min<K: ToRedisArgs>(keys: K, count: isize) -> (Option<(String, Vec<(String, f64)>)>) {
1209        cmd("ZMPOP").arg(keys.num_of_args()).arg(keys).arg("MIN").arg("COUNT").arg(count)
1210    }
1211
1212    /// Return up to count random members in a sorted set (or 1 if `count == None`)
1213    /// [Redis Docs](https://redis.io/commands/ZRANDMEMBER)
1214    fn zrandmember<K: ToSingleRedisArg>(key: K, count: Option<isize>) -> Generic {
1215        cmd("ZRANDMEMBER").arg(key).arg(count)
1216    }
1217
1218    /// Return up to count random members in a sorted set with scores
1219    /// [Redis Docs](https://redis.io/commands/ZRANDMEMBER)
1220    fn zrandmember_withscores<K: ToSingleRedisArg>(key: K, count: isize) -> Generic {
1221        cmd("ZRANDMEMBER").arg(key).arg(count).arg("WITHSCORES")
1222    }
1223
1224    /// Return a range of members in a sorted set, by index
1225    /// [Redis Docs](https://redis.io/commands/ZRANGE)
1226    fn zrange<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (Vec<String>) {
1227        cmd("ZRANGE").arg(key).arg(start).arg(stop)
1228    }
1229
1230    /// Return a range of members in a sorted set, by index with scores.
1231    /// [Redis Docs](https://redis.io/commands/ZRANGE)
1232    fn zrange_withscores<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (Vec<(String, f64)>) {
1233        cmd("ZRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
1234    }
1235
1236    /// Return a range of members in a sorted set, by lexicographical range.
1237    /// [Redis Docs](https://redis.io/commands/ZRANGEBYLEX)
1238    fn zrangebylex<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (Vec<String>) {
1239        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max)
1240    }
1241
1242    /// Return a range of members in a sorted set, by lexicographical
1243    /// range with offset and limit.
1244    /// [Redis Docs](https://redis.io/commands/ZRANGEBYLEX)
1245    fn zrangebylex_limit<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(
1246            key: K, min: M, max: MM, offset: isize, count: isize) -> (Vec<String>) {
1247        cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
1248    }
1249
1250    /// Return a range of members in a sorted set, by lexicographical range.
1251    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYLEX)
1252    fn zrevrangebylex<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, max: MM, min: M) -> (Vec<String>) {
1253        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min)
1254    }
1255
1256    /// Return a range of members in a sorted set, by lexicographical
1257    /// range with offset and limit.
1258    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYLEX)
1259    fn zrevrangebylex_limit<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>(
1260            key: K, max: MM, min: M, offset: isize, count: isize) -> (Vec<String>) {
1261        cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
1262    }
1263
1264    /// Return a range of members in a sorted set, by score.
1265    /// [Redis Docs](https://redis.io/commands/ZRANGEBYSCORE)
1266    fn zrangebyscore<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (Vec<String>) {
1267        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max)
1268    }
1269
1270    /// Return a range of members in a sorted set, by score with scores.
1271    /// [Redis Docs](https://redis.io/commands/ZRANGEBYSCORE)
1272    fn zrangebyscore_withscores<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (Vec<(String, usize)>) {
1273        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
1274    }
1275
1276    /// Return a range of members in a sorted set, by score with limit.
1277    /// [Redis Docs](https://redis.io/commands/ZRANGEBYSCORE)
1278    fn zrangebyscore_limit<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>
1279            (key: K, min: M, max: MM, offset: isize, count: isize) -> (Vec<String>) {
1280        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
1281    }
1282
1283    /// Return a range of members in a sorted set, by score with limit with scores.
1284    /// [Redis Docs](https://redis.io/commands/ZRANGEBYSCORE)
1285    fn zrangebyscore_limit_withscores<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>
1286            (key: K, min: M, max: MM, offset: isize, count: isize) -> (Vec<(String, usize)>) {
1287        cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
1288            .arg("LIMIT").arg(offset).arg(count)
1289    }
1290
1291    /// Determine the index of a member in a sorted set.
1292    /// [Redis Docs](https://redis.io/commands/ZRANK)
1293    fn zrank<K: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M) -> (Option<usize>) {
1294        cmd("ZRANK").arg(key).arg(member)
1295    }
1296
1297    /// Remove one or more members from a sorted set.
1298    /// [Redis Docs](https://redis.io/commands/ZREM)
1299    fn zrem<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: M) -> (usize) {
1300        cmd("ZREM").arg(key).arg(members)
1301    }
1302
1303    /// Remove all members in a sorted set between the given lexicographical range.
1304    /// [Redis Docs](https://redis.io/commands/ZREMRANGEBYLEX)
1305    fn zrembylex<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (usize) {
1306        cmd("ZREMRANGEBYLEX").arg(key).arg(min).arg(max)
1307    }
1308
1309    /// Remove all members in a sorted set within the given indexes.
1310    /// [Redis Docs](https://redis.io/commands/ZREMRANGEBYRANK)
1311    fn zremrangebyrank<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (usize) {
1312        cmd("ZREMRANGEBYRANK").arg(key).arg(start).arg(stop)
1313    }
1314
1315    /// Remove all members in a sorted set within the given scores.
1316    /// [Redis Docs](https://redis.io/commands/ZREMRANGEBYSCORE)
1317    fn zrembyscore<K: ToSingleRedisArg, M: ToSingleRedisArg, MM: ToSingleRedisArg>(key: K, min: M, max: MM) -> (usize) {
1318        cmd("ZREMRANGEBYSCORE").arg(key).arg(min).arg(max)
1319    }
1320
1321    /// Return a range of members in a sorted set, by index,
1322    /// ordered from high to low.
1323    /// [Redis Docs](https://redis.io/commands/ZREVRANGE)
1324    fn zrevrange<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (Vec<String>) {
1325        cmd("ZREVRANGE").arg(key).arg(start).arg(stop)
1326    }
1327
1328    /// Return a range of members in a sorted set, by index, with scores
1329    /// ordered from high to low.
1330    /// [Redis Docs](https://redis.io/commands/ZREVRANGE)
1331    fn zrevrange_withscores<K: ToSingleRedisArg>(key: K, start: isize, stop: isize) -> (Vec<String>) {
1332        cmd("ZREVRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
1333    }
1334
1335    /// Return a range of members in a sorted set, by score.
1336    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYSCORE)
1337    fn zrevrangebyscore<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, max: MM, min: M) -> (Vec<String>) {
1338        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min)
1339    }
1340
1341    /// Return a range of members in a sorted set, by score with scores.
1342    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYSCORE)
1343    fn zrevrangebyscore_withscores<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, max: MM, min: M) -> (Vec<String>) {
1344        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
1345    }
1346
1347    /// Return a range of members in a sorted set, by score with limit.
1348    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYSCORE)
1349    fn zrevrangebyscore_limit<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>
1350            (key: K, max: MM, min: M, offset: isize, count: isize) -> (Vec<String>) {
1351        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
1352    }
1353
1354    /// Return a range of members in a sorted set, by score with limit with scores.
1355    /// [Redis Docs](https://redis.io/commands/ZREVRANGEBYSCORE)
1356    fn zrevrangebyscore_limit_withscores<K: ToSingleRedisArg, MM: ToSingleRedisArg, M: ToSingleRedisArg>
1357            (key: K, max: MM, min: M, offset: isize, count: isize) -> (Vec<String>) {
1358        cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
1359            .arg("LIMIT").arg(offset).arg(count)
1360    }
1361
1362    /// Determine the index of a member in a sorted set, with scores ordered from high to low.
1363    /// [Redis Docs](https://redis.io/commands/ZREVRANK)
1364    fn zrevrank<K: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M) -> (Option<usize>) {
1365        cmd("ZREVRANK").arg(key).arg(member)
1366    }
1367
1368    /// Get the score associated with the given member in a sorted set.
1369    /// [Redis Docs](https://redis.io/commands/ZSCORE)
1370    fn zscore<K: ToSingleRedisArg, M: ToSingleRedisArg>(key: K, member: M) -> (Option<f64>) {
1371        cmd("ZSCORE").arg(key).arg(member)
1372    }
1373
1374    /// Get the scores associated with multiple members in a sorted set.
1375    /// [Redis Docs](https://redis.io/commands/ZMSCORE)
1376    fn zscore_multiple<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: &'a [M]) -> (Option<Vec<f64>>) {
1377        cmd("ZMSCORE").arg(key).arg(members)
1378    }
1379
1380    /// Unions multiple sorted sets and store the resulting sorted set in
1381    /// a new key using SUM as aggregation function.
1382    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1383    fn zunionstore<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1384        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys)
1385    }
1386
1387    /// Unions multiple sorted sets and store the resulting sorted set in
1388    /// a new key using MIN as aggregation function.
1389    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1390    fn zunionstore_min<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1391        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN")
1392    }
1393
1394    /// Unions multiple sorted sets and store the resulting sorted set in
1395    /// a new key using MAX as aggregation function.
1396    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1397    fn zunionstore_max<D: ToSingleRedisArg, K: ToRedisArgs>(dstkey: D, keys: K) -> (usize) {
1398        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX")
1399    }
1400
1401    /// [`Commands::zunionstore`], but with the ability to specify a
1402    /// multiplication factor for each sorted set by pairing one with each key
1403    /// in a tuple.
1404    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1405    fn zunionstore_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1406        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1407        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("WEIGHTS").arg(weights)
1408    }
1409
1410    /// [`Commands::zunionstore_min`], but with the ability to specify a
1411    /// multiplication factor for each sorted set by pairing one with each key
1412    /// in a tuple.
1413    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1414    fn zunionstore_min_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1415        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1416        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MIN").arg("WEIGHTS").arg(weights)
1417    }
1418
1419    /// [`Commands::zunionstore_max`], but with the ability to specify a
1420    /// multiplication factor for each sorted set by pairing one with each key
1421    /// in a tuple.
1422    /// [Redis Docs](https://redis.io/commands/ZUNIONSTORE)
1423    fn zunionstore_max_weights<D: ToSingleRedisArg, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]) -> (usize) {
1424        let (keys, weights): (Vec<&K>, Vec<&W>) = keys.iter().map(|(key, weight):&(K, W)| -> ((&K, &W)) {(key, weight)}).unzip();
1425        cmd("ZUNIONSTORE").arg(dstkey).arg(keys.num_of_args()).arg(keys).arg("AGGREGATE").arg("MAX").arg("WEIGHTS").arg(weights)
1426    }
1427
1428    // vector set commands
1429
1430    /// Add a new element into the vector set specified by key.
1431    /// [Redis Docs](https://redis.io/commands/VADD)
1432    #[cfg(feature = "vector-sets")]
1433    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1434    fn vadd<K: ToRedisArgs, E: ToRedisArgs>(key: K, input: vector_sets::VectorAddInput<'a>, element: E) -> (bool) {
1435        cmd("VADD").arg(key).arg(input).arg(element)
1436    }
1437
1438    /// Add a new element into the vector set specified by key with optional parameters for fine-tuning the insertion process.
1439    /// [Redis Docs](https://redis.io/commands/VADD)
1440    #[cfg(feature = "vector-sets")]
1441    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1442    fn vadd_options<K: ToRedisArgs, E: ToRedisArgs>(key: K, input: vector_sets::VectorAddInput<'a>, element: E, options: &'a vector_sets::VAddOptions) -> (bool) {
1443        cmd("VADD").arg(key).arg(options.reduction_dimension.map(|_| "REDUCE")).arg(options.reduction_dimension).arg(input).arg(element).arg(options)
1444    }
1445
1446    /// Get the number of members in a vector set.
1447    /// [Redis Docs](https://redis.io/commands/VCARD)
1448    #[cfg(feature = "vector-sets")]
1449    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1450    fn vcard<K: ToRedisArgs>(key: K) -> (usize) {
1451        cmd("VCARD").arg(key)
1452    }
1453
1454    /// Return the number of dimensions of the vectors in the specified vector set.
1455    /// [Redis Docs](https://redis.io/commands/VDIM)
1456    #[cfg(feature = "vector-sets")]
1457    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1458    fn vdim<K: ToRedisArgs>(key: K) -> (usize) {
1459        cmd("VDIM").arg(key)
1460    }
1461
1462    /// Return the approximate vector associated with a given element in the vector set.
1463    /// [Redis Docs](https://redis.io/commands/VEMB)
1464    #[cfg(feature = "vector-sets")]
1465    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1466    fn vemb<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> Generic {
1467        cmd("VEMB").arg(key).arg(element)
1468    }
1469
1470    /// Return the raw internal representation of the approximate vector associated with a given element in the vector set.
1471    /// Vector sets normalize and may quantize vectors on insertion.
1472    /// VEMB reverses this process to approximate the original vector by de-normalizing and de-quantizing it.
1473    /// [Redis Docs](https://redis.io/commands/VEMB)
1474    #[cfg(feature = "vector-sets")]
1475    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1476    fn vemb_options<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E, options: &'a vector_sets::VEmbOptions) -> Generic {
1477        cmd("VEMB").arg(key).arg(element).arg(options)
1478    }
1479
1480    /// Remove an element from a vector set.
1481    /// [Redis Docs](https://redis.io/commands/VREM)
1482    #[cfg(feature = "vector-sets")]
1483    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1484    fn vrem<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> (bool) {
1485        cmd("VREM").arg(key).arg(element)
1486    }
1487
1488    /// Associate a JSON object with an element in a vector set.
1489    /// Use this command to store attributes that can be used in filtered similarity searches with VSIM.
1490    /// [Redis Docs](https://redis.io/commands/VSETATTR)
1491    #[cfg(feature = "vector-sets")]
1492    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1493    fn vsetattr<K: ToRedisArgs, E: ToRedisArgs, J: Serialize>(key: K, element: E, json_object: &'a J) -> (bool) {
1494        let attributes_json = match serde_json::to_value(json_object) {
1495            Ok(serde_json::Value::String(s)) if s.is_empty() => "".to_string(),
1496            _ => serde_json::to_string(json_object).unwrap(),
1497        };
1498
1499        cmd("VSETATTR").arg(key).arg(element).arg(attributes_json)
1500    }
1501
1502    /// Delete the JSON attributes associated with an element in a vector set.
1503    /// This is an utility function that uses VSETATTR with an empty string.
1504    /// [Redis Docs](https://redis.io/commands/VSETATTR)
1505    #[cfg(feature = "vector-sets")]
1506    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1507    fn vdelattr<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> (bool) {
1508        cmd("VSETATTR").arg(key).arg(element).arg("")
1509    }
1510
1511    /// Return the JSON attributes associated with an element in a vector set.
1512    /// [Redis Docs](https://redis.io/commands/VGETATTR)
1513    #[cfg(feature = "vector-sets")]
1514    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1515    fn vgetattr<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> (Option<String>) {
1516        cmd("VGETATTR").arg(key).arg(element)
1517    }
1518
1519    /// Return metadata and internal details about a vector set, including
1520    /// size, dimensions, quantization type, and graph structure.
1521    /// [Redis Docs](https://redis.io/commands/VINFO)
1522    #[cfg(feature = "vector-sets")]
1523    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1524    fn vinfo<K: ToRedisArgs>(key: K) -> (Option<std::collections::HashMap<String, Value>>) {
1525        cmd("VINFO").arg(key)
1526    }
1527
1528    /// Return the neighbors of a specified element in a vector set.
1529    /// The command shows the connections for each layer of the HNSW graph.
1530    /// [Redis Docs](https://redis.io/commands/VLINKS)
1531    #[cfg(feature = "vector-sets")]
1532    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1533    fn vlinks<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> Generic {
1534        cmd("VLINKS").arg(key).arg(element)
1535    }
1536
1537    /// Return the neighbors of a specified element in a vector set.
1538    /// The command shows the connections for each layer of the HNSW graph
1539    /// and includes similarity scores for each neighbor.
1540    /// [Redis Docs](https://redis.io/commands/VLINKS)]
1541    #[cfg(feature = "vector-sets")]
1542    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1543    fn vlinks_with_scores<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) -> Generic {
1544        cmd("VLINKS").arg(key).arg(element).arg("WITHSCORES")
1545    }
1546
1547    /// Return one random elements from a vector set.
1548    /// [Redis Docs](https://redis.io/commands/VRANDMEMBER)
1549    #[cfg(feature = "vector-sets")]
1550    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1551    fn vrandmember<K: ToRedisArgs>(key: K) -> (Option<String>) {
1552        cmd("VRANDMEMBER").arg(key)
1553    }
1554
1555    /// Return multiple random elements from a vector set.
1556    /// [Redis Docs](https://redis.io/commands/VRANDMEMBER)
1557    #[cfg(feature = "vector-sets")]
1558    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1559    fn vrandmember_multiple<K: ToRedisArgs>(key: K, count: usize) -> (Vec<String>) {
1560        cmd("VRANDMEMBER").arg(key).arg(count)
1561    }
1562
1563    /// Perform vector similarity search.
1564    /// [Redis Docs](https://redis.io/commands/VSIM)
1565    #[cfg(feature = "vector-sets")]
1566    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1567    fn vsim<K: ToRedisArgs>(key: K, input: vector_sets::VectorSimilaritySearchInput<'a>) -> Generic {
1568        cmd("VSIM").arg(key).arg(input)
1569    }
1570
1571    /// Performs a vector similarity search with optional parameters for customization.
1572    /// [Redis Docs](https://redis.io/commands/VSIM)
1573    #[cfg(feature = "vector-sets")]
1574    #[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
1575    fn vsim_options<K: ToRedisArgs>(key: K, input: vector_sets::VectorSimilaritySearchInput<'a>, options: &'a vector_sets::VSimOptions) -> Generic {
1576        cmd("VSIM").arg(key).arg(input).arg(options)
1577    }
1578
1579    // hyperloglog commands
1580
1581    /// Adds the specified elements to the specified HyperLogLog.
1582    /// [Redis Docs](https://redis.io/commands/PFADD)
1583    fn pfadd<K: ToSingleRedisArg, E: ToRedisArgs>(key: K, element: E) -> (bool) {
1584        cmd("PFADD").arg(key).arg(element)
1585    }
1586
1587    /// Return the approximated cardinality of the set(s) observed by the
1588    /// HyperLogLog at key(s).
1589    /// [Redis Docs](https://redis.io/commands/PFCOUNT)
1590    fn pfcount<K: ToRedisArgs>(key: K) -> (usize) {
1591        cmd("PFCOUNT").arg(key)
1592    }
1593
1594    /// Merge N different HyperLogLogs into a single one.
1595    /// [Redis Docs](https://redis.io/commands/PFMERGE)
1596    fn pfmerge<D: ToSingleRedisArg, S: ToRedisArgs>(dstkey: D, srckeys: S) -> (()) {
1597        cmd("PFMERGE").arg(dstkey).arg(srckeys)
1598    }
1599
1600    /// Posts a message to the given channel.
1601    /// [Redis Docs](https://redis.io/commands/PUBLISH)
1602    fn publish<K: ToSingleRedisArg, E: ToSingleRedisArg>(channel: K, message: E) -> (usize) {
1603        cmd("PUBLISH").arg(channel).arg(message)
1604    }
1605
1606    /// Posts a message to the given sharded channel.
1607    /// [Redis Docs](https://redis.io/commands/SPUBLISH)
1608    fn spublish<K: ToSingleRedisArg, E: ToSingleRedisArg>(channel: K, message: E) -> (usize) {
1609        cmd("SPUBLISH").arg(channel).arg(message)
1610    }
1611
1612    // Object commands
1613
1614    /// Returns the encoding of a key.
1615    /// [Redis Docs](https://redis.io/commands/OBJECT)
1616    fn object_encoding<K: ToSingleRedisArg>(key: K) -> (Option<String>) {
1617        cmd("OBJECT").arg("ENCODING").arg(key)
1618    }
1619
1620    /// Returns the time in seconds since the last access of a key.
1621    /// [Redis Docs](https://redis.io/commands/OBJECT)
1622    fn object_idletime<K: ToSingleRedisArg>(key: K) -> (Option<usize>) {
1623        cmd("OBJECT").arg("IDLETIME").arg(key)
1624    }
1625
1626    /// Returns the logarithmic access frequency counter of a key.
1627    /// [Redis Docs](https://redis.io/commands/OBJECT)
1628    fn object_freq<K: ToSingleRedisArg>(key: K) -> (Option<usize>) {
1629        cmd("OBJECT").arg("FREQ").arg(key)
1630    }
1631
1632    /// Returns the reference count of a key.
1633    /// [Redis Docs](https://redis.io/commands/OBJECT)
1634    fn object_refcount<K: ToSingleRedisArg>(key: K) -> (Option<usize>) {
1635        cmd("OBJECT").arg("REFCOUNT").arg(key)
1636    }
1637
1638    /// Returns the name of the current connection as set by CLIENT SETNAME.
1639    /// [Redis Docs](https://redis.io/commands/CLIENT)
1640    fn client_getname<>() -> (Option<String>) {
1641        cmd("CLIENT").arg("GETNAME")
1642    }
1643
1644    /// Returns the ID of the current connection.
1645    /// [Redis Docs](https://redis.io/commands/CLIENT)
1646    fn client_id<>() -> (isize) {
1647        cmd("CLIENT").arg("ID")
1648    }
1649
1650    /// Command assigns a name to the current connection.
1651    /// [Redis Docs](https://redis.io/commands/CLIENT)
1652    fn client_setname<K: ToSingleRedisArg>(connection_name: K) -> (()) {
1653        cmd("CLIENT").arg("SETNAME").arg(connection_name)
1654    }
1655
1656    // ACL commands
1657
1658    /// When Redis is configured to use an ACL file (with the aclfile
1659    /// configuration option), this command will reload the ACLs from the file,
1660    /// replacing all the current ACL rules with the ones defined in the file.
1661    #[cfg(feature = "acl")]
1662    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1663    /// [Redis Docs](https://redis.io/commands/ACL)
1664    fn acl_load<>() -> () {
1665        cmd("ACL").arg("LOAD")
1666    }
1667
1668    /// When Redis is configured to use an ACL file (with the aclfile
1669    /// configuration option), this command will save the currently defined
1670    /// ACLs from the server memory to the ACL file.
1671    #[cfg(feature = "acl")]
1672    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1673    /// [Redis Docs](https://redis.io/commands/ACL)
1674    fn acl_save<>() -> () {
1675        cmd("ACL").arg("SAVE")
1676    }
1677
1678    /// Shows the currently active ACL rules in the Redis server.
1679    #[cfg(feature = "acl")]
1680    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1681    /// [Redis Docs](https://redis.io/commands/ACL)
1682    fn acl_list<>() -> (Vec<String>) {
1683        cmd("ACL").arg("LIST")
1684    }
1685
1686    /// Shows a list of all the usernames of the currently configured users in
1687    /// the Redis ACL system.
1688    #[cfg(feature = "acl")]
1689    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1690    /// [Redis Docs](https://redis.io/commands/ACL)
1691    fn acl_users<>() -> (Vec<String>) {
1692        cmd("ACL").arg("USERS")
1693    }
1694
1695    /// Returns all the rules defined for an existing ACL user.
1696    #[cfg(feature = "acl")]
1697    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1698    /// [Redis Docs](https://redis.io/commands/ACL)
1699    fn acl_getuser<K: ToSingleRedisArg>(username: K) -> (Option<acl::AclInfo>) {
1700        cmd("ACL").arg("GETUSER").arg(username)
1701    }
1702
1703    /// Creates an ACL user without any privilege.
1704    #[cfg(feature = "acl")]
1705    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1706    /// [Redis Docs](https://redis.io/commands/ACL)
1707    fn acl_setuser<K: ToSingleRedisArg>(username: K) -> () {
1708        cmd("ACL").arg("SETUSER").arg(username)
1709    }
1710
1711    /// Creates an ACL user with the specified rules or modify the rules of
1712    /// an existing user.
1713    #[cfg(feature = "acl")]
1714    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1715    /// [Redis Docs](https://redis.io/commands/ACL)
1716    fn acl_setuser_rules<K: ToSingleRedisArg>(username: K, rules: &'a [acl::Rule]) -> () {
1717        cmd("ACL").arg("SETUSER").arg(username).arg(rules)
1718    }
1719
1720    /// Delete all the specified ACL users and terminate all the connections
1721    /// that are authenticated with such users.
1722    #[cfg(feature = "acl")]
1723    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1724    /// [Redis Docs](https://redis.io/commands/ACL)
1725    fn acl_deluser<K: ToRedisArgs>(usernames: &'a [K]) -> (usize) {
1726        cmd("ACL").arg("DELUSER").arg(usernames)
1727    }
1728
1729    /// Simulate the execution of a given command by a given user.
1730    #[cfg(feature = "acl")]
1731    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1732    /// [Redis Docs](https://redis.io/commands/ACL)
1733    fn acl_dryrun<K: ToSingleRedisArg, C: ToSingleRedisArg, A: ToRedisArgs>(username: K, command: C, args: A) -> (String) {
1734        cmd("ACL").arg("DRYRUN").arg(username).arg(command).arg(args)
1735    }
1736
1737    /// Shows the available ACL categories.
1738    /// [Redis Docs](https://redis.io/commands/ACL)
1739    #[cfg(feature = "acl")]
1740    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1741    fn acl_cat<>() -> (HashSet<String>) {
1742        cmd("ACL").arg("CAT")
1743    }
1744
1745    /// Shows all the Redis commands in the specified category.
1746    /// [Redis Docs](https://redis.io/commands/ACL)
1747    #[cfg(feature = "acl")]
1748    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1749    fn acl_cat_categoryname<K: ToSingleRedisArg>(categoryname: K) -> (HashSet<String>) {
1750        cmd("ACL").arg("CAT").arg(categoryname)
1751    }
1752
1753    /// Generates a 256-bits password starting from /dev/urandom if available.
1754    /// [Redis Docs](https://redis.io/commands/ACL)
1755    #[cfg(feature = "acl")]
1756    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1757    fn acl_genpass<>() -> (String) {
1758        cmd("ACL").arg("GENPASS")
1759    }
1760
1761    /// Generates a 1-to-1024-bits password starting from /dev/urandom if available.
1762    /// [Redis Docs](https://redis.io/commands/ACL)
1763    #[cfg(feature = "acl")]
1764    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1765    fn acl_genpass_bits<>(bits: isize) -> (String) {
1766        cmd("ACL").arg("GENPASS").arg(bits)
1767    }
1768
1769    /// Returns the username the current connection is authenticated with.
1770    /// [Redis Docs](https://redis.io/commands/ACL)
1771    #[cfg(feature = "acl")]
1772    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1773    fn acl_whoami<>() -> (String) {
1774        cmd("ACL").arg("WHOAMI")
1775    }
1776
1777    /// Shows a list of recent ACL security events
1778    /// [Redis Docs](https://redis.io/commands/ACL)
1779    #[cfg(feature = "acl")]
1780    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1781    fn acl_log<>(count: isize) -> (Vec<String>) {
1782        cmd("ACL").arg("LOG").arg(count)
1783
1784    }
1785
1786    /// Clears the ACL log.
1787    /// [Redis Docs](https://redis.io/commands/ACL)
1788    #[cfg(feature = "acl")]
1789    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1790    fn acl_log_reset<>() -> () {
1791        cmd("ACL").arg("LOG").arg("RESET")
1792    }
1793
1794    /// Returns a helpful text describing the different subcommands.
1795    /// [Redis Docs](https://redis.io/commands/ACL)
1796    #[cfg(feature = "acl")]
1797    #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1798    fn acl_help<>() -> (Vec<String>) {
1799        cmd("ACL").arg("HELP")
1800    }
1801
1802    //
1803    // geospatial commands
1804    //
1805
1806    /// Adds the specified geospatial items to the specified key.
1807    ///
1808    /// Every member has to be written as a tuple of `(longitude, latitude,
1809    /// member_name)`. It can be a single tuple, or a vector of tuples.
1810    ///
1811    /// `longitude, latitude` can be set using [`redis::geo::Coord`][1].
1812    ///
1813    /// [1]: ./geo/struct.Coord.html
1814    ///
1815    /// Returns the number of elements added to the sorted set, not including
1816    /// elements already existing for which the score was updated.
1817    ///
1818    /// # Example
1819    ///
1820    /// ```rust,no_run
1821    /// use redis::{Commands, Connection, RedisResult};
1822    /// use redis::geo::Coord;
1823    ///
1824    /// fn add_point(con: &mut Connection) -> (RedisResult<isize>) {
1825    ///     con.geo_add("my_gis", (Coord::lon_lat(13.361389, 38.115556), "Palermo"))
1826    /// }
1827    ///
1828    /// fn add_point_with_tuples(con: &mut Connection) -> (RedisResult<isize>) {
1829    ///     con.geo_add("my_gis", ("13.361389", "38.115556", "Palermo"))
1830    /// }
1831    ///
1832    /// fn add_many_points(con: &mut Connection) -> (RedisResult<isize>) {
1833    ///     con.geo_add("my_gis", &[
1834    ///         ("13.361389", "38.115556", "Palermo"),
1835    ///         ("15.087269", "37.502669", "Catania")
1836    ///     ])
1837    /// }
1838    /// ```
1839    /// [Redis Docs](https://redis.io/commands/GEOADD)
1840    #[cfg(feature = "geospatial")]
1841    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1842    fn geo_add<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: M) -> (usize) {
1843        cmd("GEOADD").arg(key).arg(members)
1844    }
1845
1846    /// Return the distance between two members in the geospatial index
1847    /// represented by the sorted set.
1848    ///
1849    /// If one or both the members are missing, the command returns NULL, so
1850    /// it may be convenient to parse its response as either `Option<f64>` or
1851    /// `Option<String>`.
1852    ///
1853    /// # Example
1854    ///
1855    /// ```rust,no_run
1856    /// use redis::{Commands, RedisResult};
1857    /// use redis::geo::Unit;
1858    ///
1859    /// fn get_dists(con: &mut redis::Connection) {
1860    ///     let x: RedisResult<f64> = con.geo_dist(
1861    ///         "my_gis",
1862    ///         "Palermo",
1863    ///         "Catania",
1864    ///         Unit::Kilometers
1865    ///     );
1866    ///     // x is Ok(166.2742)
1867    ///
1868    ///     let x: RedisResult<Option<f64>> = con.geo_dist(
1869    ///         "my_gis",
1870    ///         "Palermo",
1871    ///         "Atlantis",
1872    ///         Unit::Meters
1873    ///     );
1874    ///     // x is Ok(None)
1875    /// }
1876    /// ```
1877    /// [Redis Docs](https://redis.io/commands/GEODIST)
1878    #[cfg(feature = "geospatial")]
1879    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1880    fn geo_dist<K: ToSingleRedisArg, M1: ToSingleRedisArg, M2: ToSingleRedisArg>(
1881        key: K,
1882        member1: M1,
1883        member2: M2,
1884        unit: geo::Unit
1885    ) -> (Option<f64>) {
1886        cmd("GEODIST")
1887            .arg(key)
1888            .arg(member1)
1889            .arg(member2)
1890            .arg(unit)
1891    }
1892
1893    /// Return valid [Geohash][1] strings representing the position of one or
1894    /// more members of the geospatial index represented by the sorted set at
1895    /// key.
1896    ///
1897    /// [1]: https://en.wikipedia.org/wiki/Geohash
1898    ///
1899    /// # Example
1900    ///
1901    /// ```rust,no_run
1902    /// use redis::{Commands, RedisResult};
1903    ///
1904    /// fn get_hash(con: &mut redis::Connection) {
1905    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", "Palermo");
1906    ///     // x is vec!["sqc8b49rny0"]
1907    ///
1908    ///     let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", &["Palermo", "Catania"]);
1909    ///     // x is vec!["sqc8b49rny0", "sqdtr74hyu0"]
1910    /// }
1911    /// ```
1912    /// [Redis Docs](https://redis.io/commands/GEOHASH)
1913    #[cfg(feature = "geospatial")]
1914    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1915    fn geo_hash<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: M) -> (Vec<String>) {
1916        cmd("GEOHASH").arg(key).arg(members)
1917    }
1918
1919    /// Return the positions of all the specified members of the geospatial
1920    /// index represented by the sorted set at key.
1921    ///
1922    /// Every position is a pair of `(longitude, latitude)`. [`redis::geo::Coord`][1]
1923    /// can be used to convert these value in a struct.
1924    ///
1925    /// [1]: ./geo/struct.Coord.html
1926    ///
1927    /// # Example
1928    ///
1929    /// ```rust,no_run
1930    /// use redis::{Commands, RedisResult};
1931    /// use redis::geo::Coord;
1932    ///
1933    /// fn get_position(con: &mut redis::Connection) {
1934    ///     let x: RedisResult<Vec<Vec<f64>>> = con.geo_pos("my_gis", &["Palermo", "Catania"]);
1935    ///     // x is [ [ 13.361389, 38.115556 ], [ 15.087269, 37.502669 ] ];
1936    ///
1937    ///     let x: Vec<Coord<f64>> = con.geo_pos("my_gis", "Palermo").unwrap();
1938    ///     // x[0].longitude is 13.361389
1939    ///     // x[0].latitude is 38.115556
1940    /// }
1941    /// ```
1942    /// [Redis Docs](https://redis.io/commands/GEOPOS)
1943    #[cfg(feature = "geospatial")]
1944    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1945    fn geo_pos<K: ToSingleRedisArg, M: ToRedisArgs>(key: K, members: M) -> (Vec<Option<geo::Coord<f64>>>) {
1946        cmd("GEOPOS").arg(key).arg(members)
1947    }
1948
1949    /// Return the members of a sorted set populated with geospatial information
1950    /// using [`geo_add`](#method.geo_add), which are within the borders of the area
1951    /// specified with the center location and the maximum distance from the center
1952    /// (the radius).
1953    ///
1954    /// Every item in the result can be read with [`redis::geo::RadiusSearchResult`][1],
1955    /// which support the multiple formats returned by `GEORADIUS`.
1956    ///
1957    /// [1]: ./geo/struct.RadiusSearchResult.html
1958    ///
1959    /// ```rust,no_run
1960    /// use redis::{Commands, RedisResult};
1961    /// use redis::geo::{RadiusOptions, RadiusSearchResult, RadiusOrder, Unit};
1962    ///
1963    /// fn radius(con: &mut redis::Connection) -> (Vec<RadiusSearchResult>) {
1964    ///     let opts = RadiusOptions::default().with_dist().order(RadiusOrder::Asc);
1965    ///     con.geo_radius("my_gis", 15.90, 37.21, 51.39, Unit::Kilometers, opts).unwrap()
1966    /// }
1967    /// ```
1968    /// [Redis Docs](https://redis.io/commands/GEORADIUS)
1969    #[cfg(feature = "geospatial")]
1970    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1971    fn geo_radius<K: ToSingleRedisArg>(
1972        key: K,
1973        longitude: f64,
1974        latitude: f64,
1975        radius: f64,
1976        unit: geo::Unit,
1977        options: geo::RadiusOptions
1978    ) -> (Vec<geo::RadiusSearchResult>) {
1979        cmd("GEORADIUS")
1980            .arg(key)
1981            .arg(longitude)
1982            .arg(latitude)
1983            .arg(radius)
1984            .arg(unit)
1985            .arg(options)
1986    }
1987
1988    /// Retrieve members selected by distance with the center of `member`. The
1989    /// member itself is always contained in the results.
1990    /// [Redis Docs](https://redis.io/commands/GEORADIUSBYMEMBER)
1991    #[cfg(feature = "geospatial")]
1992    #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1993    fn geo_radius_by_member<K: ToSingleRedisArg, M: ToSingleRedisArg>(
1994        key: K,
1995        member: M,
1996        radius: f64,
1997        unit: geo::Unit,
1998        options: geo::RadiusOptions
1999    ) -> (Vec<geo::RadiusSearchResult>) {
2000        cmd("GEORADIUSBYMEMBER")
2001            .arg(key)
2002            .arg(member)
2003            .arg(radius)
2004            .arg(unit)
2005            .arg(options)
2006    }
2007
2008    //
2009    // streams commands
2010    //
2011
2012    /// Ack pending stream messages checked out by a consumer.
2013    ///
2014    /// ```text
2015    /// XACK <key> <group> <id> <id> ... <id>
2016    /// ```
2017    /// [Redis Docs](https://redis.io/commands/XACK)
2018    #[cfg(feature = "streams")]
2019    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2020    fn xack<K: ToRedisArgs, G: ToRedisArgs, I: ToRedisArgs>(
2021        key: K,
2022        group: G,
2023        ids: &'a [I]) -> (usize) {
2024        cmd("XACK")
2025            .arg(key)
2026            .arg(group)
2027            .arg(ids)
2028    }
2029
2030
2031    /// Add a stream message by `key`. Use `*` as the `id` for the current timestamp.
2032    ///
2033    /// ```text
2034    /// XADD key <ID or *> [field value] [field value] ...
2035    /// ```
2036    /// [Redis Docs](https://redis.io/commands/XADD)
2037    #[cfg(feature = "streams")]
2038    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2039    fn xadd<K: ToRedisArgs, ID: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(
2040        key: K,
2041        id: ID,
2042        items: &'a [(F, V)]
2043    ) -> (Option<String>) {
2044        cmd("XADD").arg(key).arg(id).arg(items)
2045    }
2046
2047
2048    /// BTreeMap variant for adding a stream message by `key`.
2049    /// Use `*` as the `id` for the current timestamp.
2050    ///
2051    /// ```text
2052    /// XADD key <ID or *> [rust BTreeMap] ...
2053    /// ```
2054    /// [Redis Docs](https://redis.io/commands/XADD)
2055    #[cfg(feature = "streams")]
2056    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2057    fn xadd_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
2058        key: K,
2059        id: ID,
2060        map: BTM
2061    ) -> (Option<String>) {
2062        cmd("XADD").arg(key).arg(id).arg(map)
2063    }
2064
2065
2066    /// Add a stream message with options.
2067    ///
2068    /// Items can be any list type, e.g.
2069    /// ```rust
2070    /// // static items
2071    /// let items = &[("key", "val"), ("key2", "val2")];
2072    /// # use std::collections::BTreeMap;
2073    /// // A map (Can be BTreeMap, HashMap, etc)
2074    /// let mut map: BTreeMap<&str, &str> = BTreeMap::new();
2075    /// map.insert("ab", "cd");
2076    /// map.insert("ef", "gh");
2077    /// map.insert("ij", "kl");
2078    /// ```
2079    ///
2080    /// ```text
2081    /// XADD key [NOMKSTREAM] [<MAXLEN|MINID> [~|=] threshold [LIMIT count]] <* | ID> field value [field value] [KEEPREF | DELREF | ACKED] ...
2082    /// ```
2083    /// [Redis Docs](https://redis.io/commands/XADD)
2084    #[cfg(feature = "streams")]
2085    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2086    fn xadd_options<
2087        K: ToRedisArgs, ID: ToRedisArgs, I: ToRedisArgs
2088    >(
2089        key: K,
2090        id: ID,
2091        items: I,
2092        options: &'a streams::StreamAddOptions
2093    ) -> (Option<String>) {
2094        cmd("XADD")
2095            .arg(key)
2096            .arg(options)
2097            .arg(id)
2098            .arg(items)
2099    }
2100
2101
2102    /// Add a stream message while capping the stream at a maxlength.
2103    ///
2104    /// ```text
2105    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [field value] [field value] ...
2106    /// ```
2107    /// [Redis Docs](https://redis.io/commands/XADD)
2108    #[cfg(feature = "streams")]
2109    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2110    fn xadd_maxlen<
2111        K: ToSingleRedisArg,
2112        ID: ToRedisArgs,
2113        F: ToRedisArgs,
2114        V: ToRedisArgs
2115    >(
2116        key: K,
2117        maxlen: streams::StreamMaxlen,
2118        id: ID,
2119        items: &'a [(F, V)]
2120    ) -> (Option<String>) {
2121        cmd("XADD")
2122            .arg(key)
2123            .arg(maxlen)
2124            .arg(id)
2125            .arg(items)
2126    }
2127
2128
2129    /// BTreeMap variant for adding a stream message while capping the stream at a maxlength.
2130    ///
2131    /// ```text
2132    /// XADD key [MAXLEN [~|=] <count>] <ID or *> [rust BTreeMap] ...
2133    /// ```
2134    /// [Redis Docs](https://redis.io/commands/XADD)
2135    #[cfg(feature = "streams")]
2136    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2137    fn xadd_maxlen_map<K: ToSingleRedisArg, ID: ToRedisArgs, BTM: ToRedisArgs>(
2138        key: K,
2139        maxlen: streams::StreamMaxlen,
2140        id: ID,
2141        map: BTM
2142    ) -> (Option<String>) {
2143        cmd("XADD")
2144            .arg(key)
2145            .arg(maxlen)
2146            .arg(id)
2147            .arg(map)
2148    }
2149
2150    /// Perform a combined xpending and xclaim flow.
2151    ///
2152    /// ```no_run
2153    /// use redis::{Connection,Commands,RedisResult};
2154    /// use redis::streams::{StreamAutoClaimOptions, StreamAutoClaimReply};
2155    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2156    /// let mut con = client.get_connection().unwrap();
2157    ///
2158    /// let opts = StreamAutoClaimOptions::default();
2159    /// let results : RedisResult<StreamAutoClaimReply> = con.xautoclaim_options("k1", "g1", "c1", 10, "0-0", opts);
2160    /// ```
2161    ///
2162    /// ```text
2163    /// XAUTOCLAIM <key> <group> <consumer> <min-idle-time> <start> [COUNT <count>] [JUSTID]
2164    /// ```
2165    /// [Redis Docs](https://redis.io/commands/XAUTOCLAIM)
2166    #[cfg(feature = "streams")]
2167    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2168    fn xautoclaim_options<
2169        K: ToSingleRedisArg,
2170        G: ToRedisArgs,
2171        C: ToRedisArgs,
2172        MIT: ToRedisArgs,
2173        S: ToRedisArgs
2174    >(
2175        key: K,
2176        group: G,
2177        consumer: C,
2178        min_idle_time: MIT,
2179        start: S,
2180        options: streams::StreamAutoClaimOptions
2181    ) -> (streams::StreamAutoClaimReply) {
2182        cmd("XAUTOCLAIM")
2183            .arg(key)
2184            .arg(group)
2185            .arg(consumer)
2186            .arg(min_idle_time)
2187            .arg(start)
2188            .arg(options)
2189    }
2190
2191    /// Claim pending, unacked messages, after some period of time,
2192    /// currently checked out by another consumer.
2193    ///
2194    /// This method only accepts the must-have arguments for claiming messages.
2195    /// If optional arguments are required, see `xclaim_options` below.
2196    ///
2197    /// ```text
2198    /// XCLAIM <key> <group> <consumer> <min-idle-time> [<ID-1> <ID-2>]
2199    /// ```
2200    /// [Redis Docs](https://redis.io/commands/XCLAIM)
2201    #[cfg(feature = "streams")]
2202    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2203    fn xclaim<K: ToSingleRedisArg, G: ToRedisArgs, C: ToRedisArgs, MIT: ToRedisArgs, ID: ToRedisArgs>(
2204        key: K,
2205        group: G,
2206        consumer: C,
2207        min_idle_time: MIT,
2208        ids: &'a [ID]
2209    ) -> (streams::StreamClaimReply) {
2210        cmd("XCLAIM")
2211            .arg(key)
2212            .arg(group)
2213            .arg(consumer)
2214            .arg(min_idle_time)
2215            .arg(ids)
2216    }
2217
2218    /// This is the optional arguments version for claiming unacked, pending messages
2219    /// currently checked out by another consumer.
2220    ///
2221    /// ```no_run
2222    /// use redis::{Connection,Commands,RedisResult};
2223    /// use redis::streams::{StreamClaimOptions,StreamClaimReply};
2224    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2225    /// let mut con = client.get_connection().unwrap();
2226    ///
2227    /// // Claim all pending messages for key "k1",
2228    /// // from group "g1", checked out by consumer "c1"
2229    /// // for 10ms with RETRYCOUNT 2 and FORCE
2230    ///
2231    /// let opts = StreamClaimOptions::default()
2232    ///     .with_force()
2233    ///     .retry(2);
2234    /// let results: RedisResult<StreamClaimReply> =
2235    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
2236    ///
2237    /// // All optional arguments return a `Result<StreamClaimReply>` with one exception:
2238    /// // Passing JUSTID returns only the message `id` and omits the HashMap for each message.
2239    ///
2240    /// let opts = StreamClaimOptions::default()
2241    ///     .with_justid();
2242    /// let results: RedisResult<Vec<String>> =
2243    ///     con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
2244    /// ```
2245    ///
2246    /// ```text
2247    /// XCLAIM <key> <group> <consumer> <min-idle-time> <ID-1> <ID-2>
2248    ///     [IDLE <milliseconds>] [TIME <mstime>] [RETRYCOUNT <count>]
2249    ///     [FORCE] [JUSTID] [LASTID <lastid>]
2250    /// ```
2251    /// [Redis Docs](https://redis.io/commands/XCLAIM)
2252    #[cfg(feature = "streams")]
2253    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2254    fn xclaim_options<
2255        K: ToSingleRedisArg,
2256        G: ToRedisArgs,
2257        C: ToRedisArgs,
2258        MIT: ToRedisArgs,
2259        ID: ToRedisArgs
2260    >(
2261        key: K,
2262        group: G,
2263        consumer: C,
2264        min_idle_time: MIT,
2265        ids: &'a [ID],
2266        options: streams::StreamClaimOptions
2267    ) -> Generic {
2268        cmd("XCLAIM")
2269            .arg(key)
2270            .arg(group)
2271            .arg(consumer)
2272            .arg(min_idle_time)
2273            .arg(ids)
2274            .arg(options)
2275    }
2276
2277
2278    /// Deletes a list of `id`s for a given stream `key`.
2279    ///
2280    /// ```text
2281    /// XDEL <key> [<ID1> <ID2> ... <IDN>]
2282    /// ```
2283    /// [Redis Docs](https://redis.io/commands/XDEL)
2284    #[cfg(feature = "streams")]
2285    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2286    fn xdel<K: ToSingleRedisArg, ID: ToRedisArgs>(
2287        key: K,
2288        ids: &'a [ID]
2289    ) -> (usize) {
2290        cmd("XDEL").arg(key).arg(ids)
2291    }
2292
2293    /// An extension of the Streams `XDEL` command that provides finer control over how message entries are deleted with respect to consumer groups.
2294    #[cfg(feature = "streams")]
2295    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2296    fn xdel_ex<K: ToRedisArgs, ID: ToRedisArgs>(key: K, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XDelExStatusCode>) {
2297        cmd("XDELEX").arg(key).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2298    }
2299
2300    /// A combination of `XACK` and `XDEL` that acknowledges and attempts to delete a list of `ids` for a given stream `key` and consumer `group`.
2301    #[cfg(feature = "streams")]
2302    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2303    fn xack_del<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(key: K, group: G, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XAckDelStatusCode>) {
2304        cmd("XACKDEL").arg(key).arg(group).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2305    }
2306
2307    /// This command is used for creating a consumer `group`. It expects the stream key
2308    /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
2309    /// The `id` is the starting message id all consumers should read from. Use `$` If you want
2310    /// all consumers to read from the last message added to stream.
2311    ///
2312    /// ```text
2313    /// XGROUP CREATE <key> <groupname> <id or $>
2314    /// ```
2315    /// [Redis Docs](https://redis.io/commands/XGROUP)
2316    #[cfg(feature = "streams")]
2317    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2318    fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2319        key: K,
2320        group: G,
2321        id: ID
2322    ) -> () {
2323        cmd("XGROUP")
2324            .arg("CREATE")
2325            .arg(key)
2326            .arg(group)
2327            .arg(id)
2328    }
2329
2330    /// This creates a `consumer` explicitly (vs implicit via XREADGROUP)
2331    /// for given stream `key.
2332    ///
2333    /// The return value is either a 0 or a 1 for the number of consumers created
2334    /// 0 means the consumer already exists
2335    ///
2336    /// ```text
2337    /// XGROUP CREATECONSUMER <key> <groupname> <consumername>
2338    /// ```
2339    /// [Redis Docs](https://redis.io/commands/XGROUP)
2340    #[cfg(feature = "streams")]
2341    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2342    fn xgroup_createconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2343        key: K,
2344        group: G,
2345        consumer: C
2346    ) -> bool {
2347        cmd("XGROUP")
2348            .arg("CREATECONSUMER")
2349            .arg(key)
2350            .arg(group)
2351            .arg(consumer)
2352    }
2353
2354    /// This is the alternate version for creating a consumer `group`
2355    /// which makes the stream if it doesn't exist.
2356    ///
2357    /// ```text
2358    /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
2359    /// ```
2360    /// [Redis Docs](https://redis.io/commands/XGROUP)
2361    #[cfg(feature = "streams")]
2362    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2363    fn xgroup_create_mkstream<
2364        K: ToRedisArgs,
2365        G: ToRedisArgs,
2366        ID: ToRedisArgs
2367    >(
2368        key: K,
2369        group: G,
2370        id: ID
2371    ) -> () {
2372        cmd("XGROUP")
2373            .arg("CREATE")
2374            .arg(key)
2375            .arg(group)
2376            .arg(id)
2377            .arg("MKSTREAM")
2378    }
2379
2380
2381    /// Alter which `id` you want consumers to begin reading from an existing
2382    /// consumer `group`.
2383    ///
2384    /// ```text
2385    /// XGROUP SETID <key> <groupname> <id or $>
2386    /// ```
2387    /// [Redis Docs](https://redis.io/commands/XGROUP)
2388    #[cfg(feature = "streams")]
2389    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2390    fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2391        key: K,
2392        group: G,
2393        id: ID
2394    ) -> () {
2395        cmd("XGROUP")
2396            .arg("SETID")
2397            .arg(key)
2398            .arg(group)
2399            .arg(id)
2400    }
2401
2402
2403    /// Destroy an existing consumer `group` for a given stream `key`
2404    ///
2405    /// ```text
2406    /// XGROUP SETID <key> <groupname> <id or $>
2407    /// ```
2408    /// [Redis Docs](https://redis.io/commands/XGROUP)
2409    #[cfg(feature = "streams")]
2410    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2411    fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
2412        key: K,
2413        group: G
2414    ) -> bool {
2415        cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
2416    }
2417
2418    /// This deletes a `consumer` from an existing consumer `group`
2419    /// for given stream `key.
2420    ///
2421    /// ```text
2422    /// XGROUP DELCONSUMER <key> <groupname> <consumername>
2423    /// ```
2424    /// [Redis Docs](https://redis.io/commands/XGROUP)
2425    #[cfg(feature = "streams")]
2426    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2427    fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2428        key: K,
2429        group: G,
2430        consumer: C
2431    ) -> usize {
2432        cmd("XGROUP")
2433            .arg("DELCONSUMER")
2434            .arg(key)
2435            .arg(group)
2436            .arg(consumer)
2437    }
2438
2439
2440    /// This returns all info details about
2441    /// which consumers have read messages for given consumer `group`.
2442    /// Take note of the StreamInfoConsumersReply return type.
2443    ///
2444    /// *It's possible this return value might not contain new fields
2445    /// added by Redis in future versions.*
2446    ///
2447    /// ```text
2448    /// XINFO CONSUMERS <key> <group>
2449    /// ```
2450    /// [Redis Docs](https://redis.io/commands/XINFO")
2451    #[cfg(feature = "streams")]
2452    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2453    fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
2454        key: K,
2455        group: G
2456    ) -> (streams::StreamInfoConsumersReply) {
2457        cmd("XINFO")
2458            .arg("CONSUMERS")
2459            .arg(key)
2460            .arg(group)
2461    }
2462
2463
2464    /// Returns all consumer `group`s created for a given stream `key`.
2465    /// Take note of the StreamInfoGroupsReply return type.
2466    ///
2467    /// *It's possible this return value might not contain new fields
2468    /// added by Redis in future versions.*
2469    ///
2470    /// ```text
2471    /// XINFO GROUPS <key>
2472    /// ```
2473    /// [Redis Docs](https://redis.io/commands/XINFO-GROUPS)
2474    #[cfg(feature = "streams")]
2475    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2476    fn xinfo_groups<K: ToRedisArgs>(key: K) -> (streams::StreamInfoGroupsReply) {
2477        cmd("XINFO").arg("GROUPS").arg(key)
2478    }
2479
2480
2481    /// Returns info about high-level stream details
2482    /// (first & last message `id`, length, number of groups, etc.)
2483    /// Take note of the StreamInfoStreamReply return type.
2484    ///
2485    /// *It's possible this return value might not contain new fields
2486    /// added by Redis in future versions.*
2487    ///
2488    /// ```text
2489    /// XINFO STREAM <key>
2490    /// ```
2491    /// [Redis Docs](https://redis.io/commands/XINFO-STREAM)
2492    #[cfg(feature = "streams")]
2493    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2494    fn xinfo_stream<K: ToRedisArgs>(key: K) -> (streams::StreamInfoStreamReply) {
2495        cmd("XINFO").arg("STREAM").arg(key)
2496    }
2497
2498    /// Returns the number of messages for a given stream `key`.
2499    ///
2500    /// ```text
2501    /// XLEN <key>
2502    /// ```
2503    #[cfg(feature = "streams")]
2504    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2505    /// [Redis Docs](https://redis.io/commands/XLEN)
2506    fn xlen<K: ToRedisArgs>(key: K) -> usize {
2507        cmd("XLEN").arg(key)
2508    }
2509
2510
2511    /// This is a basic version of making XPENDING command calls which only
2512    /// passes a stream `key` and consumer `group` and it
2513    /// returns details about which consumers have pending messages
2514    /// that haven't been acked.
2515    ///
2516    /// You can use this method along with
2517    /// `xclaim` or `xclaim_options` for determining which messages
2518    /// need to be retried.
2519    ///
2520    /// Take note of the StreamPendingReply return type.
2521    ///
2522    /// ```text
2523    /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
2524    /// ```
2525    /// [Redis Docs](https://redis.io/commands/XPENDING)
2526    #[cfg(feature = "streams")]
2527    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2528    fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
2529        key: K,
2530        group: G
2531    ) -> (streams::StreamPendingReply) {
2532        cmd("XPENDING").arg(key).arg(group)
2533    }
2534
2535
2536    /// This XPENDING version returns a list of all messages over the range.
2537    /// You can use this for paginating pending messages (but without the message HashMap).
2538    ///
2539    /// Start and end follow the same rules `xrange` args. Set start to `-`
2540    /// and end to `+` for the entire stream.
2541    ///
2542    /// Take note of the StreamPendingCountReply return type.
2543    ///
2544    /// ```text
2545    /// XPENDING <key> <group> <start> <stop> <count>
2546    /// ```
2547    /// [Redis Docs](https://redis.io/commands/XPENDING)
2548    #[cfg(feature = "streams")]
2549    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2550    fn xpending_count<
2551        K: ToRedisArgs,
2552        G: ToRedisArgs,
2553        S: ToRedisArgs,
2554        E: ToRedisArgs,
2555        C: ToRedisArgs
2556    >(
2557        key: K,
2558        group: G,
2559        start: S,
2560        end: E,
2561        count: C
2562    ) -> (streams::StreamPendingCountReply) {
2563        cmd("XPENDING")
2564            .arg(key)
2565            .arg(group)
2566            .arg(start)
2567            .arg(end)
2568            .arg(count)
2569    }
2570
2571
2572    /// An alternate version of `xpending_count` which filters by `consumer` name.
2573    ///
2574    /// Start and end follow the same rules `xrange` args. Set start to `-`
2575    /// and end to `+` for the entire stream.
2576    ///
2577    /// Take note of the StreamPendingCountReply return type.
2578    ///
2579    /// ```text
2580    /// XPENDING <key> <group> <start> <stop> <count> <consumer>
2581    /// ```
2582    /// [Redis Docs](https://redis.io/commands/XPENDING)
2583    #[cfg(feature = "streams")]
2584    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2585    fn xpending_consumer_count<
2586        K: ToRedisArgs,
2587        G: ToRedisArgs,
2588        S: ToRedisArgs,
2589        E: ToRedisArgs,
2590        C: ToRedisArgs,
2591        CN: ToRedisArgs
2592    >(
2593        key: K,
2594        group: G,
2595        start: S,
2596        end: E,
2597        count: C,
2598        consumer: CN
2599    ) -> (streams::StreamPendingCountReply) {
2600        cmd("XPENDING")
2601            .arg(key)
2602            .arg(group)
2603            .arg(start)
2604            .arg(end)
2605            .arg(count)
2606            .arg(consumer)
2607    }
2608
2609    /// Returns a range of messages in a given stream `key`.
2610    ///
2611    /// Set `start` to `-` to begin at the first message.
2612    /// Set `end` to `+` to end the most recent message.
2613    /// You can pass message `id` to both `start` and `end`.
2614    ///
2615    /// Take note of the StreamRangeReply return type.
2616    ///
2617    /// ```text
2618    /// XRANGE key start end
2619    /// ```
2620    /// [Redis Docs](https://redis.io/commands/XRANGE)
2621    #[cfg(feature = "streams")]
2622    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2623    fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
2624        key: K,
2625        start: S,
2626        end: E
2627    ) -> (streams::StreamRangeReply) {
2628        cmd("XRANGE").arg(key).arg(start).arg(end)
2629    }
2630
2631
2632    /// A helper method for automatically returning all messages in a stream by `key`.
2633    /// **Use with caution!**
2634    ///
2635    /// ```text
2636    /// XRANGE key - +
2637    /// ```
2638    /// [Redis Docs](https://redis.io/commands/XRANGE)
2639    #[cfg(feature = "streams")]
2640    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2641    fn xrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2642        cmd("XRANGE").arg(key).arg("-").arg("+")
2643    }
2644
2645
2646    /// A method for paginating a stream by `key`.
2647    ///
2648    /// ```text
2649    /// XRANGE key start end [COUNT <n>]
2650    /// ```
2651    /// [Redis Docs](https://redis.io/commands/XRANGE)
2652    #[cfg(feature = "streams")]
2653    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2654    fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
2655        key: K,
2656        start: S,
2657        end: E,
2658        count: C
2659    ) -> (streams::StreamRangeReply) {
2660        cmd("XRANGE")
2661            .arg(key)
2662            .arg(start)
2663            .arg(end)
2664            .arg("COUNT")
2665            .arg(count)
2666    }
2667
2668
2669    /// Read a list of `id`s for each stream `key`.
2670    /// This is the basic form of reading streams.
2671    /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
2672    /// see `xread_options`.
2673    ///
2674    /// ```text
2675    /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
2676    /// ```
2677    /// [Redis Docs](https://redis.io/commands/XREAD)
2678    #[cfg(feature = "streams")]
2679    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2680    fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
2681        keys: &'a [K],
2682        ids: &'a [ID]
2683    ) -> (Option<streams::StreamReadReply>) {
2684        cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
2685    }
2686
2687    /// This method handles setting optional arguments for
2688    /// `XREAD` or `XREADGROUP` Redis commands.
2689    /// ```no_run
2690    /// use redis::{Connection,RedisResult,Commands};
2691    /// use redis::streams::{StreamReadOptions,StreamReadReply};
2692    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2693    /// let mut con = client.get_connection().unwrap();
2694    ///
2695    /// // Read 10 messages from the start of the stream,
2696    /// // without registering as a consumer group.
2697    ///
2698    /// let opts = StreamReadOptions::default()
2699    ///     .count(10);
2700    /// let results: RedisResult<StreamReadReply> =
2701    ///     con.xread_options(&["k1"], &["0"], &opts);
2702    ///
2703    /// // Read all undelivered messages for a given
2704    /// // consumer group. Be advised: the consumer group must already
2705    /// // exist before making this call. Also note: we're passing
2706    /// // '>' as the id here, which means all undelivered messages.
2707    ///
2708    /// let opts = StreamReadOptions::default()
2709    ///     .group("group-1", "consumer-1");
2710    /// let results: RedisResult<StreamReadReply> =
2711    ///     con.xread_options(&["k1"], &[">"], &opts);
2712    /// ```
2713    ///
2714    /// ```text
2715    /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
2716    ///     STREAMS key_1 key_2 ... key_N
2717    ///     ID_1 ID_2 ... ID_N
2718    ///
2719    /// XREADGROUP [GROUP group-name consumer-name] [BLOCK <milliseconds>] [COUNT <count>] [NOACK]
2720    ///     STREAMS key_1 key_2 ... key_N
2721    ///     ID_1 ID_2 ... ID_N
2722    /// ```
2723    /// [Redis Docs](https://redis.io/commands/XREAD)
2724    #[cfg(feature = "streams")]
2725    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2726    fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
2727        keys: &'a [K],
2728        ids: &'a [ID],
2729        options: &'a streams::StreamReadOptions
2730    ) -> (Option<streams::StreamReadReply>) {
2731        cmd(if options.read_only() {
2732            "XREAD"
2733        } else {
2734            "XREADGROUP"
2735        })
2736        .arg(options)
2737        .arg("STREAMS")
2738        .arg(keys)
2739        .arg(ids)
2740    }
2741
2742    /// This is the reverse version of `xrange`.
2743    /// The same rules apply for `start` and `end` here.
2744    ///
2745    /// ```text
2746    /// XREVRANGE key end start
2747    /// ```
2748    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2749    #[cfg(feature = "streams")]
2750    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2751    fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
2752        key: K,
2753        end: E,
2754        start: S
2755    ) -> (streams::StreamRangeReply) {
2756        cmd("XREVRANGE").arg(key).arg(end).arg(start)
2757    }
2758
2759    /// This is the reverse version of `xrange_all`.
2760    /// The same rules apply for `start` and `end` here.
2761    ///
2762    /// ```text
2763    /// XREVRANGE key + -
2764    /// ```
2765    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2766    #[cfg(feature = "streams")]
2767    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2768    fn xrevrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2769        cmd("XREVRANGE").arg(key).arg("+").arg("-")
2770    }
2771
2772    /// This is the reverse version of `xrange_count`.
2773    /// The same rules apply for `start` and `end` here.
2774    ///
2775    /// ```text
2776    /// XREVRANGE key end start [COUNT <n>]
2777    /// ```
2778    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2779    #[cfg(feature = "streams")]
2780    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2781    fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
2782        key: K,
2783        end: E,
2784        start: S,
2785        count: C
2786    ) -> (streams::StreamRangeReply) {
2787        cmd("XREVRANGE")
2788            .arg(key)
2789            .arg(end)
2790            .arg(start)
2791            .arg("COUNT")
2792            .arg(count)
2793    }
2794
2795    /// Trim a stream `key` to a MAXLEN count.
2796    ///
2797    /// ```text
2798    /// XTRIM <key> MAXLEN [~|=] <count>  (Same as XADD MAXLEN option)
2799    /// ```
2800    /// [Redis Docs](https://redis.io/commands/XTRIM)
2801    #[cfg(feature = "streams")]
2802    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2803    fn xtrim<K: ToRedisArgs>(
2804        key: K,
2805        maxlen: streams::StreamMaxlen
2806    ) -> usize {
2807        cmd("XTRIM").arg(key).arg(maxlen)
2808    }
2809
2810     /// Trim a stream `key` with full options
2811     ///
2812     /// ```text
2813     /// XTRIM <key> <MAXLEN|MINID> [~|=] <threshold> [LIMIT <count>]  (Same as XADD MAXID|MINID options) [KEEPREF | DELREF | ACKED]
2814     /// ```
2815     /// [Redis Docs](https://redis.io/commands/XTRIM)
2816    #[cfg(feature = "streams")]
2817    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2818    fn xtrim_options<K: ToRedisArgs>(
2819        key: K,
2820        options: &'a streams::StreamTrimOptions
2821    ) -> usize {
2822        cmd("XTRIM").arg(key).arg(options)
2823    }
2824
2825    // script commands
2826
2827    /// Load a script.
2828    ///
2829    /// See [`invoke_script`](Self::invoke_script) to actually run the scripts.
2830    #[cfg_attr(feature = "script", doc = r##"
2831
2832# Examples:
2833
2834```rust,no_run
2835# fn do_something() -> redis::RedisResult<()> {
2836# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2837# let mut con = client.get_connection().unwrap();
2838let script = redis::Script::new(r"
2839    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2840");
2841let (load_res, invok_res): (String, isize) = redis::pipe()
2842    .load_script(&script)
2843    .invoke_script(script.arg(1).arg(2))
2844    .query(&mut con)?;
2845
2846assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2847assert_eq!(invok_res, 3);
2848# Ok(()) }
2849```
2850"##)]
2851    #[cfg(feature = "script")]
2852    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2853    fn load_script<>(script: &'a crate::Script) -> Generic {
2854        &mut script.load_cmd()
2855    }
2856
2857    /// Invoke a prepared script.
2858    ///
2859    /// Note: Unlike[`ScriptInvocation::invoke`](crate::ScriptInvocation::invoke), this function
2860    /// does _not_ automatically load the script. If the invoked script did not get loaded beforehand, you
2861    /// need to manually load it (e.g.: using [`load_script`](Self::load_script) or
2862    /// [`ScriptInvocation::load`](crate::ScriptInvocation::load)). Otherwise this command will fail.
2863    #[cfg_attr(feature = "script", doc = r##"
2864
2865# Examples:
2866
2867```rust,no_run
2868# fn do_something() -> redis::RedisResult<()> {
2869# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2870# let mut con = client.get_connection().unwrap();
2871let script = redis::Script::new(r"
2872    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2873");
2874let (load_res, invok_1_res, invok_2_res): (String, isize, isize) = redis::pipe()
2875    .load_script(&script)
2876    .invoke_script(script.arg(1).arg(2))
2877    .invoke_script(script.arg(2).arg(3))
2878    .query(&mut con)?;
2879
2880assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2881assert_eq!(invok_1_res, 3);
2882assert_eq!(invok_2_res, 5);
2883# Ok(()) }
2884```
2885"##)]
2886    #[cfg(feature = "script")]
2887    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2888    fn invoke_script<>(invocation: &'a crate::ScriptInvocation<'a>) -> Generic {
2889        &mut invocation.eval_cmd()
2890    }
2891
2892    // cleanup commands
2893
2894    /// Deletes all the keys of all databases
2895    ///
2896    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2897    /// of your Redis server.
2898    ///
2899    /// To enforce a flush mode, use [`Commands::flushall_options`].
2900    ///
2901    /// ```text
2902    /// FLUSHALL
2903    /// ```
2904    /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2905    fn flushall<>() -> () {
2906        &mut cmd("FLUSHALL")
2907    }
2908
2909    /// Deletes all the keys of all databases with options
2910    ///
2911    /// ```text
2912    /// FLUSHALL [ASYNC|SYNC]
2913    /// ```
2914    /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2915    fn flushall_options<>(options: &'a FlushAllOptions) -> () {
2916        cmd("FLUSHALL").arg(options)
2917    }
2918
2919    /// Deletes all the keys of the current database
2920    ///
2921    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2922    /// of your Redis server.
2923    ///
2924    /// To enforce a flush mode, use [`Commands::flushdb_options`].
2925    ///
2926    /// ```text
2927    /// FLUSHDB
2928    /// ```
2929    /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2930    fn flushdb<>() -> () {
2931        &mut cmd("FLUSHDB")
2932    }
2933
2934    /// Deletes all the keys of the current database with options
2935    ///
2936    /// ```text
2937    /// FLUSHDB [ASYNC|SYNC]
2938    /// ```
2939    /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2940    fn flushdb_options<>(options: &'a FlushDbOptions) -> () {
2941        cmd("FLUSHDB").arg(options)
2942    }
2943}
2944
2945/// Allows pubsub callbacks to stop receiving messages.
2946///
2947/// Arbitrary data may be returned from `Break`.
2948#[non_exhaustive]
2949pub enum ControlFlow<U> {
2950    /// Continues.
2951    Continue,
2952    /// Breaks with a value.
2953    Break(U),
2954}
2955
2956/// The PubSub trait allows subscribing to one or more channels
2957/// and receiving a callback whenever a message arrives.
2958///
2959/// Each method handles subscribing to the list of keys, waiting for
2960/// messages, and unsubscribing from the same list of channels once
2961/// a ControlFlow::Break is encountered.
2962///
2963/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2964/// for calling other methods.
2965///
2966/// # Examples
2967///
2968/// ```rust,no_run
2969/// # fn do_something() -> redis::RedisResult<()> {
2970/// use redis::{PubSubCommands, ControlFlow};
2971/// let client = redis::Client::open("redis://127.0.0.1/")?;
2972/// let mut con = client.get_connection()?;
2973/// let mut count = 0;
2974/// con.subscribe(&["foo"], |msg| {
2975///     // do something with message
2976///     assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2977///
2978///     // increment messages seen counter
2979///     count += 1;
2980///     match count {
2981///         // stop after receiving 10 messages
2982///         10 => ControlFlow::Break(()),
2983///         _ => ControlFlow::Continue,
2984///     }
2985/// })?;
2986/// # Ok(()) }
2987/// ```
2988// TODO In the future, it would be nice to implement Try such that `?` will work
2989//      within the closure.
2990pub trait PubSubCommands: Sized {
2991    /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2992    /// closure for each message received.
2993    ///
2994    /// For every `Msg` passed to the provided closure, either
2995    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2996    /// method will not return until `ControlFlow::Break` is observed.
2997    fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2998    where
2999        F: FnMut(Msg) -> ControlFlow<U>,
3000        C: ToRedisArgs;
3001
3002    /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
3003    /// closure for each message received.
3004    ///
3005    /// For every `Msg` passed to the provided closure, either
3006    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
3007    /// method will not return until `ControlFlow::Break` is observed.
3008    fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
3009    where
3010        F: FnMut(Msg) -> ControlFlow<U>,
3011        P: ToRedisArgs;
3012}
3013
3014impl<T> Commands for T where T: ConnectionLike {}
3015
3016#[cfg(feature = "aio")]
3017impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
3018
3019impl<T> TypedCommands for T where T: ConnectionLike {}
3020
3021#[cfg(feature = "aio")]
3022impl<T> AsyncTypedCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
3023
3024impl PubSubCommands for Connection {
3025    fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
3026    where
3027        F: FnMut(Msg) -> ControlFlow<U>,
3028        C: ToRedisArgs,
3029    {
3030        let mut pubsub = self.as_pubsub();
3031        pubsub.subscribe(channels)?;
3032
3033        loop {
3034            let msg = pubsub.get_message()?;
3035            match func(msg) {
3036                ControlFlow::Continue => continue,
3037                ControlFlow::Break(value) => return Ok(value),
3038            }
3039        }
3040    }
3041
3042    fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
3043    where
3044        F: FnMut(Msg) -> ControlFlow<U>,
3045        P: ToRedisArgs,
3046    {
3047        let mut pubsub = self.as_pubsub();
3048        pubsub.psubscribe(patterns)?;
3049
3050        loop {
3051            let msg = pubsub.get_message()?;
3052            match func(msg) {
3053                ControlFlow::Continue => continue,
3054                ControlFlow::Break(value) => return Ok(value),
3055            }
3056        }
3057    }
3058}
3059
3060/// Options for the [SCAN](https://redis.io/commands/scan) command
3061///
3062/// # Example
3063///
3064/// ```rust
3065/// use redis::{Commands, RedisResult, ScanOptions, Iter};
3066/// fn force_fetching_every_matching_key<'a, T: redis::FromRedisValue>(
3067///     con: &'a mut redis::Connection,
3068///     pattern: &'a str,
3069///     count: usize,
3070/// ) -> RedisResult<Iter<'a, T>> {
3071///     let opts = ScanOptions::default()
3072///         .with_pattern(pattern)
3073///         .with_count(count);
3074///     con.scan_options(opts)
3075/// }
3076/// ```
3077#[derive(Default)]
3078pub struct ScanOptions {
3079    pattern: Option<String>,
3080    count: Option<usize>,
3081    scan_type: Option<String>,
3082}
3083
3084impl ScanOptions {
3085    /// Limit the results to the first N matching items.
3086    pub fn with_count(mut self, n: usize) -> Self {
3087        self.count = Some(n);
3088        self
3089    }
3090
3091    /// Pattern for scan
3092    pub fn with_pattern(mut self, p: impl Into<String>) -> Self {
3093        self.pattern = Some(p.into());
3094        self
3095    }
3096
3097    /// Limit the results to those with the given Redis type
3098    pub fn with_type(mut self, t: impl Into<String>) -> Self {
3099        self.scan_type = Some(t.into());
3100        self
3101    }
3102}
3103
3104impl ToRedisArgs for ScanOptions {
3105    fn write_redis_args<W>(&self, out: &mut W)
3106    where
3107        W: ?Sized + RedisWrite,
3108    {
3109        if let Some(p) = &self.pattern {
3110            out.write_arg(b"MATCH");
3111            out.write_arg_fmt(p);
3112        }
3113
3114        if let Some(n) = self.count {
3115            out.write_arg(b"COUNT");
3116            out.write_arg_fmt(n);
3117        }
3118
3119        if let Some(t) = &self.scan_type {
3120            out.write_arg(b"TYPE");
3121            out.write_arg_fmt(t);
3122        }
3123    }
3124
3125    fn num_of_args(&self) -> usize {
3126        let mut len = 0;
3127        if self.pattern.is_some() {
3128            len += 2;
3129        }
3130        if self.count.is_some() {
3131            len += 2;
3132        }
3133        if self.scan_type.is_some() {
3134            len += 2;
3135        }
3136        len
3137    }
3138}
3139
3140/// Options for the [LPOS](https://redis.io/commands/lpos) command
3141///
3142/// # Example
3143///
3144/// ```rust,no_run
3145/// use redis::{Commands, RedisResult, LposOptions};
3146/// fn fetch_list_position(
3147///     con: &mut redis::Connection,
3148///     key: &str,
3149///     value: &str,
3150///     count: usize,
3151///     rank: isize,
3152///     maxlen: usize,
3153/// ) -> RedisResult<Vec<usize>> {
3154///     let opts = LposOptions::default()
3155///         .count(count)
3156///         .rank(rank)
3157///         .maxlen(maxlen);
3158///     con.lpos(key, value, opts)
3159/// }
3160/// ```
3161#[derive(Default)]
3162pub struct LposOptions {
3163    count: Option<usize>,
3164    maxlen: Option<usize>,
3165    rank: Option<isize>,
3166}
3167
3168impl LposOptions {
3169    /// Limit the results to the first N matching items.
3170    pub fn count(mut self, n: usize) -> Self {
3171        self.count = Some(n);
3172        self
3173    }
3174
3175    /// Return the value of N from the matching items.
3176    pub fn rank(mut self, n: isize) -> Self {
3177        self.rank = Some(n);
3178        self
3179    }
3180
3181    /// Limit the search to N items in the list.
3182    pub fn maxlen(mut self, n: usize) -> Self {
3183        self.maxlen = Some(n);
3184        self
3185    }
3186}
3187
3188impl ToRedisArgs for LposOptions {
3189    fn write_redis_args<W>(&self, out: &mut W)
3190    where
3191        W: ?Sized + RedisWrite,
3192    {
3193        if let Some(n) = self.count {
3194            out.write_arg(b"COUNT");
3195            out.write_arg_fmt(n);
3196        }
3197
3198        if let Some(n) = self.rank {
3199            out.write_arg(b"RANK");
3200            out.write_arg_fmt(n);
3201        }
3202
3203        if let Some(n) = self.maxlen {
3204            out.write_arg(b"MAXLEN");
3205            out.write_arg_fmt(n);
3206        }
3207    }
3208
3209    fn num_of_args(&self) -> usize {
3210        let mut len = 0;
3211        if self.count.is_some() {
3212            len += 2;
3213        }
3214        if self.rank.is_some() {
3215            len += 2;
3216        }
3217        if self.maxlen.is_some() {
3218            len += 2;
3219        }
3220        len
3221    }
3222}
3223
3224/// Enum for the LEFT | RIGHT args used by some commands
3225#[non_exhaustive]
3226pub enum Direction {
3227    /// Targets the first element (head) of the list
3228    Left,
3229    /// Targets the last element (tail) of the list
3230    Right,
3231}
3232
3233impl ToRedisArgs for Direction {
3234    fn write_redis_args<W>(&self, out: &mut W)
3235    where
3236        W: ?Sized + RedisWrite,
3237    {
3238        let s: &[u8] = match self {
3239            Direction::Left => b"LEFT",
3240            Direction::Right => b"RIGHT",
3241        };
3242        out.write_arg(s);
3243    }
3244}
3245
3246impl ToSingleRedisArg for Direction {}
3247
3248/// Options for the [COPY](https://redis.io/commands/copy) command
3249///
3250/// # Example
3251/// ```rust,no_run
3252/// use redis::{Commands, RedisResult, CopyOptions, SetExpiry, ExistenceCheck};
3253/// fn copy_value(
3254///     con: &mut redis::Connection,
3255///     old: &str,
3256///     new: &str,
3257/// ) -> RedisResult<Vec<usize>> {
3258///     let opts = CopyOptions::default()
3259///         .db("my_other_db")
3260///         .replace(true);
3261///     con.copy(old, new, opts)
3262/// }
3263/// ```
3264#[derive(Clone, Copy, Debug)]
3265pub struct CopyOptions<Db: ToString> {
3266    db: Option<Db>,
3267    replace: bool,
3268}
3269
3270impl Default for CopyOptions<&'static str> {
3271    fn default() -> Self {
3272        CopyOptions {
3273            db: None,
3274            replace: false,
3275        }
3276    }
3277}
3278
3279impl<Db: ToString> CopyOptions<Db> {
3280    /// Set the target database for the copy operation
3281    pub fn db<Db2: ToString>(self, db: Db2) -> CopyOptions<Db2> {
3282        CopyOptions {
3283            db: Some(db),
3284            replace: self.replace,
3285        }
3286    }
3287
3288    /// Set the replace option for the copy operation
3289    pub fn replace(mut self, replace: bool) -> Self {
3290        self.replace = replace;
3291        self
3292    }
3293}
3294
3295impl<Db: ToString> ToRedisArgs for CopyOptions<Db> {
3296    fn write_redis_args<W>(&self, out: &mut W)
3297    where
3298        W: ?Sized + RedisWrite,
3299    {
3300        if let Some(db) = &self.db {
3301            out.write_arg(b"DB");
3302            out.write_arg(db.to_string().as_bytes());
3303        }
3304        if self.replace {
3305            out.write_arg(b"REPLACE");
3306        }
3307    }
3308}
3309
3310impl<Db: ToString> ToSingleRedisArg for CopyOptions<Db> {}
3311
3312/// Options for the [SET](https://redis.io/commands/set) command
3313///
3314/// # Example
3315/// ```rust,no_run
3316/// use redis::{Commands, RedisResult, SetOptions, SetExpiry, ExistenceCheck, ValueComparison};
3317/// fn set_key_value(
3318///     con: &mut redis::Connection,
3319///     key: &str,
3320///     value: &str,
3321/// ) -> RedisResult<Vec<usize>> {
3322///     let opts = SetOptions::default()
3323///         .conditional_set(ExistenceCheck::NX)
3324///         .value_comparison(ValueComparison::ifeq("old_value"))
3325///         .get(true)
3326///         .with_expiration(SetExpiry::EX(60));
3327///     con.set_options(key, value, opts)
3328/// }
3329/// ```
3330#[derive(Clone, Default)]
3331pub struct SetOptions {
3332    conditional_set: Option<ExistenceCheck>,
3333    /// IFEQ `match-value` - Set the key's value and expiration only if its current value is equal to `match-value`.
3334    /// If the key doesn't exist, it won't be created.
3335    /// IFNE `match-value` - Set the key's value and expiration only if its current value is not equal to `match-value`.
3336    /// If the key doesn't exist, it will be created.
3337    /// IFDEQ `match-digest` - Set the key's value and expiration only if the digest of its current value is equal to `match-digest`.
3338    /// If the key doesn't exist, it won't be created.
3339    /// IFDNE `match-digest` - Set the key's value and expiration only if the digest of its current value is not equal to `match-digest`.
3340    /// If the key doesn't exist, it will be created.
3341    value_comparison: Option<ValueComparison>,
3342    get: bool,
3343    expiration: Option<SetExpiry>,
3344}
3345
3346impl SetOptions {
3347    /// Set the existence check for the SET command
3348    pub fn conditional_set(mut self, existence_check: ExistenceCheck) -> Self {
3349        self.conditional_set = Some(existence_check);
3350        self
3351    }
3352
3353    /// Set the value comparison for the SET command
3354    pub fn value_comparison(mut self, value_comparison: ValueComparison) -> Self {
3355        self.value_comparison = Some(value_comparison);
3356        self
3357    }
3358
3359    /// Set the GET option for the SET command
3360    pub fn get(mut self, get: bool) -> Self {
3361        self.get = get;
3362        self
3363    }
3364
3365    /// Set the expiration for the SET command
3366    pub fn with_expiration(mut self, expiration: SetExpiry) -> Self {
3367        self.expiration = Some(expiration);
3368        self
3369    }
3370}
3371
3372impl ToRedisArgs for SetOptions {
3373    fn write_redis_args<W>(&self, out: &mut W)
3374    where
3375        W: ?Sized + RedisWrite,
3376    {
3377        if let Some(ref conditional_set) = self.conditional_set {
3378            conditional_set.write_redis_args(out);
3379        }
3380        if let Some(ref value_comparison) = self.value_comparison {
3381            value_comparison.write_redis_args(out);
3382        }
3383        if self.get {
3384            out.write_arg(b"GET");
3385        }
3386        if let Some(ref expiration) = self.expiration {
3387            expiration.write_redis_args(out);
3388        }
3389    }
3390}
3391
3392/// Options for the [MSETEX](https://redis.io/commands/msetex) command
3393///
3394/// # Example
3395/// ```rust,no_run
3396/// use redis::{Commands, RedisResult, MSetOptions, SetExpiry, ExistenceCheck};
3397/// fn set_multiple_key_values(
3398///     con: &mut redis::Connection,
3399/// ) -> RedisResult<bool> {
3400///     let opts = MSetOptions::default()
3401///         .conditional_set(ExistenceCheck::NX)
3402///         .with_expiration(SetExpiry::EX(60));
3403///     con.mset_ex(&[("key1", "value1"), ("key2", "value2")], opts)
3404/// }
3405/// ```
3406#[derive(Clone, Copy, Default)]
3407pub struct MSetOptions {
3408    conditional_set: Option<ExistenceCheck>,
3409    expiration: Option<SetExpiry>,
3410}
3411
3412impl MSetOptions {
3413    /// Set the existence check for the MSETEX command
3414    pub fn conditional_set(mut self, existence_check: ExistenceCheck) -> Self {
3415        self.conditional_set = Some(existence_check);
3416        self
3417    }
3418
3419    /// Set the expiration for the MSETEX command
3420    pub fn with_expiration(mut self, expiration: SetExpiry) -> Self {
3421        self.expiration = Some(expiration);
3422        self
3423    }
3424}
3425
3426impl ToRedisArgs for MSetOptions {
3427    fn write_redis_args<W>(&self, out: &mut W)
3428    where
3429        W: ?Sized + RedisWrite,
3430    {
3431        if let Some(ref conditional_set) = self.conditional_set {
3432            conditional_set.write_redis_args(out);
3433        }
3434        if let Some(ref expiration) = self.expiration {
3435            expiration.write_redis_args(out);
3436        }
3437    }
3438}
3439
3440/// Options for the [FLUSHALL](https://redis.io/commands/flushall) command
3441///
3442/// # Example
3443/// ```rust,no_run
3444/// use redis::{Commands, RedisResult, FlushAllOptions};
3445/// fn flushall_sync(
3446///     con: &mut redis::Connection,
3447/// ) -> RedisResult<()> {
3448///     let opts = FlushAllOptions{blocking: true};
3449///     con.flushall_options(&opts)
3450/// }
3451/// ```
3452#[derive(Clone, Copy, Default)]
3453pub struct FlushAllOptions {
3454    /// Blocking (`SYNC`) waits for completion, non-blocking (`ASYNC`) runs in the background
3455    pub blocking: bool,
3456}
3457
3458impl FlushAllOptions {
3459    /// Set whether to run blocking (`SYNC`) or non-blocking (`ASYNC`) flush
3460    pub fn blocking(mut self, blocking: bool) -> Self {
3461        self.blocking = blocking;
3462        self
3463    }
3464}
3465
3466impl ToRedisArgs for FlushAllOptions {
3467    fn write_redis_args<W>(&self, out: &mut W)
3468    where
3469        W: ?Sized + RedisWrite,
3470    {
3471        if self.blocking {
3472            out.write_arg(b"SYNC");
3473        } else {
3474            out.write_arg(b"ASYNC");
3475        };
3476    }
3477}
3478impl ToSingleRedisArg for FlushAllOptions {}
3479
3480/// Options for the [FLUSHDB](https://redis.io/commands/flushdb) command
3481pub type FlushDbOptions = FlushAllOptions;
3482
3483/// Options for the HSETEX command
3484#[derive(Clone, Copy, Default)]
3485pub struct HashFieldExpirationOptions {
3486    existence_check: Option<FieldExistenceCheck>,
3487    expiration: Option<SetExpiry>,
3488}
3489
3490impl HashFieldExpirationOptions {
3491    /// Set the field(s) existence check for the HSETEX command
3492    pub fn set_existence_check(mut self, field_existence_check: FieldExistenceCheck) -> Self {
3493        self.existence_check = Some(field_existence_check);
3494        self
3495    }
3496
3497    /// Set the expiration option for the field(s) in the HSETEX command
3498    pub fn set_expiration(mut self, expiration: SetExpiry) -> Self {
3499        self.expiration = Some(expiration);
3500        self
3501    }
3502}
3503
3504impl ToRedisArgs for HashFieldExpirationOptions {
3505    fn write_redis_args<W>(&self, out: &mut W)
3506    where
3507        W: ?Sized + RedisWrite,
3508    {
3509        if let Some(ref existence_check) = self.existence_check {
3510            existence_check.write_redis_args(out);
3511        }
3512
3513        if let Some(ref expiration) = self.expiration {
3514            expiration.write_redis_args(out);
3515        }
3516    }
3517}
3518
3519impl ToRedisArgs for Expiry {
3520    fn write_redis_args<W>(&self, out: &mut W)
3521    where
3522        W: ?Sized + RedisWrite,
3523    {
3524        match self {
3525            Expiry::EX(sec) => {
3526                out.write_arg(b"EX");
3527                out.write_arg(sec.to_string().as_bytes());
3528            }
3529            Expiry::PX(ms) => {
3530                out.write_arg(b"PX");
3531                out.write_arg(ms.to_string().as_bytes());
3532            }
3533            Expiry::EXAT(timestamp_sec) => {
3534                out.write_arg(b"EXAT");
3535                out.write_arg(timestamp_sec.to_string().as_bytes());
3536            }
3537            Expiry::PXAT(timestamp_ms) => {
3538                out.write_arg(b"PXAT");
3539                out.write_arg(timestamp_ms.to_string().as_bytes());
3540            }
3541            Expiry::PERSIST => {
3542                out.write_arg(b"PERSIST");
3543            }
3544        }
3545    }
3546}
3547
3548/// Helper enum that is used to define update checks
3549#[derive(Clone, Copy)]
3550#[non_exhaustive]
3551pub enum UpdateCheck {
3552    /// LT -- Only update if the new score is less than the current.
3553    LT,
3554    /// GT -- Only update if the new score is greater than the current.
3555    GT,
3556}
3557
3558impl ToRedisArgs for UpdateCheck {
3559    fn write_redis_args<W>(&self, out: &mut W)
3560    where
3561        W: ?Sized + RedisWrite,
3562    {
3563        match self {
3564            UpdateCheck::LT => {
3565                out.write_arg(b"LT");
3566            }
3567            UpdateCheck::GT => {
3568                out.write_arg(b"GT");
3569            }
3570        }
3571    }
3572}
3573
3574/// Options for the [ZADD](https://redis.io/commands/zadd) command
3575#[derive(Clone, Copy, Default)]
3576pub struct SortedSetAddOptions {
3577    conditional_set: Option<ExistenceCheck>,
3578    conditional_update: Option<UpdateCheck>,
3579    include_changed: bool,
3580    increment: bool,
3581}
3582
3583impl SortedSetAddOptions {
3584    /// Sets the NX option for the ZADD command
3585    /// Only add a member if it does not already exist.
3586    pub fn add_only() -> Self {
3587        Self {
3588            conditional_set: Some(ExistenceCheck::NX),
3589            ..Default::default()
3590        }
3591    }
3592
3593    /// Sets the XX option and optionally the GT/LT option for the ZADD command
3594    /// Only update existing members
3595    pub fn update_only(conditional_update: Option<UpdateCheck>) -> Self {
3596        Self {
3597            conditional_set: Some(ExistenceCheck::XX),
3598            conditional_update,
3599            ..Default::default()
3600        }
3601    }
3602
3603    /// Optionally sets the GT/LT option for the ZADD command
3604    /// Add new member or update existing
3605    pub fn add_or_update(conditional_update: Option<UpdateCheck>) -> Self {
3606        Self {
3607            conditional_update,
3608            ..Default::default()
3609        }
3610    }
3611
3612    /// Sets the CH option for the ZADD command
3613    /// Return the number of elements changed (not just added).
3614    pub fn include_changed_count(mut self) -> Self {
3615        self.include_changed = true;
3616        self
3617    }
3618
3619    /// Sets the INCR option for the ZADD command
3620    /// Increment the score of the member instead of setting it.
3621    pub fn increment_score(mut self) -> Self {
3622        self.increment = true;
3623        self
3624    }
3625}
3626
3627impl ToRedisArgs for SortedSetAddOptions {
3628    fn write_redis_args<W>(&self, out: &mut W)
3629    where
3630        W: ?Sized + RedisWrite,
3631    {
3632        if let Some(ref conditional_set) = self.conditional_set {
3633            conditional_set.write_redis_args(out);
3634        }
3635
3636        if let Some(ref conditional_update) = self.conditional_update {
3637            conditional_update.write_redis_args(out);
3638        }
3639        if self.include_changed {
3640            out.write_arg(b"CH")
3641        }
3642        if self.increment {
3643            out.write_arg(b"INCR")
3644        }
3645    }
3646}
3647
3648/// Creates HELLO command for RESP3 with RedisConnectionInfo
3649/// [Redis Docs](https://redis.io/commands/HELLO)
3650pub fn resp3_hello(connection_info: &RedisConnectionInfo) -> Cmd {
3651    let mut hello_cmd = cmd("HELLO");
3652    hello_cmd.arg("3");
3653    if let Some(password) = &connection_info.password {
3654        let username: &str = match connection_info.username.as_ref() {
3655            None => "default",
3656            Some(username) => username,
3657        };
3658        hello_cmd.arg("AUTH").arg(username).arg(password.as_bytes());
3659    }
3660
3661    hello_cmd
3662}