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