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