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