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] [KEEPREF | DELREF | ACKED] ...
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 /// An extension of the Streams `XDEL` command that provides finer control over how message entries are deleted with respect to consumer groups.
2170 #[cfg(feature = "streams")]
2171 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2172 fn xdel_ex<K: ToRedisArgs, ID: ToRedisArgs>(key: K, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XDelExStatusCode>) {
2173 cmd("XDELEX").arg(key).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2174 }
2175
2176 /// A combination of `XACK` and `XDEL` that acknowledges and attempts to delete a list of `ids` for a given stream `key` and consumer `group`.
2177 #[cfg(feature = "streams")]
2178 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2179 fn xack_del<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(key: K, group: G, ids: &'a [ID], options: streams::StreamDeletionPolicy) -> (Vec<streams::XAckDelStatusCode>) {
2180 cmd("XACKDEL").arg(key).arg(group).arg(options).arg("IDS").arg(ids.len()).arg(ids)
2181 }
2182
2183 /// This command is used for creating a consumer `group`. It expects the stream key
2184 /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
2185 /// The `id` is the starting message id all consumers should read from. Use `$` If you want
2186 /// all consumers to read from the last message added to stream.
2187 ///
2188 /// ```text
2189 /// XGROUP CREATE <key> <groupname> <id or $>
2190 /// ```
2191 /// [Redis Docs](https://redis.io/commands/XGROUP)
2192 #[cfg(feature = "streams")]
2193 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2194 fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2195 key: K,
2196 group: G,
2197 id: ID
2198 ) -> () {
2199 cmd("XGROUP")
2200 .arg("CREATE")
2201 .arg(key)
2202 .arg(group)
2203 .arg(id)
2204 }
2205
2206 /// This creates a `consumer` explicitly (vs implicit via XREADGROUP)
2207 /// for given stream `key.
2208 ///
2209 /// The return value is either a 0 or a 1 for the number of consumers created
2210 /// 0 means the consumer already exists
2211 ///
2212 /// ```text
2213 /// XGROUP CREATECONSUMER <key> <groupname> <consumername>
2214 /// ```
2215 /// [Redis Docs](https://redis.io/commands/XGROUP)
2216 #[cfg(feature = "streams")]
2217 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2218 fn xgroup_createconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2219 key: K,
2220 group: G,
2221 consumer: C
2222 ) -> bool {
2223 cmd("XGROUP")
2224 .arg("CREATECONSUMER")
2225 .arg(key)
2226 .arg(group)
2227 .arg(consumer)
2228 }
2229
2230 /// This is the alternate version for creating a consumer `group`
2231 /// which makes the stream if it doesn't exist.
2232 ///
2233 /// ```text
2234 /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
2235 /// ```
2236 /// [Redis Docs](https://redis.io/commands/XGROUP)
2237 #[cfg(feature = "streams")]
2238 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2239 fn xgroup_create_mkstream<
2240 K: ToRedisArgs,
2241 G: ToRedisArgs,
2242 ID: ToRedisArgs
2243 >(
2244 key: K,
2245 group: G,
2246 id: ID
2247 ) -> () {
2248 cmd("XGROUP")
2249 .arg("CREATE")
2250 .arg(key)
2251 .arg(group)
2252 .arg(id)
2253 .arg("MKSTREAM")
2254 }
2255
2256
2257 /// Alter which `id` you want consumers to begin reading from an existing
2258 /// consumer `group`.
2259 ///
2260 /// ```text
2261 /// XGROUP SETID <key> <groupname> <id or $>
2262 /// ```
2263 /// [Redis Docs](https://redis.io/commands/XGROUP)
2264 #[cfg(feature = "streams")]
2265 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2266 fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
2267 key: K,
2268 group: G,
2269 id: ID
2270 ) -> () {
2271 cmd("XGROUP")
2272 .arg("SETID")
2273 .arg(key)
2274 .arg(group)
2275 .arg(id)
2276 }
2277
2278
2279 /// Destroy an existing consumer `group` for a given stream `key`
2280 ///
2281 /// ```text
2282 /// XGROUP SETID <key> <groupname> <id or $>
2283 /// ```
2284 /// [Redis Docs](https://redis.io/commands/XGROUP)
2285 #[cfg(feature = "streams")]
2286 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2287 fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
2288 key: K,
2289 group: G
2290 ) -> bool {
2291 cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
2292 }
2293
2294 /// This deletes a `consumer` from an existing consumer `group`
2295 /// for given stream `key.
2296 ///
2297 /// ```text
2298 /// XGROUP DELCONSUMER <key> <groupname> <consumername>
2299 /// ```
2300 /// [Redis Docs](https://redis.io/commands/XGROUP)
2301 #[cfg(feature = "streams")]
2302 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2303 fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
2304 key: K,
2305 group: G,
2306 consumer: C
2307 ) -> usize {
2308 cmd("XGROUP")
2309 .arg("DELCONSUMER")
2310 .arg(key)
2311 .arg(group)
2312 .arg(consumer)
2313 }
2314
2315
2316 /// This returns all info details about
2317 /// which consumers have read messages for given consumer `group`.
2318 /// Take note of the StreamInfoConsumersReply return type.
2319 ///
2320 /// *It's possible this return value might not contain new fields
2321 /// added by Redis in future versions.*
2322 ///
2323 /// ```text
2324 /// XINFO CONSUMERS <key> <group>
2325 /// ```
2326 /// [Redis Docs](https://redis.io/commands/XINFO")
2327 #[cfg(feature = "streams")]
2328 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2329 fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
2330 key: K,
2331 group: G
2332 ) -> (streams::StreamInfoConsumersReply) {
2333 cmd("XINFO")
2334 .arg("CONSUMERS")
2335 .arg(key)
2336 .arg(group)
2337 }
2338
2339
2340 /// Returns all consumer `group`s created for a given stream `key`.
2341 /// Take note of the StreamInfoGroupsReply return type.
2342 ///
2343 /// *It's possible this return value might not contain new fields
2344 /// added by Redis in future versions.*
2345 ///
2346 /// ```text
2347 /// XINFO GROUPS <key>
2348 /// ```
2349 /// [Redis Docs](https://redis.io/commands/XINFO-GROUPS)
2350 #[cfg(feature = "streams")]
2351 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2352 fn xinfo_groups<K: ToRedisArgs>(key: K) -> (streams::StreamInfoGroupsReply) {
2353 cmd("XINFO").arg("GROUPS").arg(key)
2354 }
2355
2356
2357 /// Returns info about high-level stream details
2358 /// (first & last message `id`, length, number of groups, etc.)
2359 /// Take note of the StreamInfoStreamReply return type.
2360 ///
2361 /// *It's possible this return value might not contain new fields
2362 /// added by Redis in future versions.*
2363 ///
2364 /// ```text
2365 /// XINFO STREAM <key>
2366 /// ```
2367 /// [Redis Docs](https://redis.io/commands/XINFO-STREAM)
2368 #[cfg(feature = "streams")]
2369 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2370 fn xinfo_stream<K: ToRedisArgs>(key: K) -> (streams::StreamInfoStreamReply) {
2371 cmd("XINFO").arg("STREAM").arg(key)
2372 }
2373
2374 /// Returns the number of messages for a given stream `key`.
2375 ///
2376 /// ```text
2377 /// XLEN <key>
2378 /// ```
2379 #[cfg(feature = "streams")]
2380 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2381 /// [Redis Docs](https://redis.io/commands/XLEN)
2382 fn xlen<K: ToRedisArgs>(key: K) -> usize {
2383 cmd("XLEN").arg(key)
2384 }
2385
2386
2387 /// This is a basic version of making XPENDING command calls which only
2388 /// passes a stream `key` and consumer `group` and it
2389 /// returns details about which consumers have pending messages
2390 /// that haven't been acked.
2391 ///
2392 /// You can use this method along with
2393 /// `xclaim` or `xclaim_options` for determining which messages
2394 /// need to be retried.
2395 ///
2396 /// Take note of the StreamPendingReply return type.
2397 ///
2398 /// ```text
2399 /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
2400 /// ```
2401 /// [Redis Docs](https://redis.io/commands/XPENDING)
2402 #[cfg(feature = "streams")]
2403 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2404 fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
2405 key: K,
2406 group: G
2407 ) -> (streams::StreamPendingReply) {
2408 cmd("XPENDING").arg(key).arg(group)
2409 }
2410
2411
2412 /// This XPENDING version returns a list of all messages over the range.
2413 /// You can use this for paginating pending messages (but without the message HashMap).
2414 ///
2415 /// Start and end follow the same rules `xrange` args. Set start to `-`
2416 /// and end to `+` for the entire stream.
2417 ///
2418 /// Take note of the StreamPendingCountReply return type.
2419 ///
2420 /// ```text
2421 /// XPENDING <key> <group> <start> <stop> <count>
2422 /// ```
2423 /// [Redis Docs](https://redis.io/commands/XPENDING)
2424 #[cfg(feature = "streams")]
2425 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2426 fn xpending_count<
2427 K: ToRedisArgs,
2428 G: ToRedisArgs,
2429 S: ToRedisArgs,
2430 E: ToRedisArgs,
2431 C: ToRedisArgs
2432 >(
2433 key: K,
2434 group: G,
2435 start: S,
2436 end: E,
2437 count: C
2438 ) -> (streams::StreamPendingCountReply) {
2439 cmd("XPENDING")
2440 .arg(key)
2441 .arg(group)
2442 .arg(start)
2443 .arg(end)
2444 .arg(count)
2445 }
2446
2447
2448 /// An alternate version of `xpending_count` which filters by `consumer` name.
2449 ///
2450 /// Start and end follow the same rules `xrange` args. Set start to `-`
2451 /// and end to `+` for the entire stream.
2452 ///
2453 /// Take note of the StreamPendingCountReply return type.
2454 ///
2455 /// ```text
2456 /// XPENDING <key> <group> <start> <stop> <count> <consumer>
2457 /// ```
2458 /// [Redis Docs](https://redis.io/commands/XPENDING)
2459 #[cfg(feature = "streams")]
2460 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2461 fn xpending_consumer_count<
2462 K: ToRedisArgs,
2463 G: ToRedisArgs,
2464 S: ToRedisArgs,
2465 E: ToRedisArgs,
2466 C: ToRedisArgs,
2467 CN: ToRedisArgs
2468 >(
2469 key: K,
2470 group: G,
2471 start: S,
2472 end: E,
2473 count: C,
2474 consumer: CN
2475 ) -> (streams::StreamPendingCountReply) {
2476 cmd("XPENDING")
2477 .arg(key)
2478 .arg(group)
2479 .arg(start)
2480 .arg(end)
2481 .arg(count)
2482 .arg(consumer)
2483 }
2484
2485 /// Returns a range of messages in a given stream `key`.
2486 ///
2487 /// Set `start` to `-` to begin at the first message.
2488 /// Set `end` to `+` to end the most recent message.
2489 /// You can pass message `id` to both `start` and `end`.
2490 ///
2491 /// Take note of the StreamRangeReply return type.
2492 ///
2493 /// ```text
2494 /// XRANGE key start end
2495 /// ```
2496 /// [Redis Docs](https://redis.io/commands/XRANGE)
2497 #[cfg(feature = "streams")]
2498 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2499 fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
2500 key: K,
2501 start: S,
2502 end: E
2503 ) -> (streams::StreamRangeReply) {
2504 cmd("XRANGE").arg(key).arg(start).arg(end)
2505 }
2506
2507
2508 /// A helper method for automatically returning all messages in a stream by `key`.
2509 /// **Use with caution!**
2510 ///
2511 /// ```text
2512 /// XRANGE key - +
2513 /// ```
2514 /// [Redis Docs](https://redis.io/commands/XRANGE)
2515 #[cfg(feature = "streams")]
2516 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2517 fn xrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2518 cmd("XRANGE").arg(key).arg("-").arg("+")
2519 }
2520
2521
2522 /// A method for paginating a stream by `key`.
2523 ///
2524 /// ```text
2525 /// XRANGE key start end [COUNT <n>]
2526 /// ```
2527 /// [Redis Docs](https://redis.io/commands/XRANGE)
2528 #[cfg(feature = "streams")]
2529 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2530 fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
2531 key: K,
2532 start: S,
2533 end: E,
2534 count: C
2535 ) -> (streams::StreamRangeReply) {
2536 cmd("XRANGE")
2537 .arg(key)
2538 .arg(start)
2539 .arg(end)
2540 .arg("COUNT")
2541 .arg(count)
2542 }
2543
2544
2545 /// Read a list of `id`s for each stream `key`.
2546 /// This is the basic form of reading streams.
2547 /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
2548 /// see `xread_options`.
2549 ///
2550 /// ```text
2551 /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
2552 /// ```
2553 /// [Redis Docs](https://redis.io/commands/XREAD)
2554 #[cfg(feature = "streams")]
2555 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2556 fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
2557 keys: &'a [K],
2558 ids: &'a [ID]
2559 ) -> (Option<streams::StreamReadReply>) {
2560 cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
2561 }
2562
2563 /// This method handles setting optional arguments for
2564 /// `XREAD` or `XREADGROUP` Redis commands.
2565 /// ```no_run
2566 /// use redis::{Connection,RedisResult,Commands};
2567 /// use redis::streams::{StreamReadOptions,StreamReadReply};
2568 /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
2569 /// let mut con = client.get_connection().unwrap();
2570 ///
2571 /// // Read 10 messages from the start of the stream,
2572 /// // without registering as a consumer group.
2573 ///
2574 /// let opts = StreamReadOptions::default()
2575 /// .count(10);
2576 /// let results: RedisResult<StreamReadReply> =
2577 /// con.xread_options(&["k1"], &["0"], &opts);
2578 ///
2579 /// // Read all undelivered messages for a given
2580 /// // consumer group. Be advised: the consumer group must already
2581 /// // exist before making this call. Also note: we're passing
2582 /// // '>' as the id here, which means all undelivered messages.
2583 ///
2584 /// let opts = StreamReadOptions::default()
2585 /// .group("group-1", "consumer-1");
2586 /// let results: RedisResult<StreamReadReply> =
2587 /// con.xread_options(&["k1"], &[">"], &opts);
2588 /// ```
2589 ///
2590 /// ```text
2591 /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
2592 /// STREAMS key_1 key_2 ... key_N
2593 /// ID_1 ID_2 ... ID_N
2594 ///
2595 /// XREADGROUP [GROUP group-name consumer-name] [BLOCK <milliseconds>] [COUNT <count>] [NOACK]
2596 /// STREAMS key_1 key_2 ... key_N
2597 /// ID_1 ID_2 ... ID_N
2598 /// ```
2599 /// [Redis Docs](https://redis.io/commands/XREAD)
2600 #[cfg(feature = "streams")]
2601 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2602 fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
2603 keys: &'a [K],
2604 ids: &'a [ID],
2605 options: &'a streams::StreamReadOptions
2606 ) -> (Option<streams::StreamReadReply>) {
2607 cmd(if options.read_only() {
2608 "XREAD"
2609 } else {
2610 "XREADGROUP"
2611 })
2612 .arg(options)
2613 .arg("STREAMS")
2614 .arg(keys)
2615 .arg(ids)
2616 }
2617
2618 /// This is the reverse version of `xrange`.
2619 /// The same rules apply for `start` and `end` here.
2620 ///
2621 /// ```text
2622 /// XREVRANGE key end start
2623 /// ```
2624 /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2625 #[cfg(feature = "streams")]
2626 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2627 fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
2628 key: K,
2629 end: E,
2630 start: S
2631 ) -> (streams::StreamRangeReply) {
2632 cmd("XREVRANGE").arg(key).arg(end).arg(start)
2633 }
2634
2635 /// This is the reverse version of `xrange_all`.
2636 /// The same rules apply for `start` and `end` here.
2637 ///
2638 /// ```text
2639 /// XREVRANGE key + -
2640 /// ```
2641 /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2642 #[cfg(feature = "streams")]
2643 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2644 fn xrevrange_all<K: ToRedisArgs>(key: K) -> (streams::StreamRangeReply) {
2645 cmd("XREVRANGE").arg(key).arg("+").arg("-")
2646 }
2647
2648 /// This is the reverse version of `xrange_count`.
2649 /// The same rules apply for `start` and `end` here.
2650 ///
2651 /// ```text
2652 /// XREVRANGE key end start [COUNT <n>]
2653 /// ```
2654 /// [Redis Docs](https://redis.io/commands/XREVRANGE)
2655 #[cfg(feature = "streams")]
2656 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2657 fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
2658 key: K,
2659 end: E,
2660 start: S,
2661 count: C
2662 ) -> (streams::StreamRangeReply) {
2663 cmd("XREVRANGE")
2664 .arg(key)
2665 .arg(end)
2666 .arg(start)
2667 .arg("COUNT")
2668 .arg(count)
2669 }
2670
2671 /// Trim a stream `key` to a MAXLEN count.
2672 ///
2673 /// ```text
2674 /// XTRIM <key> MAXLEN [~|=] <count> (Same as XADD MAXLEN option)
2675 /// ```
2676 /// [Redis Docs](https://redis.io/commands/XTRIM)
2677 #[cfg(feature = "streams")]
2678 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2679 fn xtrim<K: ToRedisArgs>(
2680 key: K,
2681 maxlen: streams::StreamMaxlen
2682 ) -> usize {
2683 cmd("XTRIM").arg(key).arg(maxlen)
2684 }
2685
2686 /// Trim a stream `key` with full options
2687 ///
2688 /// ```text
2689 /// XTRIM <key> <MAXLEN|MINID> [~|=] <threshold> [LIMIT <count>] (Same as XADD MAXID|MINID options) [KEEPREF | DELREF | ACKED]
2690 /// ```
2691 /// [Redis Docs](https://redis.io/commands/XTRIM)
2692 #[cfg(feature = "streams")]
2693 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
2694 fn xtrim_options<K: ToRedisArgs>(
2695 key: K,
2696 options: &'a streams::StreamTrimOptions
2697 ) -> usize {
2698 cmd("XTRIM").arg(key).arg(options)
2699 }
2700
2701 // script commands
2702
2703 /// Load a script.
2704 ///
2705 /// See [`invoke_script`](Self::invoke_script) to actually run the scripts.
2706 #[cfg_attr(feature = "script", doc = r##"
2707
2708# Examples:
2709
2710```rust,no_run
2711# fn do_something() -> redis::RedisResult<()> {
2712# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2713# let mut con = client.get_connection().unwrap();
2714let script = redis::Script::new(r"
2715 return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2716");
2717let (load_res, invok_res): (String, isize) = redis::pipe()
2718 .load_script(&script)
2719 .invoke_script(script.arg(1).arg(2))
2720 .query(&mut con)?;
2721
2722assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2723assert_eq!(invok_res, 3);
2724# Ok(()) }
2725```
2726"##)]
2727 #[cfg(feature = "script")]
2728 #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2729 fn load_script<>(script: &'a crate::Script) -> Generic {
2730 &mut script.load_cmd()
2731 }
2732
2733 /// Invoke a prepared script.
2734 ///
2735 /// Note: Unlike[`ScriptInvocation::invoke`](crate::ScriptInvocation::invoke), this function
2736 /// does _not_ automatically load the script. If the invoked script did not get loaded beforehand, you
2737 /// need to manually load it (e.g.: using [`load_script`](Self::load_script) or
2738 /// [`ScriptInvocation::load`](crate::ScriptInvocation::load)). Otherwise this command will fail.
2739 #[cfg_attr(feature = "script", doc = r##"
2740
2741# Examples:
2742
2743```rust,no_run
2744# fn do_something() -> redis::RedisResult<()> {
2745# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
2746# let mut con = client.get_connection().unwrap();
2747let script = redis::Script::new(r"
2748 return tonumber(ARGV[1]) + tonumber(ARGV[2]);
2749");
2750let (load_res, invok_1_res, invok_2_res): (String, isize, isize) = redis::pipe()
2751 .load_script(&script)
2752 .invoke_script(script.arg(1).arg(2))
2753 .invoke_script(script.arg(2).arg(3))
2754 .query(&mut con)?;
2755
2756assert_eq!(load_res, "1ca80f2366c125a7c43519ce241d5c24c2b64023");
2757assert_eq!(invok_1_res, 3);
2758assert_eq!(invok_2_res, 5);
2759# Ok(()) }
2760```
2761"##)]
2762 #[cfg(feature = "script")]
2763 #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
2764 fn invoke_script<>(invocation: &'a crate::ScriptInvocation<'a>) -> Generic {
2765 &mut invocation.eval_cmd()
2766 }
2767
2768 // cleanup commands
2769
2770 /// Deletes all the keys of all databases
2771 ///
2772 /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2773 /// of your Redis server.
2774 ///
2775 /// To enforce a flush mode, use [`Commands::flushall_options`].
2776 ///
2777 /// ```text
2778 /// FLUSHALL
2779 /// ```
2780 /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2781 fn flushall<>() -> () {
2782 &mut cmd("FLUSHALL")
2783 }
2784
2785 /// Deletes all the keys of all databases with options
2786 ///
2787 /// ```text
2788 /// FLUSHALL [ASYNC|SYNC]
2789 /// ```
2790 /// [Redis Docs](https://redis.io/commands/FLUSHALL)
2791 fn flushall_options<>(options: &'a FlushAllOptions) -> () {
2792 cmd("FLUSHALL").arg(options)
2793 }
2794
2795 /// Deletes all the keys of the current database
2796 ///
2797 /// Whether the flushing happens asynchronously or synchronously depends on the configuration
2798 /// of your Redis server.
2799 ///
2800 /// To enforce a flush mode, use [`Commands::flushdb_options`].
2801 ///
2802 /// ```text
2803 /// FLUSHDB
2804 /// ```
2805 /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2806 fn flushdb<>() -> () {
2807 &mut cmd("FLUSHDB")
2808 }
2809
2810 /// Deletes all the keys of the current database with options
2811 ///
2812 /// ```text
2813 /// FLUSHDB [ASYNC|SYNC]
2814 /// ```
2815 /// [Redis Docs](https://redis.io/commands/FLUSHDB)
2816 fn flushdb_options<>(options: &'a FlushDbOptions) -> () {
2817 cmd("FLUSHDB").arg(options)
2818 }
2819}
2820
2821/// Allows pubsub callbacks to stop receiving messages.
2822///
2823/// Arbitrary data may be returned from `Break`.
2824pub enum ControlFlow<U> {
2825 /// Continues.
2826 Continue,
2827 /// Breaks with a value.
2828 Break(U),
2829}
2830
2831/// The PubSub trait allows subscribing to one or more channels
2832/// and receiving a callback whenever a message arrives.
2833///
2834/// Each method handles subscribing to the list of keys, waiting for
2835/// messages, and unsubscribing from the same list of channels once
2836/// a ControlFlow::Break is encountered.
2837///
2838/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2839/// for calling other methods.
2840///
2841/// # Examples
2842///
2843/// ```rust,no_run
2844/// # fn do_something() -> redis::RedisResult<()> {
2845/// use redis::{PubSubCommands, ControlFlow};
2846/// let client = redis::Client::open("redis://127.0.0.1/")?;
2847/// let mut con = client.get_connection()?;
2848/// let mut count = 0;
2849/// con.subscribe(&["foo"], |msg| {
2850/// // do something with message
2851/// assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2852///
2853/// // increment messages seen counter
2854/// count += 1;
2855/// match count {
2856/// // stop after receiving 10 messages
2857/// 10 => ControlFlow::Break(()),
2858/// _ => ControlFlow::Continue,
2859/// }
2860/// })?;
2861/// # Ok(()) }
2862/// ```
2863// TODO In the future, it would be nice to implement Try such that `?` will work
2864// within the closure.
2865pub trait PubSubCommands: Sized {
2866 /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2867 /// closure for each message received.
2868 ///
2869 /// For every `Msg` passed to the provided closure, either
2870 /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2871 /// method will not return until `ControlFlow::Break` is observed.
2872 fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2873 where
2874 F: FnMut(Msg) -> ControlFlow<U>,
2875 C: ToRedisArgs;
2876
2877 /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
2878 /// closure for each message received.
2879 ///
2880 /// For every `Msg` passed to the provided closure, either
2881 /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2882 /// method will not return until `ControlFlow::Break` is observed.
2883 fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
2884 where
2885 F: FnMut(Msg) -> ControlFlow<U>,
2886 P: ToRedisArgs;
2887}
2888
2889impl<T> Commands for T where T: ConnectionLike {}
2890
2891#[cfg(feature = "aio")]
2892impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
2893
2894impl<T> TypedCommands for T where T: ConnectionLike {}
2895
2896#[cfg(feature = "aio")]
2897impl<T> AsyncTypedCommands for T where T: crate::aio::ConnectionLike + Send + Sync + Sized {}
2898
2899impl PubSubCommands for Connection {
2900 fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
2901 where
2902 F: FnMut(Msg) -> ControlFlow<U>,
2903 C: ToRedisArgs,
2904 {
2905 let mut pubsub = self.as_pubsub();
2906 pubsub.subscribe(channels)?;
2907
2908 loop {
2909 let msg = pubsub.get_message()?;
2910 match func(msg) {
2911 ControlFlow::Continue => continue,
2912 ControlFlow::Break(value) => return Ok(value),
2913 }
2914 }
2915 }
2916
2917 fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
2918 where
2919 F: FnMut(Msg) -> ControlFlow<U>,
2920 P: ToRedisArgs,
2921 {
2922 let mut pubsub = self.as_pubsub();
2923 pubsub.psubscribe(patterns)?;
2924
2925 loop {
2926 let msg = pubsub.get_message()?;
2927 match func(msg) {
2928 ControlFlow::Continue => continue,
2929 ControlFlow::Break(value) => return Ok(value),
2930 }
2931 }
2932 }
2933}
2934
2935/// Options for the [SCAN](https://redis.io/commands/scan) command
2936///
2937/// # Example
2938///
2939/// ```rust
2940/// use redis::{Commands, RedisResult, ScanOptions, Iter};
2941/// fn force_fetching_every_matching_key<'a, T: redis::FromRedisValue>(
2942/// con: &'a mut redis::Connection,
2943/// pattern: &'a str,
2944/// count: usize,
2945/// ) -> RedisResult<Iter<'a, T>> {
2946/// let opts = ScanOptions::default()
2947/// .with_pattern(pattern)
2948/// .with_count(count);
2949/// con.scan_options(opts)
2950/// }
2951/// ```
2952#[derive(Default)]
2953pub struct ScanOptions {
2954 pattern: Option<String>,
2955 count: Option<usize>,
2956 scan_type: Option<String>,
2957}
2958
2959impl ScanOptions {
2960 /// Limit the results to the first N matching items.
2961 pub fn with_count(mut self, n: usize) -> Self {
2962 self.count = Some(n);
2963 self
2964 }
2965
2966 /// Pattern for scan
2967 pub fn with_pattern(mut self, p: impl Into<String>) -> Self {
2968 self.pattern = Some(p.into());
2969 self
2970 }
2971
2972 /// Limit the results to those with the given Redis type
2973 pub fn with_type(mut self, t: impl Into<String>) -> Self {
2974 self.scan_type = Some(t.into());
2975 self
2976 }
2977}
2978
2979impl ToRedisArgs for ScanOptions {
2980 fn write_redis_args<W>(&self, out: &mut W)
2981 where
2982 W: ?Sized + RedisWrite,
2983 {
2984 if let Some(p) = &self.pattern {
2985 out.write_arg(b"MATCH");
2986 out.write_arg_fmt(p);
2987 }
2988
2989 if let Some(n) = self.count {
2990 out.write_arg(b"COUNT");
2991 out.write_arg_fmt(n);
2992 }
2993
2994 if let Some(t) = &self.scan_type {
2995 out.write_arg(b"TYPE");
2996 out.write_arg_fmt(t);
2997 }
2998 }
2999
3000 fn num_of_args(&self) -> usize {
3001 let mut len = 0;
3002 if self.pattern.is_some() {
3003 len += 2;
3004 }
3005 if self.count.is_some() {
3006 len += 2;
3007 }
3008 if self.scan_type.is_some() {
3009 len += 2;
3010 }
3011 len
3012 }
3013}
3014
3015/// Options for the [LPOS](https://redis.io/commands/lpos) command
3016///
3017/// # Example
3018///
3019/// ```rust,no_run
3020/// use redis::{Commands, RedisResult, LposOptions};
3021/// fn fetch_list_position(
3022/// con: &mut redis::Connection,
3023/// key: &str,
3024/// value: &str,
3025/// count: usize,
3026/// rank: isize,
3027/// maxlen: usize,
3028/// ) -> RedisResult<Vec<usize>> {
3029/// let opts = LposOptions::default()
3030/// .count(count)
3031/// .rank(rank)
3032/// .maxlen(maxlen);
3033/// con.lpos(key, value, opts)
3034/// }
3035/// ```
3036#[derive(Default)]
3037pub struct LposOptions {
3038 count: Option<usize>,
3039 maxlen: Option<usize>,
3040 rank: Option<isize>,
3041}
3042
3043impl LposOptions {
3044 /// Limit the results to the first N matching items.
3045 pub fn count(mut self, n: usize) -> Self {
3046 self.count = Some(n);
3047 self
3048 }
3049
3050 /// Return the value of N from the matching items.
3051 pub fn rank(mut self, n: isize) -> Self {
3052 self.rank = Some(n);
3053 self
3054 }
3055
3056 /// Limit the search to N items in the list.
3057 pub fn maxlen(mut self, n: usize) -> Self {
3058 self.maxlen = Some(n);
3059 self
3060 }
3061}
3062
3063impl ToRedisArgs for LposOptions {
3064 fn write_redis_args<W>(&self, out: &mut W)
3065 where
3066 W: ?Sized + RedisWrite,
3067 {
3068 if let Some(n) = self.count {
3069 out.write_arg(b"COUNT");
3070 out.write_arg_fmt(n);
3071 }
3072
3073 if let Some(n) = self.rank {
3074 out.write_arg(b"RANK");
3075 out.write_arg_fmt(n);
3076 }
3077
3078 if let Some(n) = self.maxlen {
3079 out.write_arg(b"MAXLEN");
3080 out.write_arg_fmt(n);
3081 }
3082 }
3083
3084 fn num_of_args(&self) -> usize {
3085 let mut len = 0;
3086 if self.count.is_some() {
3087 len += 2;
3088 }
3089 if self.rank.is_some() {
3090 len += 2;
3091 }
3092 if self.maxlen.is_some() {
3093 len += 2;
3094 }
3095 len
3096 }
3097}
3098
3099/// Enum for the LEFT | RIGHT args used by some commands
3100pub enum Direction {
3101 /// Targets the first element (head) of the list
3102 Left,
3103 /// Targets the last element (tail) of the list
3104 Right,
3105}
3106
3107impl ToRedisArgs for Direction {
3108 fn write_redis_args<W>(&self, out: &mut W)
3109 where
3110 W: ?Sized + RedisWrite,
3111 {
3112 let s: &[u8] = match self {
3113 Direction::Left => b"LEFT",
3114 Direction::Right => b"RIGHT",
3115 };
3116 out.write_arg(s);
3117 }
3118}
3119
3120/// Options for the [COPY](https://redis.io/commands/copy) command
3121///
3122/// # Example
3123/// ```rust,no_run
3124/// use redis::{Commands, RedisResult, CopyOptions, SetExpiry, ExistenceCheck};
3125/// fn copy_value(
3126/// con: &mut redis::Connection,
3127/// old: &str,
3128/// new: &str,
3129/// ) -> RedisResult<Vec<usize>> {
3130/// let opts = CopyOptions::default()
3131/// .db("my_other_db")
3132/// .replace(true);
3133/// con.copy(old, new, opts)
3134/// }
3135/// ```
3136#[derive(Clone, Copy, Debug)]
3137pub struct CopyOptions<Db: ToString> {
3138 db: Option<Db>,
3139 replace: bool,
3140}
3141
3142impl Default for CopyOptions<&'static str> {
3143 fn default() -> Self {
3144 CopyOptions {
3145 db: None,
3146 replace: false,
3147 }
3148 }
3149}
3150
3151impl<Db: ToString> CopyOptions<Db> {
3152 /// Set the target database for the copy operation
3153 pub fn db<Db2: ToString>(self, db: Db2) -> CopyOptions<Db2> {
3154 CopyOptions {
3155 db: Some(db),
3156 replace: self.replace,
3157 }
3158 }
3159
3160 /// Set the replace option for the copy operation
3161 pub fn replace(mut self, replace: bool) -> Self {
3162 self.replace = replace;
3163 self
3164 }
3165}
3166
3167impl<Db: ToString> ToRedisArgs for CopyOptions<Db> {
3168 fn write_redis_args<W>(&self, out: &mut W)
3169 where
3170 W: ?Sized + RedisWrite,
3171 {
3172 if let Some(db) = &self.db {
3173 out.write_arg(b"DB");
3174 out.write_arg(db.to_string().as_bytes());
3175 }
3176 if self.replace {
3177 out.write_arg(b"REPLACE");
3178 }
3179 }
3180}
3181
3182/// Options for the [SET](https://redis.io/commands/set) command
3183///
3184/// # Example
3185/// ```rust,no_run
3186/// use redis::{Commands, RedisResult, SetOptions, SetExpiry, ExistenceCheck};
3187/// fn set_key_value(
3188/// con: &mut redis::Connection,
3189/// key: &str,
3190/// value: &str,
3191/// ) -> RedisResult<Vec<usize>> {
3192/// let opts = SetOptions::default()
3193/// .conditional_set(ExistenceCheck::NX)
3194/// .get(true)
3195/// .with_expiration(SetExpiry::EX(60));
3196/// con.set_options(key, value, opts)
3197/// }
3198/// ```
3199#[derive(Clone, Copy, Default)]
3200pub struct SetOptions {
3201 conditional_set: Option<ExistenceCheck>,
3202 get: bool,
3203 expiration: Option<SetExpiry>,
3204}
3205
3206impl SetOptions {
3207 /// Set the existence check for the SET command
3208 pub fn conditional_set(mut self, existence_check: ExistenceCheck) -> Self {
3209 self.conditional_set = Some(existence_check);
3210 self
3211 }
3212
3213 /// Set the GET option for the SET command
3214 pub fn get(mut self, get: bool) -> Self {
3215 self.get = get;
3216 self
3217 }
3218
3219 /// Set the expiration for the SET command
3220 pub fn with_expiration(mut self, expiration: SetExpiry) -> Self {
3221 self.expiration = Some(expiration);
3222 self
3223 }
3224}
3225
3226impl ToRedisArgs for SetOptions {
3227 fn write_redis_args<W>(&self, out: &mut W)
3228 where
3229 W: ?Sized + RedisWrite,
3230 {
3231 if let Some(ref conditional_set) = self.conditional_set {
3232 match conditional_set {
3233 ExistenceCheck::NX => {
3234 out.write_arg(b"NX");
3235 }
3236 ExistenceCheck::XX => {
3237 out.write_arg(b"XX");
3238 }
3239 }
3240 }
3241 if self.get {
3242 out.write_arg(b"GET");
3243 }
3244 if let Some(ref expiration) = self.expiration {
3245 match expiration {
3246 SetExpiry::EX(secs) => {
3247 out.write_arg(b"EX");
3248 out.write_arg(format!("{secs}").as_bytes());
3249 }
3250 SetExpiry::PX(millis) => {
3251 out.write_arg(b"PX");
3252 out.write_arg(format!("{millis}").as_bytes());
3253 }
3254 SetExpiry::EXAT(unix_time) => {
3255 out.write_arg(b"EXAT");
3256 out.write_arg(format!("{unix_time}").as_bytes());
3257 }
3258 SetExpiry::PXAT(unix_time) => {
3259 out.write_arg(b"PXAT");
3260 out.write_arg(format!("{unix_time}").as_bytes());
3261 }
3262 SetExpiry::KEEPTTL => {
3263 out.write_arg(b"KEEPTTL");
3264 }
3265 }
3266 }
3267 }
3268}
3269
3270/// Options for the [FLUSHALL](https://redis.io/commands/flushall) command
3271///
3272/// # Example
3273/// ```rust,no_run
3274/// use redis::{Commands, RedisResult, FlushAllOptions};
3275/// fn flushall_sync(
3276/// con: &mut redis::Connection,
3277/// ) -> RedisResult<()> {
3278/// let opts = FlushAllOptions{blocking: true};
3279/// con.flushall_options(&opts)
3280/// }
3281/// ```
3282#[derive(Clone, Copy, Default)]
3283pub struct FlushAllOptions {
3284 /// Blocking (`SYNC`) waits for completion, non-blocking (`ASYNC`) runs in the background
3285 pub blocking: bool,
3286}
3287
3288impl FlushAllOptions {
3289 /// Set whether to run blocking (`SYNC`) or non-blocking (`ASYNC`) flush
3290 pub fn blocking(mut self, blocking: bool) -> Self {
3291 self.blocking = blocking;
3292 self
3293 }
3294}
3295
3296impl ToRedisArgs for FlushAllOptions {
3297 fn write_redis_args<W>(&self, out: &mut W)
3298 where
3299 W: ?Sized + RedisWrite,
3300 {
3301 if self.blocking {
3302 out.write_arg(b"SYNC");
3303 } else {
3304 out.write_arg(b"ASYNC");
3305 };
3306 }
3307}
3308
3309/// Options for the [FLUSHDB](https://redis.io/commands/flushdb) command
3310pub type FlushDbOptions = FlushAllOptions;
3311
3312/// Options for the HSETEX command
3313#[derive(Clone, Copy, Default)]
3314pub struct HashFieldExpirationOptions {
3315 existence_check: Option<FieldExistenceCheck>,
3316 expiration: Option<SetExpiry>,
3317}
3318
3319impl HashFieldExpirationOptions {
3320 /// Set the field(s) existence check for the HSETEX command
3321 pub fn set_existence_check(mut self, field_existence_check: FieldExistenceCheck) -> Self {
3322 self.existence_check = Some(field_existence_check);
3323 self
3324 }
3325
3326 /// Set the expiration option for the field(s) in the HSETEX command
3327 pub fn set_expiration(mut self, expiration: SetExpiry) -> Self {
3328 self.expiration = Some(expiration);
3329 self
3330 }
3331}
3332
3333impl ToRedisArgs for HashFieldExpirationOptions {
3334 fn write_redis_args<W>(&self, out: &mut W)
3335 where
3336 W: ?Sized + RedisWrite,
3337 {
3338 if let Some(ref existence_check) = self.existence_check {
3339 match existence_check {
3340 FieldExistenceCheck::FNX => out.write_arg(b"FNX"),
3341 FieldExistenceCheck::FXX => out.write_arg(b"FXX"),
3342 }
3343 }
3344
3345 if let Some(ref expiration) = self.expiration {
3346 match expiration {
3347 SetExpiry::EX(secs) => {
3348 out.write_arg(b"EX");
3349 out.write_arg(format!("{secs}").as_bytes());
3350 }
3351 SetExpiry::PX(millis) => {
3352 out.write_arg(b"PX");
3353 out.write_arg(format!("{millis}").as_bytes());
3354 }
3355 SetExpiry::EXAT(unix_time) => {
3356 out.write_arg(b"EXAT");
3357 out.write_arg(format!("{unix_time}").as_bytes());
3358 }
3359 SetExpiry::PXAT(unix_time) => {
3360 out.write_arg(b"PXAT");
3361 out.write_arg(format!("{unix_time}").as_bytes());
3362 }
3363 SetExpiry::KEEPTTL => {
3364 out.write_arg(b"KEEPTTL");
3365 }
3366 }
3367 }
3368 }
3369}
3370
3371impl ToRedisArgs for Expiry {
3372 fn write_redis_args<W>(&self, out: &mut W)
3373 where
3374 W: ?Sized + RedisWrite,
3375 {
3376 match self {
3377 Expiry::EX(sec) => {
3378 out.write_arg(b"EX");
3379 out.write_arg(sec.to_string().as_bytes());
3380 }
3381 Expiry::PX(ms) => {
3382 out.write_arg(b"PX");
3383 out.write_arg(ms.to_string().as_bytes());
3384 }
3385 Expiry::EXAT(timestamp_sec) => {
3386 out.write_arg(b"EXAT");
3387 out.write_arg(timestamp_sec.to_string().as_bytes());
3388 }
3389 Expiry::PXAT(timestamp_ms) => {
3390 out.write_arg(b"PXAT");
3391 out.write_arg(timestamp_ms.to_string().as_bytes());
3392 }
3393 Expiry::PERSIST => {
3394 out.write_arg(b"PERSIST");
3395 }
3396 }
3397 }
3398}
3399
3400/// Helper enum that is used to define update checks
3401#[derive(Clone, Copy)]
3402pub enum UpdateCheck {
3403 /// LT -- Only update if the new score is less than the current.
3404 LT,
3405 /// GT -- Only update if the new score is greater than the current.
3406 GT,
3407}
3408
3409/// Options for the [ZADD](https://redis.io/commands/zadd) command
3410#[derive(Clone, Copy, Default)]
3411pub struct SortedSetAddOptions {
3412 conditional_set: Option<ExistenceCheck>,
3413 conditional_update: Option<UpdateCheck>,
3414 include_changed: bool,
3415 increment: bool,
3416}
3417
3418impl SortedSetAddOptions {
3419 /// Sets the NX option for the ZADD command
3420 /// Only add a member if it does not already exist.
3421 pub fn add_only() -> Self {
3422 Self {
3423 conditional_set: Some(ExistenceCheck::NX),
3424 ..Default::default()
3425 }
3426 }
3427
3428 /// Sets the XX option and optionally the GT/LT option for the ZADD command
3429 /// Only update existing members
3430 pub fn update_only(conditional_update: Option<UpdateCheck>) -> Self {
3431 Self {
3432 conditional_set: Some(ExistenceCheck::XX),
3433 conditional_update,
3434 ..Default::default()
3435 }
3436 }
3437
3438 /// Optionally sets the GT/LT option for the ZADD command
3439 /// Add new member or update existing
3440 pub fn add_or_update(conditional_update: Option<UpdateCheck>) -> Self {
3441 Self {
3442 conditional_update,
3443 ..Default::default()
3444 }
3445 }
3446
3447 /// Sets the CH option for the ZADD command
3448 /// Return the number of elements changed (not just added).
3449 pub fn include_changed_count(mut self) -> Self {
3450 self.include_changed = true;
3451 self
3452 }
3453
3454 /// Sets the INCR option for the ZADD command
3455 /// Increment the score of the member instead of setting it.
3456 pub fn increment_score(mut self) -> Self {
3457 self.increment = true;
3458 self
3459 }
3460}
3461
3462impl ToRedisArgs for SortedSetAddOptions {
3463 fn write_redis_args<W>(&self, out: &mut W)
3464 where
3465 W: ?Sized + RedisWrite,
3466 {
3467 if let Some(ref conditional_set) = self.conditional_set {
3468 match conditional_set {
3469 ExistenceCheck::NX => {
3470 out.write_arg(b"NX");
3471 }
3472 ExistenceCheck::XX => {
3473 out.write_arg(b"XX");
3474 }
3475 }
3476 }
3477
3478 if let Some(ref conditional_update) = self.conditional_update {
3479 match conditional_update {
3480 UpdateCheck::LT => {
3481 out.write_arg(b"LT");
3482 }
3483 UpdateCheck::GT => {
3484 out.write_arg(b"GT");
3485 }
3486 }
3487 }
3488 if self.include_changed {
3489 out.write_arg(b"CH")
3490 }
3491 if self.increment {
3492 out.write_arg(b"INCR")
3493 }
3494 }
3495}
3496
3497// Vector sets types
3498
3499/// Input data formats that can be used to generate vector embeddings:
3500///
3501/// - 32-bit floats
3502/// - 64-bit floats
3503/// - Strings (e.g., numbers as strings)
3504#[cfg(feature = "vector-sets")]
3505#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3506#[derive(Clone)]
3507pub enum EmbeddingInput<'a> {
3508 /// 32-bit floating point input
3509 Float32(&'a [f32]),
3510 /// 64-bit floating point input
3511 Float64(&'a [f64]),
3512 /// String input (e.g., numbers as strings)
3513 String(&'a [&'a str]),
3514}
3515
3516#[cfg(feature = "vector-sets")]
3517impl<'a> ToRedisArgs for EmbeddingInput<'a> {
3518 fn write_redis_args<W>(&self, out: &mut W)
3519 where
3520 W: ?Sized + RedisWrite,
3521 {
3522 match self {
3523 EmbeddingInput::Float32(vector) => {
3524 out.write_arg_fmt(vector.len());
3525 for &f in *vector {
3526 out.write_arg_fmt(f);
3527 }
3528 }
3529 EmbeddingInput::Float64(vector) => {
3530 out.write_arg_fmt(vector.len());
3531 for &f in *vector {
3532 out.write_arg_fmt(f);
3533 }
3534 }
3535 EmbeddingInput::String(vector) => {
3536 out.write_arg_fmt(vector.len());
3537 for v in *vector {
3538 v.write_redis_args(out);
3539 }
3540 }
3541 }
3542 }
3543}
3544
3545/// Represents different ways to input data for vector add commands
3546#[cfg(feature = "vector-sets")]
3547#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3548#[derive(Clone)]
3549pub enum VectorAddInput<'a> {
3550 /// Binary representation of 32-bit floating point values
3551 Fp32(&'a [f32]),
3552 /// A list of values whose types are supported for embedding generation
3553 Values(EmbeddingInput<'a>),
3554}
3555
3556#[cfg(feature = "vector-sets")]
3557impl<'a> ToRedisArgs for VectorAddInput<'a> {
3558 fn write_redis_args<W>(&self, out: &mut W)
3559 where
3560 W: ?Sized + RedisWrite,
3561 {
3562 match self {
3563 VectorAddInput::Fp32(vector) => {
3564 use std::io::Write;
3565 out.write_arg(b"FP32");
3566 let mut writer = out.writer_for_next_arg();
3567 for &f in *vector {
3568 writer.write_all(&f.to_le_bytes()).unwrap();
3569 }
3570 }
3571 VectorAddInput::Values(embedding_input) => {
3572 out.write_arg(b"VALUES");
3573 embedding_input.write_redis_args(out);
3574 }
3575 }
3576 }
3577}
3578
3579/// Quantization options for vector storage
3580#[cfg(feature = "vector-sets")]
3581#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3582#[derive(Clone, Copy)]
3583pub enum VectorQuantization {
3584 /// In the first VADD call for a given key, NOQUANT forces the vector to be created without int8 quantization, which is otherwise the default.
3585 NoQuant,
3586 /// Forces the vector to use signed 8-bit quantization.
3587 /// 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.
3588 Q8,
3589 /// Forces the vector to use binary quantization instead of int8.
3590 /// This is much faster and uses less memory, but impacts the recall quality.
3591 Bin,
3592}
3593
3594/// Options for the VADD command
3595///
3596/// # Example
3597/// ```rust,no_run
3598/// use redis::{Commands, RedisResult, VAddOptions, VectorQuantization};
3599/// fn add_vector(
3600/// con: &mut redis::Connection,
3601/// key: &str,
3602/// vector: &[f64],
3603/// element: &str,
3604/// ) -> RedisResult<bool> {
3605/// let opts = VAddOptions::default()
3606/// .set_reduction_dimension(5)
3607/// .set_check_and_set_style(true)
3608/// .set_quantization(VectorQuantization::Q8)
3609/// .set_build_exploration_factor(300)
3610/// .set_attributes(serde_json::json!({"name": "Vector attribute name", "description": "Vector attribute description"}))
3611/// .set_max_number_of_links(16);
3612/// con.vadd_options(key, redis::VectorAddInput::Values(redis::EmbeddingInput::Float64(vector)), element, &opts)
3613/// }
3614/// ```
3615#[cfg(feature = "vector-sets")]
3616#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3617#[derive(Clone, Default)]
3618pub struct VAddOptions {
3619 /// Implements random projection to reduce the dimensionality of the vector.
3620 /// The projection matrix is saved and reloaded along with the vector set.
3621 reduction_dimension: Option<usize>,
3622 /// Performs the operation partially using threads, in a check-and-set style.
3623 /// The neighbor candidates collection, which is slow, is performed in the background, while the command is executed in the main thread.
3624 enable_check_and_set_style: bool,
3625 /// The quantization to be used. If no quantization is provided, the default value, Q8 (signed 8-bit), will be used.
3626 vector_quantization: Option<VectorQuantization>,
3627 /// 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.
3628 /// The default is 200. Using a larger value may help in achieving a better recall.
3629 build_exploration_factor: Option<usize>,
3630 /// Assigns attributes from a JavaScript object to a newly created entry or updates existing attributes.
3631 attributes: Option<serde_json::Value>,
3632 /// The maximum number of connections that each node of the graph will have with other nodes.
3633 /// The default is 16. More connections means more memory, but provides for more efficient graph exploration.
3634 max_number_of_links: Option<usize>,
3635}
3636
3637#[cfg(feature = "vector-sets")]
3638impl VAddOptions {
3639 /// Set reduction dimension value
3640 pub fn set_reduction_dimension(mut self, dimension: usize) -> Self {
3641 self.reduction_dimension = Some(dimension);
3642 self
3643 }
3644
3645 /// Set the CAS (check-and-set) style flag
3646 pub fn set_check_and_set_style(mut self, cas_enabled: bool) -> Self {
3647 self.enable_check_and_set_style = cas_enabled;
3648 self
3649 }
3650
3651 /// Set the quantization mode
3652 pub fn set_quantization(mut self, vector_quantization: VectorQuantization) -> Self {
3653 self.vector_quantization = Some(vector_quantization);
3654 self
3655 }
3656
3657 /// Set the build exploration factor
3658 pub fn set_build_exploration_factor(mut self, build_exploration_factor: usize) -> Self {
3659 self.build_exploration_factor = Some(build_exploration_factor);
3660 self
3661 }
3662
3663 /// Set attributes as JSON string
3664 pub fn set_attributes(mut self, attributes: serde_json::Value) -> Self {
3665 self.attributes = Some(attributes);
3666 self
3667 }
3668
3669 /// Set the maximum number of links
3670 pub fn set_max_number_of_links(mut self, max_number_of_links: usize) -> Self {
3671 self.max_number_of_links = Some(max_number_of_links);
3672 self
3673 }
3674}
3675
3676#[cfg(feature = "vector-sets")]
3677impl ToRedisArgs for VAddOptions {
3678 fn write_redis_args<W>(&self, out: &mut W)
3679 where
3680 W: ?Sized + RedisWrite,
3681 {
3682 if self.enable_check_and_set_style {
3683 out.write_arg(b"CAS");
3684 }
3685
3686 if let Some(ref quantization) = self.vector_quantization {
3687 match quantization {
3688 VectorQuantization::NoQuant => out.write_arg(b"NOQUANT"),
3689 VectorQuantization::Q8 => out.write_arg(b"Q8"),
3690 VectorQuantization::Bin => out.write_arg(b"BIN"),
3691 }
3692 }
3693
3694 if let Some(exploration_factor) = self.build_exploration_factor {
3695 out.write_arg(b"EF");
3696 out.write_arg_fmt(exploration_factor);
3697 }
3698
3699 if let Some(ref attrs) = self.attributes {
3700 out.write_arg(b"SETATTR");
3701 out.write_arg(&serde_json::to_vec(&attrs).unwrap());
3702 }
3703
3704 if let Some(max_links) = self.max_number_of_links {
3705 out.write_arg(b"M");
3706 out.write_arg_fmt(max_links);
3707 }
3708 }
3709}
3710
3711/// Options for the VEMB command
3712///
3713/// # Example
3714/// ```rust,no_run
3715/// use redis::{Commands, RedisResult, VEmbOptions};
3716/// fn get_vector_embedding(
3717/// con: &mut redis::Connection,
3718/// key: &str,
3719/// element: &str,
3720/// ) -> RedisResult<redis::Value> {
3721/// let opts = VEmbOptions::default().set_raw_representation(true);
3722/// con.vemb_options(key, element, &opts)
3723/// }
3724/// ```
3725#[cfg(feature = "vector-sets")]
3726#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3727#[derive(Clone, Default)]
3728pub struct VEmbOptions {
3729 /// Returns the raw internal representation of the approximate vector associated with a given element in the vector set
3730 raw_representation: bool,
3731}
3732
3733#[cfg(feature = "vector-sets")]
3734impl VEmbOptions {
3735 /// Set the raw representation flag
3736 pub fn set_raw_representation(mut self, enabled: bool) -> Self {
3737 self.raw_representation = enabled;
3738 self
3739 }
3740}
3741
3742#[cfg(feature = "vector-sets")]
3743impl ToRedisArgs for VEmbOptions {
3744 fn write_redis_args<W>(&self, out: &mut W)
3745 where
3746 W: ?Sized + RedisWrite,
3747 {
3748 if self.raw_representation {
3749 out.write_arg(b"RAW");
3750 }
3751 }
3752}
3753
3754/// Represents different ways to input query data for vector similarity search commands
3755#[cfg(feature = "vector-sets")]
3756#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3757#[derive(Clone)]
3758pub enum VectorSimilaritySearchInput<'a> {
3759 /// Binary representation of 32-bit floating point values to use as a reference
3760 Fp32(&'a [f32]),
3761 /// List of values to use as a reference
3762 Values(EmbeddingInput<'a>),
3763 /// Element to use as a reference
3764 Element(&'a str),
3765}
3766
3767#[cfg(feature = "vector-sets")]
3768impl<'a> ToRedisArgs for VectorSimilaritySearchInput<'a> {
3769 fn write_redis_args<W>(&self, out: &mut W)
3770 where
3771 W: ?Sized + RedisWrite,
3772 {
3773 match self {
3774 VectorSimilaritySearchInput::Fp32(vector) => {
3775 use std::io::Write;
3776 out.write_arg(b"FP32");
3777 let mut writer = out.writer_for_next_arg();
3778 for &f in *vector {
3779 writer.write_all(&f.to_le_bytes()).unwrap();
3780 }
3781 }
3782 VectorSimilaritySearchInput::Values(embedding_input) => {
3783 out.write_arg(b"VALUES");
3784 embedding_input.write_redis_args(out);
3785 }
3786 VectorSimilaritySearchInput::Element(element) => {
3787 out.write_arg(b"ELE");
3788 element.write_redis_args(out);
3789 }
3790 }
3791 }
3792}
3793
3794/// Options for the VSIM command
3795///
3796/// # Example
3797/// ```rust,no_run
3798/// use redis::{Commands, RedisResult, VSimOptions};
3799/// fn search_similar_vectors(
3800/// con: &mut redis::Connection,
3801/// key: &str,
3802/// element: &str,
3803/// ) -> RedisResult<redis::Value> {
3804/// let opts = VSimOptions::default()
3805/// .set_with_scores(true)
3806/// .set_count(10)
3807/// .set_search_exploration_factor(100)
3808/// .set_filter_expression(".size == \"large\"")
3809/// .set_max_filtering_effort(10)
3810/// .set_truth(true)
3811/// .set_no_thread(true);
3812/// con.vsim_options(key, redis::VectorSimilaritySearchInput::Element(element), &opts)
3813/// }
3814/// ```
3815#[cfg(feature = "vector-sets")]
3816#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
3817#[derive(Clone, Default)]
3818pub struct VSimOptions {
3819 /// Include similarity scores in the results
3820 with_scores: bool,
3821 /// Limit the number of results returned
3822 count: Option<usize>,
3823 /// Controls the search effort. Higher values explore more nodes, improving recall at the cost of speed.
3824 /// Typical values range from 50 to 1000.
3825 search_exploration_factor: Option<usize>,
3826 /// JSON filter expression to apply to the results
3827 filter: Option<String>,
3828 /// Limits the number of filtering attempts for the FILTER expression.
3829 /// The accuracy improves the with higher values, but the search may take longer.
3830 filter_max_effort: Option<usize>,
3831 /// Forces an exact linear scan of all elements, bypassing the HNSW graph.
3832 /// Use for benchmarking or to calculate recall. This is significantly slower (O(N)).
3833 truth: bool,
3834 /// Executes the search in the main thread instead of a background thread.
3835 /// Useful for small vector sets or benchmarks. This may block the server during execution!
3836 no_thread: bool,
3837}
3838
3839#[cfg(feature = "vector-sets")]
3840impl VSimOptions {
3841 /// Include similarity scores in the results
3842 pub fn set_with_scores(mut self, enabled: bool) -> Self {
3843 self.with_scores = enabled;
3844 self
3845 }
3846
3847 /// Limit the number of results returned
3848 pub fn set_count(mut self, count: usize) -> Self {
3849 self.count = Some(count);
3850 self
3851 }
3852
3853 /// Set the search exploration factor
3854 pub fn set_search_exploration_factor(mut self, factor: usize) -> Self {
3855 self.search_exploration_factor = Some(factor);
3856 self
3857 }
3858
3859 /// Set a JSON filter expression
3860 pub fn set_filter_expression<S: Into<String>>(mut self, expression: S) -> Self {
3861 self.filter = Some(expression.into());
3862 self
3863 }
3864
3865 /// Set the maximum filtering effort
3866 pub fn set_max_filtering_effort(mut self, effort: usize) -> Self {
3867 self.filter_max_effort = Some(effort);
3868 self
3869 }
3870
3871 /// Enable/disable exact linear scan of all elements
3872 pub fn set_truth(mut self, enabled: bool) -> Self {
3873 self.truth = enabled;
3874 self
3875 }
3876
3877 /// Enable/disable multi-threading
3878 pub fn set_no_thread(mut self, enabled: bool) -> Self {
3879 self.no_thread = enabled;
3880 self
3881 }
3882}
3883
3884#[cfg(feature = "vector-sets")]
3885impl ToRedisArgs for VSimOptions {
3886 fn write_redis_args<W>(&self, out: &mut W)
3887 where
3888 W: ?Sized + RedisWrite,
3889 {
3890 if self.with_scores {
3891 out.write_arg(b"WITHSCORES");
3892 }
3893
3894 if let Some(count) = self.count {
3895 out.write_arg(b"COUNT");
3896 out.write_arg_fmt(count);
3897 }
3898
3899 if let Some(ef) = self.search_exploration_factor {
3900 out.write_arg(b"EF");
3901 out.write_arg_fmt(ef);
3902 }
3903
3904 if let Some(ref filter) = self.filter {
3905 out.write_arg(b"FILTER");
3906 out.write_arg(filter.as_bytes());
3907 }
3908
3909 if let Some(filter_ef) = self.filter_max_effort {
3910 out.write_arg(b"FILTER-EF");
3911 out.write_arg_fmt(filter_ef);
3912 }
3913
3914 if self.truth {
3915 out.write_arg(b"TRUTH");
3916 }
3917
3918 if self.no_thread {
3919 out.write_arg(b"NOTHREAD");
3920 }
3921 }
3922}
3923
3924/// Creates HELLO command for RESP3 with RedisConnectionInfo
3925/// [Redis Docs](https://redis.io/commands/HELLO)
3926pub fn resp3_hello(connection_info: &RedisConnectionInfo) -> Cmd {
3927 let mut hello_cmd = cmd("HELLO");
3928 hello_cmd.arg("3");
3929 if let Some(password) = &connection_info.password {
3930 let username: &str = match connection_info.username.as_ref() {
3931 None => "default",
3932 Some(username) => username,
3933 };
3934 hello_cmd.arg("AUTH").arg(username).arg(password);
3935 }
3936
3937 hello_cmd
3938}