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