redis/commands/
mod.rs

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