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