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] [KEEPREF | DELREF | ACKED] ...
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    /// An extension of the Streams `XDEL` command that provides finer control over how message entries are deleted with respect to consumer groups.
2170    #[cfg(feature = "streams")]
2171    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2172    fn xdel_ex<K: ToRedisArgs, ID: ToRedisArgs>(key: K, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XDelExStatusCode>) {
2173        cmd("XDELEX").arg(key).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2174    }
2175
2176    /// A combination of `XACK` and `XDEL` that acknowledges and attempts to delete a list of `ids` for a given stream `key` and consumer `group`.
2177    #[cfg(feature = "streams")]
2178    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2179    fn xack_del<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(key: K, group: G, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XAckDelStatusCode>) {
2180        cmd("XACKDEL").arg(key).arg(group).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2181    }
2182
2183    /// This command is used for creating a consumer `group`. It expects the stream key
2184    /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
2185    /// The `id` is the starting message id all consumers should read from. Use `$` If you want
2186    /// all consumers to read from the last message added to stream.
2187    ///
2188    /// ```text
2189    /// XGROUP CREATE <key> <groupname> <id or $>
2190    /// ```
2191    /// [Redis Docs](https://redis.io/commands/XGROUP)
2192    #[cfg(feature = "streams")]
2193    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2194    fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2195        key: K,
2196        group: G,
2197        id: ID
2198    ) -> () {
2199        cmd("XGROUP")
2200            .arg("CREATE")
2201            .arg(key)
2202            .arg(group)
2203            .arg(id)
2204    }
2205
2206    /// This creates a `consumer` explicitly (vs implicit via XREADGROUP)
2207    /// for given stream `key.
2208    ///
2209    /// The return value is either a 0 or a 1 for the number of consumers created
2210    /// 0 means the consumer already exists
2211    ///
2212    /// ```text
2213    /// XGROUP CREATECONSUMER <key> <groupname> <consumername>
2214    /// ```
2215    /// [Redis Docs](https://redis.io/commands/XGROUP)
2216    #[cfg(feature = "streams")]
2217    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2218    fn xgroup_createconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2219        key: K,
2220        group: G,
2221        consumer: C
2222    ) -> bool {
2223        cmd("XGROUP")
2224            .arg("CREATECONSUMER")
2225            .arg(key)
2226            .arg(group)
2227            .arg(consumer)
2228    }
2229
2230    /// This is the alternate version for creating a consumer `group`
2231    /// which makes the stream if it doesn't exist.
2232    ///
2233    /// ```text
2234    /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
2235    /// ```
2236    /// [Redis Docs](https://redis.io/commands/XGROUP)
2237    #[cfg(feature = "streams")]
2238    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2239    fn xgroup_create_mkstream<
2240        K: ToRedisArgs,
2241        G: ToRedisArgs,
2242        ID: ToRedisArgs
2243    >(
2244        key: K,
2245        group: G,
2246        id: ID
2247    ) -> () {
2248        cmd("XGROUP")
2249            .arg("CREATE")
2250            .arg(key)
2251            .arg(group)
2252            .arg(id)
2253            .arg("MKSTREAM")
2254    }
2255
2256
2257    /// Alter which `id` you want consumers to begin reading from an existing
2258    /// consumer `group`.
2259    ///
2260    /// ```text
2261    /// XGROUP SETID <key> <groupname> <id or $>
2262    /// ```
2263    /// [Redis Docs](https://redis.io/commands/XGROUP)
2264    #[cfg(feature = "streams")]
2265    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2266    fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2267        key: K,
2268        group: G,
2269        id: ID
2270    ) -> () {
2271        cmd("XGROUP")
2272            .arg("SETID")
2273            .arg(key)
2274            .arg(group)
2275            .arg(id)
2276    }
2277
2278
2279    /// Destroy an existing consumer `group` for a given stream `key`
2280    ///
2281    /// ```text
2282    /// XGROUP SETID <key> <groupname> <id or $>
2283    /// ```
2284    /// [Redis Docs](https://redis.io/commands/XGROUP)
2285    #[cfg(feature = "streams")]
2286    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2287    fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
2288        key: K,
2289        group: G
2290    ) -> bool {
2291        cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
2292    }
2293
2294    /// This deletes a `consumer` from an existing consumer `group`
2295    /// for given stream `key.
2296    ///
2297    /// ```text
2298    /// XGROUP DELCONSUMER <key> <groupname> <consumername>
2299    /// ```
2300    /// [Redis Docs](https://redis.io/commands/XGROUP)
2301    #[cfg(feature = "streams")]
2302    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2303    fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2304        key: K,
2305        group: G,
2306        consumer: C
2307    ) -> usize {
2308        cmd("XGROUP")
2309            .arg("DELCONSUMER")
2310            .arg(key)
2311            .arg(group)
2312            .arg(consumer)
2313    }
2314
2315
2316    /// This returns all info details about
2317    /// which consumers have read messages for given consumer `group`.
2318    /// Take note of the StreamInfoConsumersReply return type.
2319    ///
2320    /// *It's possible this return value might not contain new fields
2321    /// added by Redis in future versions.*
2322    ///
2323    /// ```text
2324    /// XINFO CONSUMERS <key> <group>
2325    /// ```
2326    /// [Redis Docs](https://redis.io/commands/XINFO")
2327    #[cfg(feature = "streams")]
2328    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2329    fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
2330        key: K,
2331        group: G
2332    ) -> (streams::StreamInfoConsumersReply) {
2333        cmd("XINFO")
2334            .arg("CONSUMERS")
2335            .arg(key)
2336            .arg(group)
2337    }
2338
2339
2340    /// Returns all consumer `group`s created for a given stream `key`.
2341    /// Take note of the StreamInfoGroupsReply return type.
2342    ///
2343    /// *It's possible this return value might not contain new fields
2344    /// added by Redis in future versions.*
2345    ///
2346    /// ```text
2347    /// XINFO GROUPS <key>
2348    /// ```
2349    /// [Redis Docs](https://redis.io/commands/XINFO-GROUPS)
2350    #[cfg(feature = "streams")]
2351    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2352    fn xinfo_groups<K: ToRedisArgs>(key: K) -> (streams::StreamInfoGroupsReply) {
2353        cmd("XINFO").arg("GROUPS").arg(key)
2354    }
2355
2356
2357    /// Returns info about high-level stream details
2358    /// (first & last message `id`, length, number of groups, etc.)
2359    /// Take note of the StreamInfoStreamReply return type.
2360    ///
2361    /// *It's possible this return value might not contain new fields
2362    /// added by Redis in future versions.*
2363    ///
2364    /// ```text
2365    /// XINFO STREAM <key>
2366    /// ```
2367    /// [Redis Docs](https://redis.io/commands/XINFO-STREAM)
2368    #[cfg(feature = "streams")]
2369    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2370    fn xinfo_stream<K: ToRedisArgs>(key: K) -> (streams::StreamInfoStreamReply) {
2371        cmd("XINFO").arg("STREAM").arg(key)
2372    }
2373
2374    /// Returns the number of messages for a given stream `key`.
2375    ///
2376    /// ```text
2377    /// XLEN <key>
2378    /// ```
2379    #[cfg(feature = "streams")]
2380    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2381    /// [Redis Docs](https://redis.io/commands/XLEN)
2382    fn xlen<K: ToRedisArgs>(key: K) -> usize {
2383        cmd("XLEN").arg(key)
2384    }
2385
2386
2387    /// This is a basic version of making XPENDING command calls which only
2388    /// passes a stream `key` and consumer `group` and it
2389    /// returns details about which consumers have pending messages
2390    /// that haven't been acked.
2391    ///
2392    /// You can use this method along with
2393    /// `xclaim` or `xclaim_options` for determining which messages
2394    /// need to be retried.
2395    ///
2396    /// Take note of the StreamPendingReply return type.
2397    ///
2398    /// ```text
2399    /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
2400    /// ```
2401    /// [Redis Docs](https://redis.io/commands/XPENDING)
2402    #[cfg(feature = "streams")]
2403    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2404    fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
2405        key: K,
2406        group: G
2407    ) -> (streams::StreamPendingReply) {
2408        cmd("XPENDING").arg(key).arg(group)
2409    }
2410
2411
2412    /// This XPENDING version returns a list of all messages over the range.
2413    /// You can use this for paginating pending messages (but without the message HashMap).
2414    ///
2415    /// Start and end follow the same rules `xrange` args. Set start to `-`
2416    /// and end to `+` for the entire stream.
2417    ///
2418    /// Take note of the StreamPendingCountReply return type.
2419    ///
2420    /// ```text
2421    /// XPENDING <key> <group> <start> <stop> <count>
2422    /// ```
2423    /// [Redis Docs](https://redis.io/commands/XPENDING)
2424    #[cfg(feature = "streams")]
2425    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2426    fn xpending_count<
2427        K: ToRedisArgs,
2428        G: ToRedisArgs,
2429        S: ToRedisArgs,
2430        E: ToRedisArgs,
2431        C: ToRedisArgs
2432    >(
2433        key: K,
2434        group: G,
2435        start: S,
2436        end: E,
2437        count: C
2438    ) -> (streams::StreamPendingCountReply) {
2439        cmd("XPENDING")
2440            .arg(key)
2441            .arg(group)
2442            .arg(start)
2443            .arg(end)
2444            .arg(count)
2445    }
2446
2447
2448    /// An alternate version of `xpending_count` which filters by `consumer` name.
2449    ///
2450    /// Start and end follow the same rules `xrange` args. Set start to `-`
2451    /// and end to `+` for the entire stream.
2452    ///
2453    /// Take note of the StreamPendingCountReply return type.
2454    ///
2455    /// ```text
2456    /// XPENDING <key> <group> <start> <stop> <count> <consumer>
2457    /// ```
2458    /// [Redis Docs](https://redis.io/commands/XPENDING)
2459    #[cfg(feature = "streams")]
2460    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2461    fn xpending_consumer_count<
2462        K: ToRedisArgs,
2463        G: ToRedisArgs,
2464        S: ToRedisArgs,
2465        E: ToRedisArgs,
2466        C: ToRedisArgs,
2467        CN: ToRedisArgs
2468    >(
2469        key: K,
2470        group: G,
2471        start: S,
2472        end: E,
2473        count: C,
2474        consumer: CN
2475    ) -> (streams::StreamPendingCountReply) {
2476        cmd("XPENDING")
2477            .arg(key)
2478            .arg(group)
2479            .arg(start)
2480            .arg(end)
2481            .arg(count)
2482            .arg(consumer)
2483    }
2484
2485    /// Returns a range of messages in a given stream `key`.
2486    ///
2487    /// Set `start` to `-` to begin at the first message.
2488    /// Set `end` to `+` to end the most recent message.
2489    /// You can pass message `id` to both `start` and `end`.
2490    ///
2491    /// Take note of the StreamRangeReply return type.
2492    ///
2493    /// ```text
2494    /// XRANGE key start end
2495    /// ```
2496    /// [Redis Docs](https://redis.io/commands/XRANGE)
2497    #[cfg(feature = "streams")]
2498    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2499    fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
2500        key: K,
2501        start: S,
2502        end: E
2503    ) -> (streams::StreamRangeReply) {
2504        cmd("XRANGE").arg(key).arg(start).arg(end)
2505    }
2506
2507
2508    /// A helper method for automatically returning all messages in a stream by `key`.
2509    /// **Use with caution!**
2510    ///
2511    /// ```text
2512    /// XRANGE key - +
2513    /// ```
2514    /// [Redis Docs](https://redis.io/commands/XRANGE)
2515    #[cfg(feature = "streams")]
2516    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2517    fn xrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2518        cmd("XRANGE").arg(key).arg("-").arg("+")
2519    }
2520
2521
2522    /// A method for paginating a stream by `key`.
2523    ///
2524    /// ```text
2525    /// XRANGE key start end [COUNT <n>]
2526    /// ```
2527    /// [Redis Docs](https://redis.io/commands/XRANGE)
2528    #[cfg(feature = "streams")]
2529    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2530    fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
2531        key: K,
2532        start: S,
2533        end: E,
2534        count: C
2535    ) -> (streams::StreamRangeReply) {
2536        cmd("XRANGE")
2537            .arg(key)
2538            .arg(start)
2539            .arg(end)
2540            .arg("COUNT")
2541            .arg(count)
2542    }
2543
2544
2545    /// Read a list of `id`s for each stream `key`.
2546    /// This is the basic form of reading streams.
2547    /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
2548    /// see `xread_options`.
2549    ///
2550    /// ```text
2551    /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
2552    /// ```
2553    /// [Redis Docs](https://redis.io/commands/XREAD)
2554    #[cfg(feature = "streams")]
2555    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2556    fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
2557        keys: &'a [K],
2558        ids: &'a [ID]
2559    ) -> (Option<streams::StreamReadReply>) {
2560        cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
2561    }
2562
2563    /// This method handles setting optional arguments for
2564    /// `XREAD` or `XREADGROUP` Redis commands.
2565    /// ```no_run
2566    /// use redis::{Connection,RedisResult,Commands};
2567    /// use redis::streams::{StreamReadOptions,StreamReadReply};
2568    /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2569    /// let mut con = client.get_connection().unwrap();
2570    ///
2571    /// // Read 10 messages from the start of the stream,
2572    /// // without registering as a consumer group.
2573    ///
2574    /// let opts = StreamReadOptions::default()
2575    ///     .count(10);
2576    /// let results: RedisResult<StreamReadReply> =
2577    ///     con.xread_options(&["k1"], &["0"], &opts);
2578    ///
2579    /// // Read all undelivered messages for a given
2580    /// // consumer group. Be advised: the consumer group must already
2581    /// // exist before making this call. Also note: we're passing
2582    /// // '>' as the id here, which means all undelivered messages.
2583    ///
2584    /// let opts = StreamReadOptions::default()
2585    ///     .group("group-1", "consumer-1");
2586    /// let results: RedisResult<StreamReadReply> =
2587    ///     con.xread_options(&["k1"], &[">"], &opts);
2588    /// ```
2589    ///
2590    /// ```text
2591    /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
2592    ///     STREAMS key_1 key_2 ... key_N
2593    ///     ID_1 ID_2 ... ID_N
2594    ///
2595    /// XREADGROUP [GROUP group-name consumer-name] [BLOCK <milliseconds>] [COUNT <count>] [NOACK]
2596    ///     STREAMS key_1 key_2 ... key_N
2597    ///     ID_1 ID_2 ... ID_N
2598    /// ```
2599    /// [Redis Docs](https://redis.io/commands/XREAD)
2600    #[cfg(feature = "streams")]
2601    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2602    fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
2603        keys: &'a [K],
2604        ids: &'a [ID],
2605        options: &'a streams::StreamReadOptions
2606    ) -> (Option<streams::StreamReadReply>) {
2607        cmd(if options.read_only() {
2608            "XREAD"
2609        } else {
2610            "XREADGROUP"
2611        })
2612        .arg(options)
2613        .arg("STREAMS")
2614        .arg(keys)
2615        .arg(ids)
2616    }
2617
2618    /// This is the reverse version of `xrange`.
2619    /// The same rules apply for `start` and `end` here.
2620    ///
2621    /// ```text
2622    /// XREVRANGE key end start
2623    /// ```
2624    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2625    #[cfg(feature = "streams")]
2626    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2627    fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
2628        key: K,
2629        end: E,
2630        start: S
2631    ) -> (streams::StreamRangeReply) {
2632        cmd("XREVRANGE").arg(key).arg(end).arg(start)
2633    }
2634
2635    /// This is the reverse version of `xrange_all`.
2636    /// The same rules apply for `start` and `end` here.
2637    ///
2638    /// ```text
2639    /// XREVRANGE key + -
2640    /// ```
2641    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2642    #[cfg(feature = "streams")]
2643    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2644    fn xrevrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2645        cmd("XREVRANGE").arg(key).arg("+").arg("-")
2646    }
2647
2648    /// This is the reverse version of `xrange_count`.
2649    /// The same rules apply for `start` and `end` here.
2650    ///
2651    /// ```text
2652    /// XREVRANGE key end start [COUNT <n>]
2653    /// ```
2654    /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2655    #[cfg(feature = "streams")]
2656    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2657    fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
2658        key: K,
2659        end: E,
2660        start: S,
2661        count: C
2662    ) -> (streams::StreamRangeReply) {
2663        cmd("XREVRANGE")
2664            .arg(key)
2665            .arg(end)
2666            .arg(start)
2667            .arg("COUNT")
2668            .arg(count)
2669    }
2670
2671    /// Trim a stream `key` to a MAXLEN count.
2672    ///
2673    /// ```text
2674    /// XTRIM <key> MAXLEN [~|=] <count>  (Same as XADD MAXLEN option)
2675    /// ```
2676    /// [Redis Docs](https://redis.io/commands/XTRIM)
2677    #[cfg(feature = "streams")]
2678    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2679    fn xtrim<K: ToRedisArgs>(
2680        key: K,
2681        maxlen: streams::StreamMaxlen
2682    ) -> usize {
2683        cmd("XTRIM").arg(key).arg(maxlen)
2684    }
2685
2686     /// Trim a stream `key` with full options
2687     ///
2688     /// ```text
2689     /// XTRIM <key> <MAXLEN|MINID> [~|=] <threshold> [LIMIT <count>]  (Same as XADD MAXID|MINID options) [KEEPREF | DELREF | ACKED]
2690     /// ```
2691     /// [Redis Docs](https://redis.io/commands/XTRIM)
2692    #[cfg(feature = "streams")]
2693    #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2694    fn xtrim_options<K: ToRedisArgs>(
2695        key: K,
2696        options: &'a streams::StreamTrimOptions
2697    ) -> usize {
2698        cmd("XTRIM").arg(key).arg(options)
2699    }
2700
2701    // script commands
2702
2703    /// Load a script.
2704    ///
2705    /// See [`invoke_script`](Self::invoke_script) to actually run the scripts.
2706    #[cfg_attr(feature = "script", doc = r##"
2707
2708# Examples:
2709
2710```rust,no_run
2711# fn do_something() -> redis::RedisResult<()> {
2712# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2713# let mut con = client.get_connection().unwrap();
2714let script = redis::Script::new(r"
2715    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2716");
2717let (load_res, invok_res): (String, isize) = redis::pipe()
2718    .load_script(&script)
2719    .invoke_script(script.arg(1).arg(2))
2720    .query(&mut con)?;
2721
2722assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2723assert_eq!(invok_res, 3);
2724# Ok(()) }
2725```
2726"##)]
2727    #[cfg(feature = "script")]
2728    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2729    fn load_script<>(script: &'a crate::Script) -> Generic {
2730        &mut script.load_cmd()
2731    }
2732
2733    /// Invoke a prepared script.
2734    ///
2735    /// Note: Unlike[`ScriptInvocation::invoke`](crate::ScriptInvocation::invoke), this function
2736    /// does _not_ automatically load the script. If the invoked script did not get loaded beforehand, you
2737    /// need to manually load it (e.g.: using [`load_script`](Self::load_script) or
2738    /// [`ScriptInvocation::load`](crate::ScriptInvocation::load)). Otherwise this command will fail.
2739    #[cfg_attr(feature = "script", doc = r##"
2740
2741# Examples:
2742
2743```rust,no_run
2744# fn do_something() -> redis::RedisResult<()> {
2745# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2746# let mut con = client.get_connection().unwrap();
2747let script = redis::Script::new(r"
2748    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2749");
2750let (load_res, invok_1_res, invok_2_res): (String, isize, isize) = redis::pipe()
2751    .load_script(&script)
2752    .invoke_script(script.arg(1).arg(2))
2753    .invoke_script(script.arg(2).arg(3))
2754    .query(&mut con)?;
2755
2756assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2757assert_eq!(invok_1_res, 3);
2758assert_eq!(invok_2_res, 5);
2759# Ok(()) }
2760```
2761"##)]
2762    #[cfg(feature = "script")]
2763    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2764    fn invoke_script<>(invocation: &'a crate::ScriptInvocation<'a>) -> Generic {
2765        &mut invocation.eval_cmd()
2766    }
2767
2768    // cleanup commands
2769
2770    /// Deletes all the keys of all databases
2771    ///
2772    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2773    /// of your Redis server.
2774    ///
2775    /// To enforce a flush mode, use [`Commands::flushall_options`].
2776    ///
2777    /// ```text
2778    /// FLUSHALL
2779    /// ```
2780    /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2781    fn flushall<>() -> () {
2782        &mut cmd("FLUSHALL")
2783    }
2784
2785    /// Deletes all the keys of all databases with options
2786    ///
2787    /// ```text
2788    /// FLUSHALL [ASYNC|SYNC]
2789    /// ```
2790    /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2791    fn flushall_options<>(options: &'a FlushAllOptions) -> () {
2792        cmd("FLUSHALL").arg(options)
2793    }
2794
2795    /// Deletes all the keys of the current database
2796    ///
2797    /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2798    /// of your Redis server.
2799    ///
2800    /// To enforce a flush mode, use [`Commands::flushdb_options`].
2801    ///
2802    /// ```text
2803    /// FLUSHDB
2804    /// ```
2805    /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2806    fn flushdb<>() -> () {
2807        &mut cmd("FLUSHDB")
2808    }
2809
2810    /// Deletes all the keys of the current database with options
2811    ///
2812    /// ```text
2813    /// FLUSHDB [ASYNC|SYNC]
2814    /// ```
2815    /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2816    fn flushdb_options<>(options: &'a FlushDbOptions) -> () {
2817        cmd("FLUSHDB").arg(options)
2818    }
2819}
2820
2821/// Allows pubsub callbacks to stop receiving messages.
2822///
2823/// Arbitrary data may be returned from `Break`.
2824pub enum ControlFlow<U> {
2825    /// Continues.
2826    Continue,
2827    /// Breaks with a value.
2828    Break(U),
2829}
2830
2831/// The PubSub trait allows subscribing to one or more channels
2832/// and receiving a callback whenever a message arrives.
2833///
2834/// Each method handles subscribing to the list of keys, waiting for
2835/// messages, and unsubscribing from the same list of channels once
2836/// a ControlFlow::Break is encountered.
2837///
2838/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2839/// for calling other methods.
2840///
2841/// # Examples
2842///
2843/// ```rust,no_run
2844/// # fn do_something() -> redis::RedisResult<()> {
2845/// use redis::{PubSubCommands, ControlFlow};
2846/// let client = redis::Client::open("redis://127.0.0.1/")?;
2847/// let mut con = client.get_connection()?;
2848/// let mut count = 0;
2849/// con.subscribe(&["foo"], |msg| {
2850///     // do something with message
2851///     assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2852///
2853///     // increment messages seen counter
2854///     count += 1;
2855///     match count {
2856///         // stop after receiving 10 messages
2857///         10 => ControlFlow::Break(()),
2858///         _ => ControlFlow::Continue,
2859///     }
2860/// })?;
2861/// # Ok(()) }
2862/// ```
2863// TODO In the future, it would be nice to implement Try such that `?` will work
2864//      within the closure.
2865pub trait PubSubCommands: Sized {
2866    /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2867    /// closure for each message received.
2868    ///
2869    /// For every `Msg` passed to the provided closure, either
2870    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2871    /// method will not return until `ControlFlow::Break` is observed.
2872    fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2873    where
2874        F: FnMut(Msg) -> ControlFlow<U>,
2875        C: ToRedisArgs;
2876
2877    /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
2878    /// closure for each message received.
2879    ///
2880    /// For every `Msg` passed to the provided closure, either
2881    /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2882    /// method will not return until `ControlFlow::Break` is observed.
2883    fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
2884    where
2885        F: FnMut(Msg) -> ControlFlow<U>,
2886        P: ToRedisArgs;
2887}
2888
2889impl<T> Commands for T where T: ConnectionLike {}
2890
2891#[cfg(feature = "aio")]
2892impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
2893
2894impl<T> TypedCommands for T where T: ConnectionLike {}
2895
2896#[cfg(feature = "aio")]
2897impl<T> AsyncTypedCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
2898
2899impl PubSubCommands for Connection {
2900    fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
2901    where
2902        F: FnMut(Msg) -> ControlFlow<U>,
2903        C: ToRedisArgs,
2904    {
2905        let mut pubsub = self.as_pubsub();
2906        pubsub.subscribe(channels)?;
2907
2908        loop {
2909            let msg = pubsub.get_message()?;
2910            match func(msg) {
2911                ControlFlow::Continue => continue,
2912                ControlFlow::Break(value) => return Ok(value),
2913            }
2914        }
2915    }
2916
2917    fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
2918    where
2919        F: FnMut(Msg) -> ControlFlow<U>,
2920        P: ToRedisArgs,
2921    {
2922        let mut pubsub = self.as_pubsub();
2923        pubsub.psubscribe(patterns)?;
2924
2925        loop {
2926            let msg = pubsub.get_message()?;
2927            match func(msg) {
2928                ControlFlow::Continue => continue,
2929                ControlFlow::Break(value) => return Ok(value),
2930            }
2931        }
2932    }
2933}
2934
2935/// Options for the [SCAN](https://redis.io/commands/scan) command
2936///
2937/// # Example
2938///
2939/// ```rust
2940/// use redis::{Commands, RedisResult, ScanOptions, Iter};
2941/// fn force_fetching_every_matching_key<'a, T: redis::FromRedisValue>(
2942///     con: &'a mut redis::Connection,
2943///     pattern: &'a str,
2944///     count: usize,
2945/// ) -> RedisResult<Iter<'a, T>> {
2946///     let opts = ScanOptions::default()
2947///         .with_pattern(pattern)
2948///         .with_count(count);
2949///     con.scan_options(opts)
2950/// }
2951/// ```
2952#[derive(Default)]
2953pub struct ScanOptions {
2954    pattern: Option<String>,
2955    count: Option<usize>,
2956    scan_type: Option<String>,
2957}
2958
2959impl ScanOptions {
2960    /// Limit the results to the first N matching items.
2961    pub fn with_count(mut self, n: usize) -> Self {
2962        self.count = Some(n);
2963        self
2964    }
2965
2966    /// Pattern for scan
2967    pub fn with_pattern(mut self, p: impl Into<String>) -> Self {
2968        self.pattern = Some(p.into());
2969        self
2970    }
2971
2972    /// Limit the results to those with the given Redis type
2973    pub fn with_type(mut self, t: impl Into<String>) -> Self {
2974        self.scan_type = Some(t.into());
2975        self
2976    }
2977}
2978
2979impl ToRedisArgs for ScanOptions {
2980    fn write_redis_args<W>(&self, out: &mut W)
2981    where
2982        W: ?Sized + RedisWrite,
2983    {
2984        if let Some(p) = &self.pattern {
2985            out.write_arg(b"MATCH");
2986            out.write_arg_fmt(p);
2987        }
2988
2989        if let Some(n) = self.count {
2990            out.write_arg(b"COUNT");
2991            out.write_arg_fmt(n);
2992        }
2993
2994        if let Some(t) = &self.scan_type {
2995            out.write_arg(b"TYPE");
2996            out.write_arg_fmt(t);
2997        }
2998    }
2999
3000    fn num_of_args(&self) -> usize {
3001        let mut len = 0;
3002        if self.pattern.is_some() {
3003            len += 2;
3004        }
3005        if self.count.is_some() {
3006            len += 2;
3007        }
3008        if self.scan_type.is_some() {
3009            len += 2;
3010        }
3011        len
3012    }
3013}
3014
3015/// Options for the [LPOS](https://redis.io/commands/lpos) command
3016///
3017/// # Example
3018///
3019/// ```rust,no_run
3020/// use redis::{Commands, RedisResult, LposOptions};
3021/// fn fetch_list_position(
3022///     con: &mut redis::Connection,
3023///     key: &str,
3024///     value: &str,
3025///     count: usize,
3026///     rank: isize,
3027///     maxlen: usize,
3028/// ) -> RedisResult<Vec<usize>> {
3029///     let opts = LposOptions::default()
3030///         .count(count)
3031///         .rank(rank)
3032///         .maxlen(maxlen);
3033///     con.lpos(key, value, opts)
3034/// }
3035/// ```
3036#[derive(Default)]
3037pub struct LposOptions {
3038    count: Option<usize>,
3039    maxlen: Option<usize>,
3040    rank: Option<isize>,
3041}
3042
3043impl LposOptions {
3044    /// Limit the results to the first N matching items.
3045    pub fn count(mut self, n: usize) -> Self {
3046        self.count = Some(n);
3047        self
3048    }
3049
3050    /// Return the value of N from the matching items.
3051    pub fn rank(mut self, n: isize) -> Self {
3052        self.rank = Some(n);
3053        self
3054    }
3055
3056    /// Limit the search to N items in the list.
3057    pub fn maxlen(mut self, n: usize) -> Self {
3058        self.maxlen = Some(n);
3059        self
3060    }
3061}
3062
3063impl ToRedisArgs for LposOptions {
3064    fn write_redis_args<W>(&self, out: &mut W)
3065    where
3066        W: ?Sized + RedisWrite,
3067    {
3068        if let Some(n) = self.count {
3069            out.write_arg(b"COUNT");
3070            out.write_arg_fmt(n);
3071        }
3072
3073        if let Some(n) = self.rank {
3074            out.write_arg(b"RANK");
3075            out.write_arg_fmt(n);
3076        }
3077
3078        if let Some(n) = self.maxlen {
3079            out.write_arg(b"MAXLEN");
3080            out.write_arg_fmt(n);
3081        }
3082    }
3083
3084    fn num_of_args(&self) -> usize {
3085        let mut len = 0;
3086        if self.count.is_some() {
3087            len += 2;
3088        }
3089        if self.rank.is_some() {
3090            len += 2;
3091        }
3092        if self.maxlen.is_some() {
3093            len += 2;
3094        }
3095        len
3096    }
3097}
3098
3099/// Enum for the LEFT | RIGHT args used by some commands
3100pub enum Direction {
3101    /// Targets the first element (head) of the list
3102    Left,
3103    /// Targets the last element (tail) of the list
3104    Right,
3105}
3106
3107impl ToRedisArgs for Direction {
3108    fn write_redis_args<W>(&self, out: &mut W)
3109    where
3110        W: ?Sized + RedisWrite,
3111    {
3112        let s: &[u8] = match self {
3113            Direction::Left => b"LEFT",
3114            Direction::Right => b"RIGHT",
3115        };
3116        out.write_arg(s);
3117    }
3118}
3119
3120/// Options for the [COPY](https://redis.io/commands/copy) command
3121///
3122/// # Example
3123/// ```rust,no_run
3124/// use redis::{Commands, RedisResult, CopyOptions, SetExpiry, ExistenceCheck};
3125/// fn copy_value(
3126///     con: &mut redis::Connection,
3127///     old: &str,
3128///     new: &str,
3129/// ) -> RedisResult<Vec<usize>> {
3130///     let opts = CopyOptions::default()
3131///         .db("my_other_db")
3132///         .replace(true);
3133///     con.copy(old, new, opts)
3134/// }
3135/// ```
3136#[derive(Clone, Copy, Debug)]
3137pub struct CopyOptions<Db: ToString> {
3138    db: Option<Db>,
3139    replace: bool,
3140}
3141
3142impl Default for CopyOptions<&'static str> {
3143    fn default() -> Self {
3144        CopyOptions {
3145            db: None,
3146            replace: false,
3147        }
3148    }
3149}
3150
3151impl<Db: ToString> CopyOptions<Db> {
3152    /// Set the target database for the copy operation
3153    pub fn db<Db2: ToString>(self, db: Db2) -> CopyOptions<Db2> {
3154        CopyOptions {
3155            db: Some(db),
3156            replace: self.replace,
3157        }
3158    }
3159
3160    /// Set the replace option for the copy operation
3161    pub fn replace(mut self, replace: bool) -> Self {
3162        self.replace = replace;
3163        self
3164    }
3165}
3166
3167impl<Db: ToString> ToRedisArgs for CopyOptions<Db> {
3168    fn write_redis_args<W>(&self, out: &mut W)
3169    where
3170        W: ?Sized + RedisWrite,
3171    {
3172        if let Some(db) = &self.db {
3173            out.write_arg(b"DB");
3174            out.write_arg(db.to_string().as_bytes());
3175        }
3176        if self.replace {
3177            out.write_arg(b"REPLACE");
3178        }
3179    }
3180}
3181
3182/// Options for the [SET](https://redis.io/commands/set) command
3183///
3184/// # Example
3185/// ```rust,no_run
3186/// use redis::{Commands, RedisResult, SetOptions, SetExpiry, ExistenceCheck};
3187/// fn set_key_value(
3188///     con: &mut redis::Connection,
3189///     key: &str,
3190///     value: &str,
3191/// ) -> RedisResult<Vec<usize>> {
3192///     let opts = SetOptions::default()
3193///         .conditional_set(ExistenceCheck::NX)
3194///         .get(true)
3195///         .with_expiration(SetExpiry::EX(60));
3196///     con.set_options(key, value, opts)
3197/// }
3198/// ```
3199#[derive(Clone, Copy, Default)]
3200pub struct SetOptions {
3201    conditional_set: Option<ExistenceCheck>,
3202    get: bool,
3203    expiration: Option<SetExpiry>,
3204}
3205
3206impl SetOptions {
3207    /// Set the existence check for the SET command
3208    pub fn conditional_set(mut self, existence_check: ExistenceCheck) -> Self {
3209        self.conditional_set = Some(existence_check);
3210        self
3211    }
3212
3213    /// Set the GET option for the SET command
3214    pub fn get(mut self, get: bool) -> Self {
3215        self.get = get;
3216        self
3217    }
3218
3219    /// Set the expiration for the SET command
3220    pub fn with_expiration(mut self, expiration: SetExpiry) -> Self {
3221        self.expiration = Some(expiration);
3222        self
3223    }
3224}
3225
3226impl ToRedisArgs for SetOptions {
3227    fn write_redis_args<W>(&self, out: &mut W)
3228    where
3229        W: ?Sized + RedisWrite,
3230    {
3231        if let Some(ref conditional_set) = self.conditional_set {
3232            match conditional_set {
3233                ExistenceCheck::NX => {
3234                    out.write_arg(b"NX");
3235                }
3236                ExistenceCheck::XX => {
3237                    out.write_arg(b"XX");
3238                }
3239            }
3240        }
3241        if self.get {
3242            out.write_arg(b"GET");
3243        }
3244        if let Some(ref expiration) = self.expiration {
3245            match expiration {
3246                SetExpiry::EX(secs) => {
3247                    out.write_arg(b"EX");
3248                    out.write_arg(format!("{secs}").as_bytes());
3249                }
3250                SetExpiry::PX(millis) => {
3251                    out.write_arg(b"PX");
3252                    out.write_arg(format!("{millis}").as_bytes());
3253                }
3254                SetExpiry::EXAT(unix_time) => {
3255                    out.write_arg(b"EXAT");
3256                    out.write_arg(format!("{unix_time}").as_bytes());
3257                }
3258                SetExpiry::PXAT(unix_time) => {
3259                    out.write_arg(b"PXAT");
3260                    out.write_arg(format!("{unix_time}").as_bytes());
3261                }
3262                SetExpiry::KEEPTTL => {
3263                    out.write_arg(b"KEEPTTL");
3264                }
3265            }
3266        }
3267    }
3268}
3269
3270/// Options for the [FLUSHALL](https://redis.io/commands/flushall) command
3271///
3272/// # Example
3273/// ```rust,no_run
3274/// use redis::{Commands, RedisResult, FlushAllOptions};
3275/// fn flushall_sync(
3276///     con: &mut redis::Connection,
3277/// ) -> RedisResult<()> {
3278///     let opts = FlushAllOptions{blocking: true};
3279///     con.flushall_options(&opts)
3280/// }
3281/// ```
3282#[derive(Clone, Copy, Default)]
3283pub struct FlushAllOptions {
3284    /// Blocking (`SYNC`) waits for completion, non-blocking (`ASYNC`) runs in the background
3285    pub blocking: bool,
3286}
3287
3288impl FlushAllOptions {
3289    /// Set whether to run blocking (`SYNC`) or non-blocking (`ASYNC`) flush
3290    pub fn blocking(mut self, blocking: bool) -> Self {
3291        self.blocking = blocking;
3292        self
3293    }
3294}
3295
3296impl ToRedisArgs for FlushAllOptions {
3297    fn write_redis_args<W>(&self, out: &mut W)
3298    where
3299        W: ?Sized + RedisWrite,
3300    {
3301        if self.blocking {
3302            out.write_arg(b"SYNC");
3303        } else {
3304            out.write_arg(b"ASYNC");
3305        };
3306    }
3307}
3308
3309/// Options for the [FLUSHDB](https://redis.io/commands/flushdb) command
3310pub type FlushDbOptions = FlushAllOptions;
3311
3312/// Options for the HSETEX command
3313#[derive(Clone, Copy, Default)]
3314pub struct HashFieldExpirationOptions {
3315    existence_check: Option<FieldExistenceCheck>,
3316    expiration: Option<SetExpiry>,
3317}
3318
3319impl HashFieldExpirationOptions {
3320    /// Set the field(s) existence check for the HSETEX command
3321    pub fn set_existence_check(mut self, field_existence_check: FieldExistenceCheck) -> Self {
3322        self.existence_check = Some(field_existence_check);
3323        self
3324    }
3325
3326    /// Set the expiration option for the field(s) in the HSETEX command
3327    pub fn set_expiration(mut self, expiration: SetExpiry) -> Self {
3328        self.expiration = Some(expiration);
3329        self
3330    }
3331}
3332
3333impl ToRedisArgs for HashFieldExpirationOptions {
3334    fn write_redis_args<W>(&self, out: &mut W)
3335    where
3336        W: ?Sized + RedisWrite,
3337    {
3338        if let Some(ref existence_check) = self.existence_check {
3339            match existence_check {
3340                FieldExistenceCheck::FNX => out.write_arg(b"FNX"),
3341                FieldExistenceCheck::FXX => out.write_arg(b"FXX"),
3342            }
3343        }
3344
3345        if let Some(ref expiration) = self.expiration {
3346            match expiration {
3347                SetExpiry::EX(secs) => {
3348                    out.write_arg(b"EX");
3349                    out.write_arg(format!("{secs}").as_bytes());
3350                }
3351                SetExpiry::PX(millis) => {
3352                    out.write_arg(b"PX");
3353                    out.write_arg(format!("{millis}").as_bytes());
3354                }
3355                SetExpiry::EXAT(unix_time) => {
3356                    out.write_arg(b"EXAT");
3357                    out.write_arg(format!("{unix_time}").as_bytes());
3358                }
3359                SetExpiry::PXAT(unix_time) => {
3360                    out.write_arg(b"PXAT");
3361                    out.write_arg(format!("{unix_time}").as_bytes());
3362                }
3363                SetExpiry::KEEPTTL => {
3364                    out.write_arg(b"KEEPTTL");
3365                }
3366            }
3367        }
3368    }
3369}
3370
3371impl ToRedisArgs for Expiry {
3372    fn write_redis_args<W>(&self, out: &mut W)
3373    where
3374        W: ?Sized + RedisWrite,
3375    {
3376        match self {
3377            Expiry::EX(sec) => {
3378                out.write_arg(b"EX");
3379                out.write_arg(sec.to_string().as_bytes());
3380            }
3381            Expiry::PX(ms) => {
3382                out.write_arg(b"PX");
3383                out.write_arg(ms.to_string().as_bytes());
3384            }
3385            Expiry::EXAT(timestamp_sec) => {
3386                out.write_arg(b"EXAT");
3387                out.write_arg(timestamp_sec.to_string().as_bytes());
3388            }
3389            Expiry::PXAT(timestamp_ms) => {
3390                out.write_arg(b"PXAT");
3391                out.write_arg(timestamp_ms.to_string().as_bytes());
3392            }
3393            Expiry::PERSIST => {
3394                out.write_arg(b"PERSIST");
3395            }
3396        }
3397    }
3398}
3399
3400/// Helper enum that is used to define update checks
3401#[derive(Clone, Copy)]
3402pub enum UpdateCheck {
3403    /// LT -- Only update if the new score is less than the current.
3404    LT,
3405    /// GT -- Only update if the new score is greater than the current.
3406    GT,
3407}
3408
3409/// Options for the [ZADD](https://redis.io/commands/zadd) command
3410#[derive(Clone, Copy, Default)]
3411pub struct SortedSetAddOptions {
3412    conditional_set: Option<ExistenceCheck>,
3413    conditional_update: Option<UpdateCheck>,
3414    include_changed: bool,
3415    increment: bool,
3416}
3417
3418impl SortedSetAddOptions {
3419    /// Sets the NX option for the ZADD command
3420    /// Only add a member if it does not already exist.
3421    pub fn add_only() -> Self {
3422        Self {
3423            conditional_set: Some(ExistenceCheck::NX),
3424            ..Default::default()
3425        }
3426    }
3427
3428    /// Sets the XX option and optionally the GT/LT option for the ZADD command
3429    /// Only update existing members
3430    pub fn update_only(conditional_update: Option<UpdateCheck>) -> Self {
3431        Self {
3432            conditional_set: Some(ExistenceCheck::XX),
3433            conditional_update,
3434            ..Default::default()
3435        }
3436    }
3437
3438    /// Optionally sets the GT/LT option for the ZADD command
3439    /// Add new member or update existing
3440    pub fn add_or_update(conditional_update: Option<UpdateCheck>) -> Self {
3441        Self {
3442            conditional_update,
3443            ..Default::default()
3444        }
3445    }
3446
3447    /// Sets the CH option for the ZADD command
3448    /// Return the number of elements changed (not just added).
3449    pub fn include_changed_count(mut self) -> Self {
3450        self.include_changed = true;
3451        self
3452    }
3453
3454    /// Sets the INCR option for the ZADD command
3455    /// Increment the score of the member instead of setting it.
3456    pub fn increment_score(mut self) -> Self {
3457        self.increment = true;
3458        self
3459    }
3460}
3461
3462impl ToRedisArgs for SortedSetAddOptions {
3463    fn write_redis_args<W>(&self, out: &mut W)
3464    where
3465        W: ?Sized + RedisWrite,
3466    {
3467        if let Some(ref conditional_set) = self.conditional_set {
3468            match conditional_set {
3469                ExistenceCheck::NX => {
3470                    out.write_arg(b"NX");
3471                }
3472                ExistenceCheck::XX => {
3473                    out.write_arg(b"XX");
3474                }
3475            }
3476        }
3477
3478        if let Some(ref conditional_update) = self.conditional_update {
3479            match conditional_update {
3480                UpdateCheck::LT => {
3481                    out.write_arg(b"LT");
3482                }
3483                UpdateCheck::GT => {
3484                    out.write_arg(b"GT");
3485                }
3486            }
3487        }
3488        if self.include_changed {
3489            out.write_arg(b"CH")
3490        }
3491        if self.increment {
3492            out.write_arg(b"INCR")
3493        }
3494    }
3495}
3496
3497// Vector sets types
3498
3499/// Input data formats that can be used to generate vector embeddings:
3500///
3501/// - 32-bit floats
3502/// - 64-bit floats
3503/// - Strings (e.g., numbers as strings)
3504#[cfg(feature = "vector-sets")]
3505#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3506#[derive(Clone)]
3507pub enum EmbeddingInput<'a> {
3508    /// 32-bit floating point input
3509    Float32(&'a [f32]),
3510    /// 64-bit floating point input
3511    Float64(&'a [f64]),
3512    /// String input (e.g., numbers as strings)
3513    String(&'a [&'a str]),
3514}
3515
3516#[cfg(feature = "vector-sets")]
3517impl<'a> ToRedisArgs for EmbeddingInput<'a> {
3518    fn write_redis_args<W>(&self, out: &mut W)
3519    where
3520        W: ?Sized + RedisWrite,
3521    {
3522        match self {
3523            EmbeddingInput::Float32(vector) => {
3524                out.write_arg_fmt(vector.len());
3525                for &f in *vector {
3526                    out.write_arg_fmt(f);
3527                }
3528            }
3529            EmbeddingInput::Float64(vector) => {
3530                out.write_arg_fmt(vector.len());
3531                for &f in *vector {
3532                    out.write_arg_fmt(f);
3533                }
3534            }
3535            EmbeddingInput::String(vector) => {
3536                out.write_arg_fmt(vector.len());
3537                for v in *vector {
3538                    v.write_redis_args(out);
3539                }
3540            }
3541        }
3542    }
3543}
3544
3545/// Represents different ways to input data for vector add commands
3546#[cfg(feature = "vector-sets")]
3547#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3548#[derive(Clone)]
3549pub enum VectorAddInput<'a> {
3550    /// Binary representation of 32-bit floating point values
3551    Fp32(&'a [f32]),
3552    /// A list of values whose types are supported for embedding generation
3553    Values(EmbeddingInput<'a>),
3554}
3555
3556#[cfg(feature = "vector-sets")]
3557impl<'a> ToRedisArgs for VectorAddInput<'a> {
3558    fn write_redis_args<W>(&self, out: &mut W)
3559    where
3560        W: ?Sized + RedisWrite,
3561    {
3562        match self {
3563            VectorAddInput::Fp32(vector) => {
3564                use std::io::Write;
3565                out.write_arg(b"FP32");
3566                let mut writer = out.writer_for_next_arg();
3567                for &f in *vector {
3568                    writer.write_all(&f.to_le_bytes()).unwrap();
3569                }
3570            }
3571            VectorAddInput::Values(embedding_input) => {
3572                out.write_arg(b"VALUES");
3573                embedding_input.write_redis_args(out);
3574            }
3575        }
3576    }
3577}
3578
3579/// Quantization options for vector storage
3580#[cfg(feature = "vector-sets")]
3581#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3582#[derive(Clone, Copy)]
3583pub enum VectorQuantization {
3584    /// In the first VADD call for a given key, NOQUANT forces the vector to be created without int8 quantization, which is otherwise the default.
3585    NoQuant,
3586    /// Forces the vector to use signed 8-bit quantization.
3587    /// 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.
3588    Q8,
3589    /// Forces the vector to use binary quantization instead of int8.
3590    /// This is much faster and uses less memory, but impacts the recall quality.
3591    Bin,
3592}
3593
3594/// Options for the VADD command
3595///
3596/// # Example
3597/// ```rust,no_run
3598/// use redis::{Commands, RedisResult, VAddOptions, VectorQuantization};
3599/// fn add_vector(
3600///     con: &mut redis::Connection,
3601///     key: &str,
3602///     vector: &[f64],
3603///     element: &str,
3604/// ) -> RedisResult<bool> {
3605///     let opts = VAddOptions::default()
3606///         .set_reduction_dimension(5)
3607///         .set_check_and_set_style(true)
3608///         .set_quantization(VectorQuantization::Q8)
3609///         .set_build_exploration_factor(300)
3610///         .set_attributes(serde_json::json!({"name": "Vector attribute name", "description": "Vector attribute description"}))
3611///         .set_max_number_of_links(16);
3612///     con.vadd_options(key, redis::VectorAddInput::Values(redis::EmbeddingInput::Float64(vector)), element, &opts)
3613/// }
3614/// ```
3615#[cfg(feature = "vector-sets")]
3616#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3617#[derive(Clone, Default)]
3618pub struct VAddOptions {
3619    /// Implements random projection to reduce the dimensionality of the vector.
3620    /// The projection matrix is saved and reloaded along with the vector set.
3621    reduction_dimension: Option<usize>,
3622    /// Performs the operation partially using threads, in a check-and-set style.
3623    /// The neighbor candidates collection, which is slow, is performed in the background, while the command is executed in the main thread.
3624    enable_check_and_set_style: bool,
3625    /// The quantization to be used. If no quantization is provided, the default value, Q8 (signed 8-bit), will be used.
3626    vector_quantization: Option<VectorQuantization>,
3627    /// 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.
3628    /// The default is 200. Using a larger value may help in achieving a better recall.
3629    build_exploration_factor: Option<usize>,
3630    /// Assigns attributes from a JavaScript object to a newly created entry or updates existing attributes.
3631    attributes: Option<serde_json::Value>,
3632    /// The maximum number of connections that each node of the graph will have with other nodes.
3633    /// The default is 16. More connections means more memory, but provides for more efficient graph exploration.
3634    max_number_of_links: Option<usize>,
3635}
3636
3637#[cfg(feature = "vector-sets")]
3638impl VAddOptions {
3639    /// Set reduction dimension value
3640    pub fn set_reduction_dimension(mut self, dimension: usize) -> Self {
3641        self.reduction_dimension = Some(dimension);
3642        self
3643    }
3644
3645    /// Set the CAS (check-and-set) style flag
3646    pub fn set_check_and_set_style(mut self, cas_enabled: bool) -> Self {
3647        self.enable_check_and_set_style = cas_enabled;
3648        self
3649    }
3650
3651    /// Set the quantization mode
3652    pub fn set_quantization(mut self, vector_quantization: VectorQuantization) -> Self {
3653        self.vector_quantization = Some(vector_quantization);
3654        self
3655    }
3656
3657    /// Set the build exploration factor
3658    pub fn set_build_exploration_factor(mut self, build_exploration_factor: usize) -> Self {
3659        self.build_exploration_factor = Some(build_exploration_factor);
3660        self
3661    }
3662
3663    /// Set attributes as JSON string
3664    pub fn set_attributes(mut self, attributes: serde_json::Value) -> Self {
3665        self.attributes = Some(attributes);
3666        self
3667    }
3668
3669    /// Set the maximum number of links
3670    pub fn set_max_number_of_links(mut self, max_number_of_links: usize) -> Self {
3671        self.max_number_of_links = Some(max_number_of_links);
3672        self
3673    }
3674}
3675
3676#[cfg(feature = "vector-sets")]
3677impl ToRedisArgs for VAddOptions {
3678    fn write_redis_args<W>(&self, out: &mut W)
3679    where
3680        W: ?Sized + RedisWrite,
3681    {
3682        if self.enable_check_and_set_style {
3683            out.write_arg(b"CAS");
3684        }
3685
3686        if let Some(ref quantization) = self.vector_quantization {
3687            match quantization {
3688                VectorQuantization::NoQuant => out.write_arg(b"NOQUANT"),
3689                VectorQuantization::Q8 => out.write_arg(b"Q8"),
3690                VectorQuantization::Bin => out.write_arg(b"BIN"),
3691            }
3692        }
3693
3694        if let Some(exploration_factor) = self.build_exploration_factor {
3695            out.write_arg(b"EF");
3696            out.write_arg_fmt(exploration_factor);
3697        }
3698
3699        if let Some(ref attrs) = self.attributes {
3700            out.write_arg(b"SETATTR");
3701            out.write_arg(&serde_json::to_vec(&attrs).unwrap());
3702        }
3703
3704        if let Some(max_links) = self.max_number_of_links {
3705            out.write_arg(b"M");
3706            out.write_arg_fmt(max_links);
3707        }
3708    }
3709}
3710
3711/// Options for the VEMB command
3712///
3713/// # Example
3714/// ```rust,no_run
3715/// use redis::{Commands, RedisResult, VEmbOptions};
3716/// fn get_vector_embedding(
3717///     con: &mut redis::Connection,
3718///     key: &str,
3719///     element: &str,
3720/// ) -> RedisResult<redis::Value> {
3721///     let opts = VEmbOptions::default().set_raw_representation(true);
3722///     con.vemb_options(key, element, &opts)
3723/// }
3724/// ```
3725#[cfg(feature = "vector-sets")]
3726#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3727#[derive(Clone, Default)]
3728pub struct VEmbOptions {
3729    /// Returns the raw internal representation of the approximate vector associated with a given element in the vector set
3730    raw_representation: bool,
3731}
3732
3733#[cfg(feature = "vector-sets")]
3734impl VEmbOptions {
3735    /// Set the raw representation flag
3736    pub fn set_raw_representation(mut self, enabled: bool) -> Self {
3737        self.raw_representation = enabled;
3738        self
3739    }
3740}
3741
3742#[cfg(feature = "vector-sets")]
3743impl ToRedisArgs for VEmbOptions {
3744    fn write_redis_args<W>(&self, out: &mut W)
3745    where
3746        W: ?Sized + RedisWrite,
3747    {
3748        if self.raw_representation {
3749            out.write_arg(b"RAW");
3750        }
3751    }
3752}
3753
3754/// Represents different ways to input query data for vector similarity search commands
3755#[cfg(feature = "vector-sets")]
3756#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3757#[derive(Clone)]
3758pub enum VectorSimilaritySearchInput<'a> {
3759    /// Binary representation of 32-bit floating point values to use as a reference
3760    Fp32(&'a [f32]),
3761    /// List of values to use as a reference
3762    Values(EmbeddingInput<'a>),
3763    /// Element to use as a reference
3764    Element(&'a str),
3765}
3766
3767#[cfg(feature = "vector-sets")]
3768impl<'a> ToRedisArgs for VectorSimilaritySearchInput<'a> {
3769    fn write_redis_args<W>(&self, out: &mut W)
3770    where
3771        W: ?Sized + RedisWrite,
3772    {
3773        match self {
3774            VectorSimilaritySearchInput::Fp32(vector) => {
3775                use std::io::Write;
3776                out.write_arg(b"FP32");
3777                let mut writer = out.writer_for_next_arg();
3778                for &f in *vector {
3779                    writer.write_all(&f.to_le_bytes()).unwrap();
3780                }
3781            }
3782            VectorSimilaritySearchInput::Values(embedding_input) => {
3783                out.write_arg(b"VALUES");
3784                embedding_input.write_redis_args(out);
3785            }
3786            VectorSimilaritySearchInput::Element(element) => {
3787                out.write_arg(b"ELE");
3788                element.write_redis_args(out);
3789            }
3790        }
3791    }
3792}
3793
3794/// Options for the VSIM command
3795///
3796/// # Example
3797/// ```rust,no_run
3798/// use redis::{Commands, RedisResult, VSimOptions};
3799/// fn search_similar_vectors(
3800///     con: &mut redis::Connection,
3801///     key: &str,
3802///     element: &str,
3803/// ) -> RedisResult<redis::Value> {
3804///     let opts = VSimOptions::default()
3805///         .set_with_scores(true)
3806///         .set_count(10)
3807///         .set_search_exploration_factor(100)
3808///         .set_filter_expression(".size == \"large\"")
3809///         .set_max_filtering_effort(10)
3810///         .set_truth(true)
3811///         .set_no_thread(true);
3812///     con.vsim_options(key, redis::VectorSimilaritySearchInput::Element(element), &opts)
3813/// }
3814/// ```
3815#[cfg(feature = "vector-sets")]
3816#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3817#[derive(Clone, Default)]
3818pub struct VSimOptions {
3819    /// Include similarity scores in the results
3820    with_scores: bool,
3821    /// Limit the number of results returned
3822    count: Option<usize>,
3823    /// Controls the search effort. Higher values explore more nodes, improving recall at the cost of speed.
3824    /// Typical values range from 50 to 1000.
3825    search_exploration_factor: Option<usize>,
3826    /// JSON filter expression to apply to the results
3827    filter: Option<String>,
3828    /// Limits the number of filtering attempts for the FILTER expression.
3829    /// The accuracy improves the with higher values, but the search may take longer.
3830    filter_max_effort: Option<usize>,
3831    /// Forces an exact linear scan of all elements, bypassing the HNSW graph.
3832    /// Use for benchmarking or to calculate recall. This is significantly slower (O(N)).
3833    truth: bool,
3834    /// Executes the search in the main thread instead of a background thread.
3835    /// Useful for small vector sets or benchmarks. This may block the server during execution!
3836    no_thread: bool,
3837}
3838
3839#[cfg(feature = "vector-sets")]
3840impl VSimOptions {
3841    /// Include similarity scores in the results
3842    pub fn set_with_scores(mut self, enabled: bool) -> Self {
3843        self.with_scores = enabled;
3844        self
3845    }
3846
3847    /// Limit the number of results returned
3848    pub fn set_count(mut self, count: usize) -> Self {
3849        self.count = Some(count);
3850        self
3851    }
3852
3853    /// Set the search exploration factor
3854    pub fn set_search_exploration_factor(mut self, factor: usize) -> Self {
3855        self.search_exploration_factor = Some(factor);
3856        self
3857    }
3858
3859    /// Set a JSON filter expression
3860    pub fn set_filter_expression<S: Into<String>>(mut self, expression: S) -> Self {
3861        self.filter = Some(expression.into());
3862        self
3863    }
3864
3865    /// Set the maximum filtering effort
3866    pub fn set_max_filtering_effort(mut self, effort: usize) -> Self {
3867        self.filter_max_effort = Some(effort);
3868        self
3869    }
3870
3871    /// Enable/disable exact linear scan of all elements
3872    pub fn set_truth(mut self, enabled: bool) -> Self {
3873        self.truth = enabled;
3874        self
3875    }
3876
3877    /// Enable/disable multi-threading
3878    pub fn set_no_thread(mut self, enabled: bool) -> Self {
3879        self.no_thread = enabled;
3880        self
3881    }
3882}
3883
3884#[cfg(feature = "vector-sets")]
3885impl ToRedisArgs for VSimOptions {
3886    fn write_redis_args<W>(&self, out: &mut W)
3887    where
3888        W: ?Sized + RedisWrite,
3889    {
3890        if self.with_scores {
3891            out.write_arg(b"WITHSCORES");
3892        }
3893
3894        if let Some(count) = self.count {
3895            out.write_arg(b"COUNT");
3896            out.write_arg_fmt(count);
3897        }
3898
3899        if let Some(ef) = self.search_exploration_factor {
3900            out.write_arg(b"EF");
3901            out.write_arg_fmt(ef);
3902        }
3903
3904        if let Some(ref filter) = self.filter {
3905            out.write_arg(b"FILTER");
3906            out.write_arg(filter.as_bytes());
3907        }
3908
3909        if let Some(filter_ef) = self.filter_max_effort {
3910            out.write_arg(b"FILTER-EF");
3911            out.write_arg_fmt(filter_ef);
3912        }
3913
3914        if self.truth {
3915            out.write_arg(b"TRUTH");
3916        }
3917
3918        if self.no_thread {
3919            out.write_arg(b"NOTHREAD");
3920        }
3921    }
3922}
3923
3924/// Creates HELLO command for RESP3 with RedisConnectionInfo
3925/// [Redis Docs](https://redis.io/commands/HELLO)
3926pub fn resp3_hello(connection_info: &RedisConnectionInfo) -> Cmd {
3927    let mut hello_cmd = cmd("HELLO");
3928    hello_cmd.arg("3");
3929    if let Some(password) = &connection_info.password {
3930        let username: &str = match connection_info.username.as_ref() {
3931            None => "default",
3932            Some(username) => username,
3933        };
3934        hello_cmd.arg("AUTH").arg(username).arg(password);
3935    }
3936
3937    hello_cmd
3938}