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