Skip to main content

redis/commands/
mod.rs

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