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