redis/commands/
mod.rs

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