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