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