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