mco_redis_rs/commands.rs
1// can't use rustfmt here because it screws up the file.
2#![cfg_attr(rustfmt, rustfmt_skip)]
3use crate::cmd::{cmd, Cmd, Iter};
4use crate::connection::{Connection, ConnectionLike, Msg};
5use crate::pipeline::Pipeline;
6use crate::types::{FromRedisValue, NumericBehavior, RedisResult, ToRedisArgs, RedisWrite};
7
8#[cfg(feature = "cluster")]
9use crate::cluster_pipeline::ClusterPipeline;
10
11#[cfg(feature = "geospatial")]
12use crate::geo;
13
14#[cfg(feature = "streams")]
15use crate::streams;
16
17#[cfg(feature = "acl")]
18use crate::acl;
19
20macro_rules! implement_commands {
21 (
22 $lifetime: lifetime
23 $(
24 $(#[$attr:meta])+
25 fn $name:ident<$($tyargs:ident : $ty:ident),*>(
26 $($argname:ident: $argty:ty),*) $body:block
27 )*
28 ) =>
29 (
30 /// Implements common redis commands for connection like objects. This
31 /// allows you to send commands straight to a connection or client. It
32 /// is also implemented for redis results of clients which makes for
33 /// very convenient access in some basic cases.
34 ///
35 /// This allows you to use nicer syntax for some common operations.
36 /// For instance this code:
37 ///
38 /// ```rust,no_run
39 /// # fn do_something() -> redis::RedisResult<()> {
40 /// let client = redis::Client::open("redis://127.0.0.1/")?;
41 /// let mut con = client.get_connection()?;
42 /// redis::cmd("SET").arg("my_key").arg(42).execute(&mut con);
43 /// assert_eq!(redis::cmd("GET").arg("my_key").query(&mut con), Ok(42));
44 /// # Ok(()) }
45 /// ```
46 ///
47 /// Will become this:
48 ///
49 /// ```rust,no_run
50 /// # fn do_something() -> redis::RedisResult<()> {
51 /// use redis::Commands;
52 /// let client = redis::Client::open("redis://127.0.0.1/")?;
53 /// let mut con = client.get_connection()?;
54 /// con.set("my_key", 42)?;
55 /// assert_eq!(con.get("my_key"), Ok(42));
56 /// # Ok(()) }
57 /// ```
58 pub trait Commands : ConnectionLike+Sized {
59 $(
60 $(#[$attr])*
61 #[inline]
62 #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
63 fn $name<$lifetime, $($tyargs: $ty, )* RV: FromRedisValue>(
64 &mut self $(, $argname: $argty)*) -> RedisResult<RV>
65 { Cmd::$name($($argname),*).query(self) }
66 )*
67
68 /// Incrementally iterate the keys space.
69 #[inline]
70 fn scan<RV: FromRedisValue>(&mut self) -> RedisResult<Iter<'_, RV>> {
71 let mut c = cmd("SCAN");
72 c.cursor_arg(0);
73 c.iter(self)
74 }
75
76 /// Incrementally iterate the keys space for keys matching a pattern.
77 #[inline]
78 fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> RedisResult<Iter<'_, RV>> {
79 let mut c = cmd("SCAN");
80 c.cursor_arg(0).arg("MATCH").arg(pattern);
81 c.iter(self)
82 }
83
84 /// Incrementally iterate hash fields and associated values.
85 #[inline]
86 fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
87 let mut c = cmd("HSCAN");
88 c.arg(key).cursor_arg(0);
89 c.iter(self)
90 }
91
92 /// Incrementally iterate hash fields and associated values for
93 /// field names matching a pattern.
94 #[inline]
95 fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
96 (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
97 let mut c = cmd("HSCAN");
98 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
99 c.iter(self)
100 }
101
102 /// Incrementally iterate set elements.
103 #[inline]
104 fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
105 let mut c = cmd("SSCAN");
106 c.arg(key).cursor_arg(0);
107 c.iter(self)
108 }
109
110 /// Incrementally iterate set elements for elements matching a pattern.
111 #[inline]
112 fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
113 (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
114 let mut c = cmd("SSCAN");
115 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
116 c.iter(self)
117 }
118
119 /// Incrementally iterate sorted set elements.
120 #[inline]
121 fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
122 let mut c = cmd("ZSCAN");
123 c.arg(key).cursor_arg(0);
124 c.iter(self)
125 }
126
127 /// Incrementally iterate sorted set elements for elements matching a pattern.
128 #[inline]
129 fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
130 (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
131 let mut c = cmd("ZSCAN");
132 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
133 c.iter(self)
134 }
135 }
136
137 impl Cmd {
138 $(
139 $(#[$attr])*
140 #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
141 pub fn $name<$lifetime, $($tyargs: $ty),*>($($argname: $argty),*) -> Self {
142 ::std::mem::replace($body, Cmd::new())
143 }
144 )*
145 }
146
147 /// Implements common redis commands over asynchronous connections. This
148 /// allows you to send commands straight to a connection or client.
149 ///
150 /// This allows you to use nicer syntax for some common operations.
151 /// For instance this code:
152 ///
153 /// ```rust,no_run
154 /// use redis::AsyncCommands;
155 /// # async fn do_something() -> redis::RedisResult<()> {
156 /// let client = redis::Client::open("redis://127.0.0.1/")?;
157 /// let mut con = client.get_async_connection().await?;
158 /// redis::cmd("SET").arg("my_key").arg(42i32).query_async(&mut con).await?;
159 /// assert_eq!(redis::cmd("GET").arg("my_key").query_async(&mut con).await, Ok(42i32));
160 /// # Ok(()) }
161 /// ```
162 ///
163 /// Will become this:
164 ///
165 /// ```rust,no_run
166 /// use redis::AsyncCommands;
167 /// # async fn do_something() -> redis::RedisResult<()> {
168 /// use redis::Commands;
169 /// let client = redis::Client::open("redis://127.0.0.1/")?;
170 /// let mut con = client.get_async_connection().await?;
171 /// con.set("my_key", 42i32).await?;
172 /// assert_eq!(con.get("my_key").await, Ok(42i32));
173 /// # Ok(()) }
174 /// ```
175 #[cfg(feature = "aio")]
176 pub trait AsyncCommands : crate::aio::ConnectionLike + Send + Sized {
177 $(
178 $(#[$attr])*
179 #[inline]
180 #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
181 fn $name<$lifetime, $($tyargs: $ty + Send + Sync + $lifetime,)* RV>(
182 & $lifetime mut self
183 $(, $argname: $argty)*
184 ) -> crate::types::RedisFuture<'a, RV>
185 where
186 RV: FromRedisValue,
187 {
188 Box::pin(async move { ($body).query_async(self).await })
189 }
190 )*
191
192 /// Incrementally iterate the keys space.
193 #[inline]
194 fn scan<RV: FromRedisValue>(&mut self) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
195 let mut c = cmd("SCAN");
196 c.cursor_arg(0);
197 Box::pin(async move { c.iter_async(self).await })
198 }
199
200 /// Incrementally iterate set elements for elements matching a pattern.
201 #[inline]
202 fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
203 let mut c = cmd("SCAN");
204 c.cursor_arg(0).arg("MATCH").arg(pattern);
205 Box::pin(async move { c.iter_async(self).await })
206 }
207
208 /// Incrementally iterate hash fields and associated values.
209 #[inline]
210 fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
211 let mut c = cmd("HSCAN");
212 c.arg(key).cursor_arg(0);
213 Box::pin(async move {c.iter_async(self).await })
214 }
215
216 /// Incrementally iterate hash fields and associated values for
217 /// field names matching a pattern.
218 #[inline]
219 fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
220 (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
221 let mut c = cmd("HSCAN");
222 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
223 Box::pin(async move {c.iter_async(self).await })
224 }
225
226 /// Incrementally iterate set elements.
227 #[inline]
228 fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
229 let mut c = cmd("SSCAN");
230 c.arg(key).cursor_arg(0);
231 Box::pin(async move {c.iter_async(self).await })
232 }
233
234 /// Incrementally iterate set elements for elements matching a pattern.
235 #[inline]
236 fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
237 (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
238 let mut c = cmd("SSCAN");
239 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
240 Box::pin(async move {c.iter_async(self).await })
241 }
242
243 /// Incrementally iterate sorted set elements.
244 #[inline]
245 fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
246 let mut c = cmd("ZSCAN");
247 c.arg(key).cursor_arg(0);
248 Box::pin(async move {c.iter_async(self).await })
249 }
250
251 /// Incrementally iterate sorted set elements for elements matching a pattern.
252 #[inline]
253 fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
254 (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
255 let mut c = cmd("ZSCAN");
256 c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
257 Box::pin(async move {c.iter_async(self).await })
258 }
259 }
260
261 /// Implements common redis commands for pipelines. Unlike the regular
262 /// commands trait, this returns the pipeline rather than a result
263 /// directly. Other than that it works the same however.
264 impl Pipeline {
265 $(
266 $(#[$attr])*
267 #[inline]
268 #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
269 pub fn $name<$lifetime, $($tyargs: $ty),*>(
270 &mut self $(, $argname: $argty)*
271 ) -> &mut Self {
272 self.add_command(::std::mem::replace($body, Cmd::new()))
273 }
274 )*
275 }
276
277 // Implements common redis commands for cluster pipelines. Unlike the regular
278 // commands trait, this returns the cluster pipeline rather than a result
279 // directly. Other than that it works the same however.
280 #[cfg(feature = "cluster")]
281 impl ClusterPipeline {
282 $(
283 $(#[$attr])*
284 #[inline]
285 #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
286 pub fn $name<$lifetime, $($tyargs: $ty),*>(
287 &mut self $(, $argname: $argty)*
288 ) -> &mut Self {
289 self.add_command(::std::mem::replace($body, Cmd::new()))
290 }
291 )*
292 }
293 )
294}
295
296implement_commands! {
297 'a
298 // most common operations
299
300 /// Get the value of a key. If key is a vec this becomes an `MGET`.
301 fn get<K: ToRedisArgs>(key: K) {
302 cmd(if key.is_single_arg() { "GET" } else { "MGET" }).arg(key)
303 }
304
305 /// Gets all keys matching pattern
306 fn keys<K: ToRedisArgs>(key: K) {
307 cmd("KEYS").arg(key)
308 }
309
310 /// Set the string value of a key.
311 fn set<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
312 cmd("SET").arg(key).arg(value)
313 }
314
315 /// Sets multiple keys to their values.
316 fn set_multiple<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
317 cmd("MSET").arg(items)
318 }
319
320 /// Set the value and expiration of a key.
321 fn set_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, seconds: usize) {
322 cmd("SETEX").arg(key).arg(seconds).arg(value)
323 }
324
325 /// Set the value and expiration in milliseconds of a key.
326 fn pset_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, milliseconds: usize) {
327 cmd("PSETEX").arg(key).arg(milliseconds).arg(value)
328 }
329
330 /// Set the value of a key, only if the key does not exist
331 fn set_nx<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
332 cmd("SETNX").arg(key).arg(value)
333 }
334
335 /// Sets multiple keys to their values failing if at least one already exists.
336 fn mset_nx<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]) {
337 cmd("MSETNX").arg(items)
338 }
339
340 /// Set the string value of a key and return its old value.
341 fn getset<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
342 cmd("GETSET").arg(key).arg(value)
343 }
344
345 /// Get a range of bytes/substring from the value of a key. Negative values provide an offset from the end of the value.
346 fn getrange<K: ToRedisArgs>(key: K, from: isize, to: isize) {
347 cmd("GETRANGE").arg(key).arg(from).arg(to)
348 }
349
350 /// Overwrite the part of the value stored in key at the specified offset.
351 fn setrange<K: ToRedisArgs, V: ToRedisArgs>(key: K, offset: isize, value: V) {
352 cmd("SETRANGE").arg(key).arg(offset).arg(value)
353 }
354
355 /// Delete one or more keys.
356 fn del<K: ToRedisArgs>(key: K) {
357 cmd("DEL").arg(key)
358 }
359
360 /// Determine if a key exists.
361 fn exists<K: ToRedisArgs>(key: K) {
362 cmd("EXISTS").arg(key)
363 }
364
365 /// Set a key's time to live in seconds.
366 fn expire<K: ToRedisArgs>(key: K, seconds: usize) {
367 cmd("EXPIRE").arg(key).arg(seconds)
368 }
369
370 /// Set the expiration for a key as a UNIX timestamp.
371 fn expire_at<K: ToRedisArgs>(key: K, ts: usize) {
372 cmd("EXPIREAT").arg(key).arg(ts)
373 }
374
375 /// Set a key's time to live in milliseconds.
376 fn pexpire<K: ToRedisArgs>(key: K, ms: usize) {
377 cmd("PEXPIRE").arg(key).arg(ms)
378 }
379
380 /// Set the expiration for a key as a UNIX timestamp in milliseconds.
381 fn pexpire_at<K: ToRedisArgs>(key: K, ts: usize) {
382 cmd("PEXPIREAT").arg(key).arg(ts)
383 }
384
385 /// Remove the expiration from a key.
386 fn persist<K: ToRedisArgs>(key: K) {
387 cmd("PERSIST").arg(key)
388 }
389
390 /// Get the expiration time of a key.
391 fn ttl<K: ToRedisArgs>(key: K) {
392 cmd("TTL").arg(key)
393 }
394
395 /// Get the expiration time of a key in milliseconds.
396 fn pttl<K: ToRedisArgs>(key: K) {
397 cmd("PTTL").arg(key)
398 }
399
400 /// Rename a key.
401 fn rename<K: ToRedisArgs>(key: K, new_key: K) {
402 cmd("RENAME").arg(key).arg(new_key)
403 }
404
405 /// Rename a key, only if the new key does not exist.
406 fn rename_nx<K: ToRedisArgs>(key: K, new_key: K) {
407 cmd("RENAMENX").arg(key).arg(new_key)
408 }
409
410 /// Unlink one or more keys.
411 fn unlink<K: ToRedisArgs>(key: K) {
412 cmd("UNLINK").arg(key)
413 }
414
415 // common string operations
416
417 /// Append a value to a key.
418 fn append<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
419 cmd("APPEND").arg(key).arg(value)
420 }
421
422 /// Increment the numeric value of a key by the given amount. This
423 /// issues a `INCRBY` or `INCRBYFLOAT` depending on the type.
424 fn incr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
425 cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
426 "INCRBYFLOAT"
427 } else {
428 "INCRBY"
429 }).arg(key).arg(delta)
430 }
431
432 /// Decrement the numeric value of a key by the given amount.
433 fn decr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V) {
434 cmd("DECRBY").arg(key).arg(delta)
435 }
436
437 /// Sets or clears the bit at offset in the string value stored at key.
438 fn setbit<K: ToRedisArgs>(key: K, offset: usize, value: bool) {
439 cmd("SETBIT").arg(key).arg(offset).arg(if value {1} else {0})
440 }
441
442 /// Returns the bit value at offset in the string value stored at key.
443 fn getbit<K: ToRedisArgs>(key: K, offset: usize) {
444 cmd("GETBIT").arg(key).arg(offset)
445 }
446
447 /// Count set bits in a string.
448 fn bitcount<K: ToRedisArgs>(key: K) {
449 cmd("BITCOUNT").arg(key)
450 }
451
452 /// Count set bits in a string in a range.
453 fn bitcount_range<K: ToRedisArgs>(key: K, start: usize, end: usize) {
454 cmd("BITCOUNT").arg(key).arg(start).arg(end)
455 }
456
457 /// Perform a bitwise AND between multiple keys (containing string values)
458 /// and store the result in the destination key.
459 fn bit_and<K: ToRedisArgs>(dstkey: K, srckeys: K) {
460 cmd("BITOP").arg("AND").arg(dstkey).arg(srckeys)
461 }
462
463 /// Perform a bitwise OR between multiple keys (containing string values)
464 /// and store the result in the destination key.
465 fn bit_or<K: ToRedisArgs>(dstkey: K, srckeys: K) {
466 cmd("BITOP").arg("OR").arg(dstkey).arg(srckeys)
467 }
468
469 /// Perform a bitwise XOR between multiple keys (containing string values)
470 /// and store the result in the destination key.
471 fn bit_xor<K: ToRedisArgs>(dstkey: K, srckeys: K) {
472 cmd("BITOP").arg("XOR").arg(dstkey).arg(srckeys)
473 }
474
475 /// Perform a bitwise NOT of the key (containing string values)
476 /// and store the result in the destination key.
477 fn bit_not<K: ToRedisArgs>(dstkey: K, srckey: K) {
478 cmd("BITOP").arg("NOT").arg(dstkey).arg(srckey)
479 }
480
481 /// Get the length of the value stored in a key.
482 fn strlen<K: ToRedisArgs>(key: K) {
483 cmd("STRLEN").arg(key)
484 }
485
486 // hash operations
487
488 /// Gets a single (or multiple) fields from a hash.
489 fn hget<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
490 cmd(if field.is_single_arg() { "HGET" } else { "HMGET" }).arg(key).arg(field)
491 }
492
493 /// Deletes a single (or multiple) fields from a hash.
494 fn hdel<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
495 cmd("HDEL").arg(key).arg(field)
496 }
497
498 /// Sets a single field in a hash.
499 fn hset<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
500 cmd("HSET").arg(key).arg(field).arg(value)
501 }
502
503 /// Sets a single field in a hash if it does not exist.
504 fn hset_nx<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V) {
505 cmd("HSETNX").arg(key).arg(field).arg(value)
506 }
507
508 /// Sets a multiple fields in a hash.
509 fn hset_multiple<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, items: &'a [(F, V)]) {
510 cmd("HMSET").arg(key).arg(items)
511 }
512
513 /// Increments a value.
514 fn hincr<K: ToRedisArgs, F: ToRedisArgs, D: ToRedisArgs>(key: K, field: F, delta: D) {
515 cmd(if delta.describe_numeric_behavior() == NumericBehavior::NumberIsFloat {
516 "HINCRBYFLOAT"
517 } else {
518 "HINCRBY"
519 }).arg(key).arg(field).arg(delta)
520 }
521
522 /// Checks if a field in a hash exists.
523 fn hexists<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F) {
524 cmd("HEXISTS").arg(key).arg(field)
525 }
526
527 /// Gets all the keys in a hash.
528 fn hkeys<K: ToRedisArgs>(key: K) {
529 cmd("HKEYS").arg(key)
530 }
531
532 /// Gets all the values in a hash.
533 fn hvals<K: ToRedisArgs>(key: K) {
534 cmd("HVALS").arg(key)
535 }
536
537 /// Gets all the fields and values in a hash.
538 fn hgetall<K: ToRedisArgs>(key: K) {
539 cmd("HGETALL").arg(key)
540 }
541
542 /// Gets the length of a hash.
543 fn hlen<K: ToRedisArgs>(key: K) {
544 cmd("HLEN").arg(key)
545 }
546
547 // list operations
548
549 /// Pop an element from a list, push it to another list
550 /// and return it; or block until one is available
551 fn blmove<K: ToRedisArgs>(srckey: K, dstkey: K, src_dir: Direction, dst_dir: Direction, timeout: usize) {
552 cmd("BLMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir).arg(timeout)
553 }
554
555 /// Pops `count` elements from the first non-empty list key from the list of
556 /// provided key names; or blocks until one is available.
557 fn blmpop<K: ToRedisArgs>(timeout: usize, numkeys: usize, key: K, dir: Direction, count: usize){
558 cmd("BLMPOP").arg(timeout).arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
559 }
560
561 /// Remove and get the first element in a list, or block until one is available.
562 fn blpop<K: ToRedisArgs>(key: K, timeout: usize) {
563 cmd("BLPOP").arg(key).arg(timeout)
564 }
565
566 /// Remove and get the last element in a list, or block until one is available.
567 fn brpop<K: ToRedisArgs>(key: K, timeout: usize) {
568 cmd("BRPOP").arg(key).arg(timeout)
569 }
570
571 /// Pop a value from a list, push it to another list and return it;
572 /// or block until one is available.
573 fn brpoplpush<K: ToRedisArgs>(srckey: K, dstkey: K, timeout: usize) {
574 cmd("BRPOPLPUSH").arg(srckey).arg(dstkey).arg(timeout)
575 }
576
577 /// Get an element from a list by its index.
578 fn lindex<K: ToRedisArgs>(key: K, index: isize) {
579 cmd("LINDEX").arg(key).arg(index)
580 }
581
582 /// Insert an element before another element in a list.
583 fn linsert_before<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
584 key: K, pivot: P, value: V) {
585 cmd("LINSERT").arg(key).arg("BEFORE").arg(pivot).arg(value)
586 }
587
588 /// Insert an element after another element in a list.
589 fn linsert_after<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(
590 key: K, pivot: P, value: V) {
591 cmd("LINSERT").arg(key).arg("AFTER").arg(pivot).arg(value)
592 }
593
594 /// Returns the length of the list stored at key.
595 fn llen<K: ToRedisArgs>(key: K) {
596 cmd("LLEN").arg(key)
597 }
598
599 /// Pop an element a list, push it to another list and return it
600 fn lmove<K: ToRedisArgs>(srckey: K, dstkey: K, src_dir: Direction, dst_dir: Direction) {
601 cmd("LMOVE").arg(srckey).arg(dstkey).arg(src_dir).arg(dst_dir)
602 }
603
604 /// Pops `count` elements from the first non-empty list key from the list of
605 /// provided key names.
606 fn lmpop<K: ToRedisArgs>( numkeys: usize, key: K, dir: Direction, count: usize) {
607 cmd("LMPOP").arg(numkeys).arg(key).arg(dir).arg("COUNT").arg(count)
608 }
609
610 /// Removes and returns the up to `count` first elements of the list stored at key.
611 ///
612 /// If `count` is not specified, then defaults to first element.
613 fn lpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
614 cmd("LPOP").arg(key).arg(count)
615 }
616
617 /// Returns the index of the first matching value of the list stored at key.
618 fn lpos<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: LposOptions) {
619 cmd("LPOS").arg(key).arg(value).arg(options)
620 }
621
622 /// Insert all the specified values at the head of the list stored at key.
623 fn lpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
624 cmd("LPUSH").arg(key).arg(value)
625 }
626
627 /// Inserts a value at the head of the list stored at key, only if key
628 /// already exists and holds a list.
629 fn lpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
630 cmd("LPUSHX").arg(key).arg(value)
631 }
632
633 /// Returns the specified elements of the list stored at key.
634 fn lrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
635 cmd("LRANGE").arg(key).arg(start).arg(stop)
636 }
637
638 /// Removes the first count occurrences of elements equal to value
639 /// from the list stored at key.
640 fn lrem<K: ToRedisArgs, V: ToRedisArgs>(key: K, count: isize, value: V) {
641 cmd("LREM").arg(key).arg(count).arg(value)
642 }
643
644 /// Trim an existing list so that it will contain only the specified
645 /// range of elements specified.
646 fn ltrim<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
647 cmd("LTRIM").arg(key).arg(start).arg(stop)
648 }
649
650 /// Sets the list element at index to value
651 fn lset<K: ToRedisArgs, V: ToRedisArgs>(key: K, index: isize, value: V) {
652 cmd("LSET").arg(key).arg(index).arg(value)
653 }
654
655 /// Removes and returns the up to `count` last elements of the list stored at key
656 ///
657 /// If `count` is not specified, then defaults to last element.
658 fn rpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>) {
659 cmd("RPOP").arg(key).arg(count)
660 }
661
662 /// Pop a value from a list, push it to another list and return it.
663 fn rpoplpush<K: ToRedisArgs>(key: K, dstkey: K) {
664 cmd("RPOPLPUSH").arg(key).arg(dstkey)
665 }
666
667 /// Insert all the specified values at the tail of the list stored at key.
668 fn rpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
669 cmd("RPUSH").arg(key).arg(value)
670 }
671
672 /// Inserts value at the tail of the list stored at key, only if key
673 /// already exists and holds a list.
674 fn rpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V) {
675 cmd("RPUSHX").arg(key).arg(value)
676 }
677
678 // set commands
679
680 /// Add one or more members to a set.
681 fn sadd<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
682 cmd("SADD").arg(key).arg(member)
683 }
684
685 /// Get the number of members in a set.
686 fn scard<K: ToRedisArgs>(key: K) {
687 cmd("SCARD").arg(key)
688 }
689
690 /// Subtract multiple sets.
691 fn sdiff<K: ToRedisArgs>(keys: K) {
692 cmd("SDIFF").arg(keys)
693 }
694
695 /// Subtract multiple sets and store the resulting set in a key.
696 fn sdiffstore<K: ToRedisArgs>(dstkey: K, keys: K) {
697 cmd("SDIFFSTORE").arg(dstkey).arg(keys)
698 }
699
700 /// Intersect multiple sets.
701 fn sinter<K: ToRedisArgs>(keys: K) {
702 cmd("SINTER").arg(keys)
703 }
704
705 /// Intersect multiple sets and store the resulting set in a key.
706 fn sinterstore<K: ToRedisArgs>(dstkey: K, keys: K) {
707 cmd("SINTERSTORE").arg(dstkey).arg(keys)
708 }
709
710 /// Determine if a given value is a member of a set.
711 fn sismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
712 cmd("SISMEMBER").arg(key).arg(member)
713 }
714
715 /// Get all the members in a set.
716 fn smembers<K: ToRedisArgs>(key: K) {
717 cmd("SMEMBERS").arg(key)
718 }
719
720 /// Move a member from one set to another.
721 fn smove<K: ToRedisArgs, M: ToRedisArgs>(srckey: K, dstkey: K, member: M) {
722 cmd("SMOVE").arg(srckey).arg(dstkey).arg(member)
723 }
724
725 /// Remove and return a random member from a set.
726 fn spop<K: ToRedisArgs>(key: K) {
727 cmd("SPOP").arg(key)
728 }
729
730 /// Get one random member from a set.
731 fn srandmember<K: ToRedisArgs>(key: K) {
732 cmd("SRANDMEMBER").arg(key)
733 }
734
735 /// Get multiple random members from a set.
736 fn srandmember_multiple<K: ToRedisArgs>(key: K, count: usize) {
737 cmd("SRANDMEMBER").arg(key).arg(count)
738 }
739
740 /// Remove one or more members from a set.
741 fn srem<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
742 cmd("SREM").arg(key).arg(member)
743 }
744
745 /// Add multiple sets.
746 fn sunion<K: ToRedisArgs>(keys: K) {
747 cmd("SUNION").arg(keys)
748 }
749
750 /// Add multiple sets and store the resulting set in a key.
751 fn sunionstore<K: ToRedisArgs>(dstkey: K, keys: K) {
752 cmd("SUNIONSTORE").arg(dstkey).arg(keys)
753 }
754
755 // sorted set commands
756
757 /// Add one member to a sorted set, or update its score if it already exists.
758 fn zadd<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, member: M, score: S) {
759 cmd("ZADD").arg(key).arg(score).arg(member)
760 }
761
762 /// Add multiple members to a sorted set, or update its score if it already exists.
763 fn zadd_multiple<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)]) {
764 cmd("ZADD").arg(key).arg(items)
765 }
766
767 /// Get the number of members in a sorted set.
768 fn zcard<K: ToRedisArgs>(key: K) {
769 cmd("ZCARD").arg(key)
770 }
771
772 /// Count the members in a sorted set with scores within the given values.
773 fn zcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
774 cmd("ZCOUNT").arg(key).arg(min).arg(max)
775 }
776
777 /// Increments the member in a sorted set at key by delta.
778 /// If the member does not exist, it is added with delta as its score.
779 fn zincr<K: ToRedisArgs, M: ToRedisArgs, D: ToRedisArgs>(key: K, member: M, delta: D) {
780 cmd("ZINCRBY").arg(key).arg(delta).arg(member)
781 }
782
783 /// Intersect multiple sorted sets and store the resulting sorted set in
784 /// a new key using SUM as aggregation function.
785 fn zinterstore<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
786 cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys)
787 }
788
789 /// Intersect multiple sorted sets and store the resulting sorted set in
790 /// a new key using MIN as aggregation function.
791 fn zinterstore_min<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
792 cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MIN")
793 }
794
795 /// Intersect multiple sorted sets and store the resulting sorted set in
796 /// a new key using MAX as aggregation function.
797 fn zinterstore_max<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
798 cmd("ZINTERSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MAX")
799 }
800
801 /// Count the number of members in a sorted set between a given lexicographical range.
802 fn zlexcount<K: ToRedisArgs, L: ToRedisArgs>(key: K, min: L, max: L) {
803 cmd("ZLEXCOUNT").arg(key).arg(min).arg(max)
804 }
805
806 /// Removes and returns up to count members with the highest scores in a sorted set
807 fn zpopmax<K: ToRedisArgs>(key: K, count: isize) {
808 cmd("ZPOPMAX").arg(key).arg(count)
809 }
810
811 /// Removes and returns up to count members with the lowest scores in a sorted set
812 fn zpopmin<K: ToRedisArgs>(key: K, count: isize) {
813 cmd("ZPOPMIN").arg(key).arg(count)
814 }
815
816 /// Return up to count random members in a sorted set (or 1 if `count == None`)
817 fn zrandmember<K: ToRedisArgs>(key: K, count: Option<isize>) {
818 cmd("ZRANDMEMBER").arg(key).arg(count)
819 }
820
821 /// Return up to count random members in a sorted set with scores
822 fn zrandmember_withscores<K: ToRedisArgs>(key: K, count: isize) {
823 cmd("ZRANDMEMBER").arg(key).arg(count).arg("WITHSCORES")
824 }
825
826 /// Return a range of members in a sorted set, by index
827 fn zrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
828 cmd("ZRANGE").arg(key).arg(start).arg(stop)
829 }
830
831 /// Return a range of members in a sorted set, by index with scores.
832 fn zrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
833 cmd("ZRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
834 }
835
836 /// Return a range of members in a sorted set, by lexicographical range.
837 fn zrangebylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
838 cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max)
839 }
840
841 /// Return a range of members in a sorted set, by lexicographical
842 /// range with offset and limit.
843 fn zrangebylex_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(
844 key: K, min: M, max: MM, offset: isize, count: isize) {
845 cmd("ZRANGEBYLEX").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
846 }
847
848 /// Return a range of members in a sorted set, by lexicographical range.
849 fn zrevrangebylex<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
850 cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min)
851 }
852
853 /// Return a range of members in a sorted set, by lexicographical
854 /// range with offset and limit.
855 fn zrevrangebylex_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(
856 key: K, max: MM, min: M, offset: isize, count: isize) {
857 cmd("ZREVRANGEBYLEX").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
858 }
859
860 /// Return a range of members in a sorted set, by score.
861 fn zrangebyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
862 cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max)
863 }
864
865 /// Return a range of members in a sorted set, by score with scores.
866 fn zrangebyscore_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
867 cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
868 }
869
870 /// Return a range of members in a sorted set, by score with limit.
871 fn zrangebyscore_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
872 (key: K, min: M, max: MM, offset: isize, count: isize) {
873 cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("LIMIT").arg(offset).arg(count)
874 }
875
876 /// Return a range of members in a sorted set, by score with limit with scores.
877 fn zrangebyscore_limit_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>
878 (key: K, min: M, max: MM, offset: isize, count: isize) {
879 cmd("ZRANGEBYSCORE").arg(key).arg(min).arg(max).arg("WITHSCORES")
880 .arg("LIMIT").arg(offset).arg(count)
881 }
882
883 /// Determine the index of a member in a sorted set.
884 fn zrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
885 cmd("ZRANK").arg(key).arg(member)
886 }
887
888 /// Remove one or more members from a sorted set.
889 fn zrem<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
890 cmd("ZREM").arg(key).arg(members)
891 }
892
893 /// Remove all members in a sorted set between the given lexicographical range.
894 fn zrembylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
895 cmd("ZREMRANGEBYLEX").arg(key).arg(min).arg(max)
896 }
897
898 /// Remove all members in a sorted set within the given indexes.
899 fn zremrangebyrank<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
900 cmd("ZREMRANGEBYRANK").arg(key).arg(start).arg(stop)
901 }
902
903 /// Remove all members in a sorted set within the given scores.
904 fn zrembyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM) {
905 cmd("ZREMRANGEBYSCORE").arg(key).arg(min).arg(max)
906 }
907
908 /// Return a range of members in a sorted set, by index, with scores
909 /// ordered from high to low.
910 fn zrevrange<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
911 cmd("ZREVRANGE").arg(key).arg(start).arg(stop)
912 }
913
914 /// Return a range of members in a sorted set, by index, with scores
915 /// ordered from high to low.
916 fn zrevrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize) {
917 cmd("ZREVRANGE").arg(key).arg(start).arg(stop).arg("WITHSCORES")
918 }
919
920 /// Return a range of members in a sorted set, by score.
921 fn zrevrangebyscore<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
922 cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min)
923 }
924
925 /// Return a range of members in a sorted set, by score with scores.
926 fn zrevrangebyscore_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M) {
927 cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
928 }
929
930 /// Return a range of members in a sorted set, by score with limit.
931 fn zrevrangebyscore_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
932 (key: K, max: MM, min: M, offset: isize, count: isize) {
933 cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("LIMIT").arg(offset).arg(count)
934 }
935
936 /// Return a range of members in a sorted set, by score with limit with scores.
937 fn zrevrangebyscore_limit_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>
938 (key: K, max: MM, min: M, offset: isize, count: isize) {
939 cmd("ZREVRANGEBYSCORE").arg(key).arg(max).arg(min).arg("WITHSCORES")
940 .arg("LIMIT").arg(offset).arg(count)
941 }
942
943 /// Determine the index of a member in a sorted set, with scores ordered from high to low.
944 fn zrevrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
945 cmd("ZREVRANK").arg(key).arg(member)
946 }
947
948 /// Get the score associated with the given member in a sorted set.
949 fn zscore<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M) {
950 cmd("ZSCORE").arg(key).arg(member)
951 }
952
953 /// Get the scores associated with multiple members in a sorted set.
954 fn zscore_multiple<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: &'a [M]) {
955 cmd("ZMSCORE").arg(key).arg(members)
956 }
957
958 /// Unions multiple sorted sets and store the resulting sorted set in
959 /// a new key using SUM as aggregation function.
960 fn zunionstore<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
961 cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys)
962 }
963
964 /// Unions multiple sorted sets and store the resulting sorted set in
965 /// a new key using MIN as aggregation function.
966 fn zunionstore_min<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
967 cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MIN")
968 }
969
970 /// Unions multiple sorted sets and store the resulting sorted set in
971 /// a new key using MAX as aggregation function.
972 fn zunionstore_max<K: ToRedisArgs>(dstkey: K, keys: &'a [K]) {
973 cmd("ZUNIONSTORE").arg(dstkey).arg(keys.len()).arg(keys).arg("AGGREGATE").arg("MAX")
974 }
975
976 // hyperloglog commands
977
978 /// Adds the specified elements to the specified HyperLogLog.
979 fn pfadd<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E) {
980 cmd("PFADD").arg(key).arg(element)
981 }
982
983 /// Return the approximated cardinality of the set(s) observed by the
984 /// HyperLogLog at key(s).
985 fn pfcount<K: ToRedisArgs>(key: K) {
986 cmd("PFCOUNT").arg(key)
987 }
988
989 /// Merge N different HyperLogLogs into a single one.
990 fn pfmerge<K: ToRedisArgs>(dstkey: K, srckeys: K) {
991 cmd("PFMERGE").arg(dstkey).arg(srckeys)
992 }
993
994 /// Posts a message to the given channel.
995 fn publish<K: ToRedisArgs, E: ToRedisArgs>(channel: K, message: E) {
996 cmd("PUBLISH").arg(channel).arg(message)
997 }
998
999 // ACL commands
1000
1001 /// When Redis is configured to use an ACL file (with the aclfile
1002 /// configuration option), this command will reload the ACLs from the file,
1003 /// replacing all the current ACL rules with the ones defined in the file.
1004 #[cfg(feature = "acl")]
1005 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1006 fn acl_load<>() {
1007 cmd("ACL").arg("LOAD")
1008 }
1009
1010 /// When Redis is configured to use an ACL file (with the aclfile
1011 /// configuration option), this command will save the currently defined
1012 /// ACLs from the server memory to the ACL file.
1013 #[cfg(feature = "acl")]
1014 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1015 fn acl_save<>() {
1016 cmd("ACL").arg("SAVE")
1017 }
1018
1019 /// Shows the currently active ACL rules in the Redis server.
1020 #[cfg(feature = "acl")]
1021 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1022 fn acl_list<>() {
1023 cmd("ACL").arg("LIST")
1024 }
1025
1026 /// Shows a list of all the usernames of the currently configured users in
1027 /// the Redis ACL system.
1028 #[cfg(feature = "acl")]
1029 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1030 fn acl_users<>() {
1031 cmd("ACL").arg("USERS")
1032 }
1033
1034 /// Returns all the rules defined for an existing ACL user.
1035 #[cfg(feature = "acl")]
1036 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1037 fn acl_getuser<K: ToRedisArgs>(username: K) {
1038 cmd("ACL").arg("GETUSER").arg(username)
1039 }
1040
1041 /// Creates an ACL user without any privilege.
1042 #[cfg(feature = "acl")]
1043 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1044 fn acl_setuser<K: ToRedisArgs>(username: K) {
1045 cmd("ACL").arg("SETUSER").arg(username)
1046 }
1047
1048 /// Creates an ACL user with the specified rules or modify the rules of
1049 /// an existing user.
1050 #[cfg(feature = "acl")]
1051 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1052 fn acl_setuser_rules<K: ToRedisArgs>(username: K, rules: &'a [acl::Rule]) {
1053 cmd("ACL").arg("SETUSER").arg(username).arg(rules)
1054 }
1055
1056 /// Delete all the specified ACL users and terminate all the connections
1057 /// that are authenticated with such users.
1058 #[cfg(feature = "acl")]
1059 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1060 fn acl_deluser<K: ToRedisArgs>(usernames: &'a [K]) {
1061 cmd("ACL").arg("DELUSER").arg(usernames)
1062 }
1063
1064 /// Shows the available ACL categories.
1065 #[cfg(feature = "acl")]
1066 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1067 fn acl_cat<>() {
1068 cmd("ACL").arg("CAT")
1069 }
1070
1071 /// Shows all the Redis commands in the specified category.
1072 #[cfg(feature = "acl")]
1073 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1074 fn acl_cat_categoryname<K: ToRedisArgs>(categoryname: K) {
1075 cmd("ACL").arg("CAT").arg(categoryname)
1076 }
1077
1078 /// Generates a 256-bits password starting from /dev/urandom if available.
1079 #[cfg(feature = "acl")]
1080 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1081 fn acl_genpass<>() {
1082 cmd("ACL").arg("GENPASS")
1083 }
1084
1085 /// Generates a 1-to-1024-bits password starting from /dev/urandom if available.
1086 #[cfg(feature = "acl")]
1087 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1088 fn acl_genpass_bits<>(bits: isize) {
1089 cmd("ACL").arg("GENPASS").arg(bits)
1090 }
1091
1092 /// Returns the username the current connection is authenticated with.
1093 #[cfg(feature = "acl")]
1094 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1095 fn acl_whoami<>() {
1096 cmd("ACL").arg("WHOAMI")
1097 }
1098
1099 /// Shows a list of recent ACL security events
1100 #[cfg(feature = "acl")]
1101 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1102 fn acl_log<>(count: isize) {
1103 cmd("ACL").arg("LOG").arg(count)
1104
1105 }
1106
1107 /// Clears the ACL log.
1108 #[cfg(feature = "acl")]
1109 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1110 fn acl_log_reset<>() {
1111 cmd("ACL").arg("LOG").arg("RESET")
1112 }
1113
1114 /// Returns a helpful text describing the different subcommands.
1115 #[cfg(feature = "acl")]
1116 #[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
1117 fn acl_help<>() {
1118 cmd("ACL").arg("HELP")
1119 }
1120
1121 //
1122 // geospatial commands
1123 //
1124
1125 /// Adds the specified geospatial items to the specified key.
1126 ///
1127 /// Every member has to be written as a tuple of `(longitude, latitude,
1128 /// member_name)`. It can be a single tuple, or a vector of tuples.
1129 ///
1130 /// `longitude, latitude` can be set using [`redis::geo::Coord`][1].
1131 ///
1132 /// [1]: ./geo/struct.Coord.html
1133 ///
1134 /// Returns the number of elements added to the sorted set, not including
1135 /// elements already existing for which the score was updated.
1136 ///
1137 /// # Example
1138 ///
1139 /// ```rust,no_run
1140 /// use redis::{Commands, Connection, RedisResult};
1141 /// use redis::geo::Coord;
1142 ///
1143 /// fn add_point(con: &mut Connection) -> RedisResult<isize> {
1144 /// con.geo_add("my_gis", (Coord::lon_lat(13.361389, 38.115556), "Palermo"))
1145 /// }
1146 ///
1147 /// fn add_point_with_tuples(con: &mut Connection) -> RedisResult<isize> {
1148 /// con.geo_add("my_gis", ("13.361389", "38.115556", "Palermo"))
1149 /// }
1150 ///
1151 /// fn add_many_points(con: &mut Connection) -> RedisResult<isize> {
1152 /// con.geo_add("my_gis", &[
1153 /// ("13.361389", "38.115556", "Palermo"),
1154 /// ("15.087269", "37.502669", "Catania")
1155 /// ])
1156 /// }
1157 /// ```
1158 #[cfg(feature = "geospatial")]
1159 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1160 fn geo_add<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1161 cmd("GEOADD").arg(key).arg(members)
1162 }
1163
1164 /// Return the distance between two members in the geospatial index
1165 /// represented by the sorted set.
1166 ///
1167 /// If one or both the members are missing, the command returns NULL, so
1168 /// it may be convenient to parse its response as either `Option<f64>` or
1169 /// `Option<String>`.
1170 ///
1171 /// # Example
1172 ///
1173 /// ```rust,no_run
1174 /// use redis::{Commands, RedisResult};
1175 /// use redis::geo::Unit;
1176 ///
1177 /// fn get_dists(con: &mut redis::Connection) {
1178 /// let x: RedisResult<f64> = con.geo_dist(
1179 /// "my_gis",
1180 /// "Palermo",
1181 /// "Catania",
1182 /// Unit::Kilometers
1183 /// );
1184 /// // x is Ok(166.2742)
1185 ///
1186 /// let x: RedisResult<Option<f64>> = con.geo_dist(
1187 /// "my_gis",
1188 /// "Palermo",
1189 /// "Atlantis",
1190 /// Unit::Meters
1191 /// );
1192 /// // x is Ok(None)
1193 /// }
1194 /// ```
1195 #[cfg(feature = "geospatial")]
1196 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1197 fn geo_dist<K: ToRedisArgs, M1: ToRedisArgs, M2: ToRedisArgs>(
1198 key: K,
1199 member1: M1,
1200 member2: M2,
1201 unit: geo::Unit
1202 ) {
1203 cmd("GEODIST")
1204 .arg(key)
1205 .arg(member1)
1206 .arg(member2)
1207 .arg(unit)
1208 }
1209
1210 /// Return valid [Geohash][1] strings representing the position of one or
1211 /// more members of the geospatial index represented by the sorted set at
1212 /// key.
1213 ///
1214 /// [1]: https://en.wikipedia.org/wiki/Geohash
1215 ///
1216 /// # Example
1217 ///
1218 /// ```rust,no_run
1219 /// use redis::{Commands, RedisResult};
1220 ///
1221 /// fn get_hash(con: &mut redis::Connection) {
1222 /// let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", "Palermo");
1223 /// // x is vec!["sqc8b49rny0"]
1224 ///
1225 /// let x: RedisResult<Vec<String>> = con.geo_hash("my_gis", &["Palermo", "Catania"]);
1226 /// // x is vec!["sqc8b49rny0", "sqdtr74hyu0"]
1227 /// }
1228 /// ```
1229 #[cfg(feature = "geospatial")]
1230 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1231 fn geo_hash<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1232 cmd("GEOHASH").arg(key).arg(members)
1233 }
1234
1235 /// Return the positions of all the specified members of the geospatial
1236 /// index represented by the sorted set at key.
1237 ///
1238 /// Every position is a pair of `(longitude, latitude)`. [`redis::geo::Coord`][1]
1239 /// can be used to convert these value in a struct.
1240 ///
1241 /// [1]: ./geo/struct.Coord.html
1242 ///
1243 /// # Example
1244 ///
1245 /// ```rust,no_run
1246 /// use redis::{Commands, RedisResult};
1247 /// use redis::geo::Coord;
1248 ///
1249 /// fn get_position(con: &mut redis::Connection) {
1250 /// let x: RedisResult<Vec<Vec<f64>>> = con.geo_pos("my_gis", &["Palermo", "Catania"]);
1251 /// // x is [ [ 13.361389, 38.115556 ], [ 15.087269, 37.502669 ] ];
1252 ///
1253 /// let x: Vec<Coord<f64>> = con.geo_pos("my_gis", "Palermo").unwrap();
1254 /// // x[0].longitude is 13.361389
1255 /// // x[0].latitude is 38.115556
1256 /// }
1257 /// ```
1258 #[cfg(feature = "geospatial")]
1259 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1260 fn geo_pos<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M) {
1261 cmd("GEOPOS").arg(key).arg(members)
1262 }
1263
1264 /// Return the members of a sorted set populated with geospatial information
1265 /// using [`geo_add`](#method.geo_add), which are within the borders of the area
1266 /// specified with the center location and the maximum distance from the center
1267 /// (the radius).
1268 ///
1269 /// Every item in the result can be read with [`redis::geo::RadiusSearchResult`][1],
1270 /// which support the multiple formats returned by `GEORADIUS`.
1271 ///
1272 /// [1]: ./geo/struct.RadiusSearchResult.html
1273 ///
1274 /// ```rust,no_run
1275 /// use redis::{Commands, RedisResult};
1276 /// use redis::geo::{RadiusOptions, RadiusSearchResult, RadiusOrder, Unit};
1277 ///
1278 /// fn radius(con: &mut redis::Connection) -> Vec<RadiusSearchResult> {
1279 /// let opts = RadiusOptions::default().with_dist().order(RadiusOrder::Asc);
1280 /// con.geo_radius("my_gis", 15.90, 37.21, 51.39, Unit::Kilometers, opts).unwrap()
1281 /// }
1282 /// ```
1283 #[cfg(feature = "geospatial")]
1284 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1285 fn geo_radius<K: ToRedisArgs>(
1286 key: K,
1287 longitude: f64,
1288 latitude: f64,
1289 radius: f64,
1290 unit: geo::Unit,
1291 options: geo::RadiusOptions
1292 ) {
1293 cmd("GEORADIUS")
1294 .arg(key)
1295 .arg(longitude)
1296 .arg(latitude)
1297 .arg(radius)
1298 .arg(unit)
1299 .arg(options)
1300 }
1301
1302 /// Retrieve members selected by distance with the center of `member`. The
1303 /// member itself is always contained in the results.
1304 #[cfg(feature = "geospatial")]
1305 #[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
1306 fn geo_radius_by_member<K: ToRedisArgs, M: ToRedisArgs>(
1307 key: K,
1308 member: M,
1309 radius: f64,
1310 unit: geo::Unit,
1311 options: geo::RadiusOptions
1312 ) {
1313 cmd("GEORADIUSBYMEMBER")
1314 .arg(key)
1315 .arg(member)
1316 .arg(radius)
1317 .arg(unit)
1318 .arg(options)
1319 }
1320
1321 //
1322 // streams commands
1323 //
1324
1325 /// Ack pending stream messages checked out by a consumer.
1326 ///
1327 /// ```text
1328 /// XACK <key> <group> <id> <id> ... <id>
1329 /// ```
1330 #[cfg(feature = "streams")]
1331 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1332 fn xack<K: ToRedisArgs, G: ToRedisArgs, I: ToRedisArgs>(
1333 key: K,
1334 group: G,
1335 ids: &'a [I]) {
1336 cmd("XACK")
1337 .arg(key)
1338 .arg(group)
1339 .arg(ids)
1340 }
1341
1342
1343 /// Add a stream message by `key`. Use `*` as the `id` for the current timestamp.
1344 ///
1345 /// ```text
1346 /// XADD key <ID or *> [field value] [field value] ...
1347 /// ```
1348 #[cfg(feature = "streams")]
1349 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1350 fn xadd<K: ToRedisArgs, ID: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(
1351 key: K,
1352 id: ID,
1353 items: &'a [(F, V)]
1354 ) {
1355 cmd("XADD").arg(key).arg(id).arg(items)
1356 }
1357
1358
1359 /// BTreeMap variant for adding a stream message by `key`.
1360 /// Use `*` as the `id` for the current timestamp.
1361 ///
1362 /// ```text
1363 /// XADD key <ID or *> [rust BTreeMap] ...
1364 /// ```
1365 #[cfg(feature = "streams")]
1366 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1367 fn xadd_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1368 key: K,
1369 id: ID,
1370 map: BTM
1371 ) {
1372 cmd("XADD").arg(key).arg(id).arg(map)
1373 }
1374
1375 /// Add a stream message while capping the stream at a maxlength.
1376 ///
1377 /// ```text
1378 /// XADD key [MAXLEN [~|=] <count>] <ID or *> [field value] [field value] ...
1379 /// ```
1380 #[cfg(feature = "streams")]
1381 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1382 fn xadd_maxlen<
1383 K: ToRedisArgs,
1384 ID: ToRedisArgs,
1385 F: ToRedisArgs,
1386 V: ToRedisArgs
1387 >(
1388 key: K,
1389 maxlen: streams::StreamMaxlen,
1390 id: ID,
1391 items: &'a [(F, V)]
1392 ) {
1393 cmd("XADD")
1394 .arg(key)
1395 .arg(maxlen)
1396 .arg(id)
1397 .arg(items)
1398 }
1399
1400
1401 /// BTreeMap variant for adding a stream message while capping the stream at a maxlength.
1402 ///
1403 /// ```text
1404 /// XADD key [MAXLEN [~|=] <count>] <ID or *> [rust BTreeMap] ...
1405 /// ```
1406 #[cfg(feature = "streams")]
1407 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1408 fn xadd_maxlen_map<K: ToRedisArgs, ID: ToRedisArgs, BTM: ToRedisArgs>(
1409 key: K,
1410 maxlen: streams::StreamMaxlen,
1411 id: ID,
1412 map: BTM
1413 ) {
1414 cmd("XADD")
1415 .arg(key)
1416 .arg(maxlen)
1417 .arg(id)
1418 .arg(map)
1419 }
1420
1421
1422
1423 /// Claim pending, unacked messages, after some period of time,
1424 /// currently checked out by another consumer.
1425 ///
1426 /// This method only accepts the must-have arguments for claiming messages.
1427 /// If optional arguments are required, see `xclaim_options` below.
1428 ///
1429 /// ```text
1430 /// XCLAIM <key> <group> <consumer> <min-idle-time> [<ID-1> <ID-2>]
1431 /// ```
1432 #[cfg(feature = "streams")]
1433 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1434 fn xclaim<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs, MIT: ToRedisArgs, ID: ToRedisArgs>(
1435 key: K,
1436 group: G,
1437 consumer: C,
1438 min_idle_time: MIT,
1439 ids: &'a [ID]
1440 ) {
1441 cmd("XCLAIM")
1442 .arg(key)
1443 .arg(group)
1444 .arg(consumer)
1445 .arg(min_idle_time)
1446 .arg(ids)
1447 }
1448
1449 /// This is the optional arguments version for claiming unacked, pending messages
1450 /// currently checked out by another consumer.
1451 ///
1452 /// ```no_run
1453 /// use redis::{Connection,Commands,RedisResult};
1454 /// use redis::streams::{StreamClaimOptions,StreamClaimReply};
1455 /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1456 /// let mut con = client.get_connection().unwrap();
1457 ///
1458 /// // Claim all pending messages for key "k1",
1459 /// // from group "g1", checked out by consumer "c1"
1460 /// // for 10ms with RETRYCOUNT 2 and FORCE
1461 ///
1462 /// let opts = StreamClaimOptions::default()
1463 /// .with_force()
1464 /// .retry(2);
1465 /// let results: RedisResult<StreamClaimReply> =
1466 /// con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1467 ///
1468 /// // All optional arguments return a `Result<StreamClaimReply>` with one exception:
1469 /// // Passing JUSTID returns only the message `id` and omits the HashMap for each message.
1470 ///
1471 /// let opts = StreamClaimOptions::default()
1472 /// .with_justid();
1473 /// let results: RedisResult<Vec<String>> =
1474 /// con.xclaim_options("k1", "g1", "c1", 10, &["0"], opts);
1475 /// ```
1476 ///
1477 /// ```text
1478 /// XCLAIM <key> <group> <consumer> <min-idle-time> <ID-1> <ID-2>
1479 /// [IDLE <milliseconds>] [TIME <mstime>] [RETRYCOUNT <count>]
1480 /// [FORCE] [JUSTID]
1481 /// ```
1482 #[cfg(feature = "streams")]
1483 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1484 fn xclaim_options<
1485 K: ToRedisArgs,
1486 G: ToRedisArgs,
1487 C: ToRedisArgs,
1488 MIT: ToRedisArgs,
1489 ID: ToRedisArgs
1490 >(
1491 key: K,
1492 group: G,
1493 consumer: C,
1494 min_idle_time: MIT,
1495 ids: &'a [ID],
1496 options: streams::StreamClaimOptions
1497 ) {
1498 cmd("XCLAIM")
1499 .arg(key)
1500 .arg(group)
1501 .arg(consumer)
1502 .arg(min_idle_time)
1503 .arg(ids)
1504 .arg(options)
1505 }
1506
1507
1508 /// Deletes a list of `id`s for a given stream `key`.
1509 ///
1510 /// ```text
1511 /// XDEL <key> [<ID1> <ID2> ... <IDN>]
1512 /// ```
1513 #[cfg(feature = "streams")]
1514 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1515 fn xdel<K: ToRedisArgs, ID: ToRedisArgs>(
1516 key: K,
1517 ids: &'a [ID]
1518 ) {
1519 cmd("XDEL").arg(key).arg(ids)
1520 }
1521
1522
1523 /// This command is used for creating a consumer `group`. It expects the stream key
1524 /// to already exist. Otherwise, use `xgroup_create_mkstream` if it doesn't.
1525 /// The `id` is the starting message id all consumers should read from. Use `$` If you want
1526 /// all consumers to read from the last message added to stream.
1527 ///
1528 /// ```text
1529 /// XGROUP CREATE <key> <groupname> <id or $>
1530 /// ```
1531 #[cfg(feature = "streams")]
1532 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1533 fn xgroup_create<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1534 key: K,
1535 group: G,
1536 id: ID
1537 ) {
1538 cmd("XGROUP")
1539 .arg("CREATE")
1540 .arg(key)
1541 .arg(group)
1542 .arg(id)
1543 }
1544
1545
1546 /// This is the alternate version for creating a consumer `group`
1547 /// which makes the stream if it doesn't exist.
1548 ///
1549 /// ```text
1550 /// XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM]
1551 /// ```
1552 #[cfg(feature = "streams")]
1553 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1554 fn xgroup_create_mkstream<
1555 K: ToRedisArgs,
1556 G: ToRedisArgs,
1557 ID: ToRedisArgs
1558 >(
1559 key: K,
1560 group: G,
1561 id: ID
1562 ) {
1563 cmd("XGROUP")
1564 .arg("CREATE")
1565 .arg(key)
1566 .arg(group)
1567 .arg(id)
1568 .arg("MKSTREAM")
1569 }
1570
1571
1572 /// Alter which `id` you want consumers to begin reading from an existing
1573 /// consumer `group`.
1574 ///
1575 /// ```text
1576 /// XGROUP SETID <key> <groupname> <id or $>
1577 /// ```
1578 #[cfg(feature = "streams")]
1579 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1580 fn xgroup_setid<K: ToRedisArgs, G: ToRedisArgs, ID: ToRedisArgs>(
1581 key: K,
1582 group: G,
1583 id: ID
1584 ) {
1585 cmd("XGROUP")
1586 .arg("SETID")
1587 .arg(key)
1588 .arg(group)
1589 .arg(id)
1590 }
1591
1592
1593 /// Destroy an existing consumer `group` for a given stream `key`
1594 ///
1595 /// ```text
1596 /// XGROUP SETID <key> <groupname> <id or $>
1597 /// ```
1598 #[cfg(feature = "streams")]
1599 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1600 fn xgroup_destroy<K: ToRedisArgs, G: ToRedisArgs>(
1601 key: K,
1602 group: G
1603 ) {
1604 cmd("XGROUP").arg("DESTROY").arg(key).arg(group)
1605 }
1606
1607 /// This deletes a `consumer` from an existing consumer `group`
1608 /// for given stream `key.
1609 ///
1610 /// ```text
1611 /// XGROUP DELCONSUMER <key> <groupname> <consumername>
1612 /// ```
1613 #[cfg(feature = "streams")]
1614 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1615 fn xgroup_delconsumer<K: ToRedisArgs, G: ToRedisArgs, C: ToRedisArgs>(
1616 key: K,
1617 group: G,
1618 consumer: C
1619 ) {
1620 cmd("XGROUP")
1621 .arg("DELCONSUMER")
1622 .arg(key)
1623 .arg(group)
1624 .arg(consumer)
1625 }
1626
1627
1628 /// This returns all info details about
1629 /// which consumers have read messages for given consumer `group`.
1630 /// Take note of the StreamInfoConsumersReply return type.
1631 ///
1632 /// *It's possible this return value might not contain new fields
1633 /// added by Redis in future versions.*
1634 ///
1635 /// ```text
1636 /// XINFO CONSUMERS <key> <group>
1637 /// ```
1638 #[cfg(feature = "streams")]
1639 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1640 fn xinfo_consumers<K: ToRedisArgs, G: ToRedisArgs>(
1641 key: K,
1642 group: G
1643 ) {
1644 cmd("XINFO")
1645 .arg("CONSUMERS")
1646 .arg(key)
1647 .arg(group)
1648 }
1649
1650
1651 /// Returns all consumer `group`s created for a given stream `key`.
1652 /// Take note of the StreamInfoGroupsReply return type.
1653 ///
1654 /// *It's possible this return value might not contain new fields
1655 /// added by Redis in future versions.*
1656 ///
1657 /// ```text
1658 /// XINFO GROUPS <key>
1659 /// ```
1660 #[cfg(feature = "streams")]
1661 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1662 fn xinfo_groups<K: ToRedisArgs>(key: K) {
1663 cmd("XINFO").arg("GROUPS").arg(key)
1664 }
1665
1666
1667 /// Returns info about high-level stream details
1668 /// (first & last message `id`, length, number of groups, etc.)
1669 /// Take note of the StreamInfoStreamReply return type.
1670 ///
1671 /// *It's possible this return value might not contain new fields
1672 /// added by Redis in future versions.*
1673 ///
1674 /// ```text
1675 /// XINFO STREAM <key>
1676 /// ```
1677 #[cfg(feature = "streams")]
1678 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1679 fn xinfo_stream<K: ToRedisArgs>(key: K) {
1680 cmd("XINFO").arg("STREAM").arg(key)
1681 }
1682
1683 /// Returns the number of messages for a given stream `key`.
1684 ///
1685 /// ```text
1686 /// XLEN <key>
1687 /// ```
1688 #[cfg(feature = "streams")]
1689 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1690 fn xlen<K: ToRedisArgs>(key: K) {
1691 cmd("XLEN").arg(key)
1692 }
1693
1694
1695 /// This is a basic version of making XPENDING command calls which only
1696 /// passes a stream `key` and consumer `group` and it
1697 /// returns details about which consumers have pending messages
1698 /// that haven't been acked.
1699 ///
1700 /// You can use this method along with
1701 /// `xclaim` or `xclaim_options` for determining which messages
1702 /// need to be retried.
1703 ///
1704 /// Take note of the StreamPendingReply return type.
1705 ///
1706 /// ```text
1707 /// XPENDING <key> <group> [<start> <stop> <count> [<consumer>]]
1708 /// ```
1709 #[cfg(feature = "streams")]
1710 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1711 fn xpending<K: ToRedisArgs, G: ToRedisArgs>(
1712 key: K,
1713 group: G
1714 ) {
1715 cmd("XPENDING").arg(key).arg(group)
1716 }
1717
1718
1719 /// This XPENDING version returns a list of all messages over the range.
1720 /// You can use this for paginating pending messages (but without the message HashMap).
1721 ///
1722 /// Start and end follow the same rules `xrange` args. Set start to `-`
1723 /// and end to `+` for the entire stream.
1724 ///
1725 /// Take note of the StreamPendingCountReply return type.
1726 ///
1727 /// ```text
1728 /// XPENDING <key> <group> <start> <stop> <count>
1729 /// ```
1730 #[cfg(feature = "streams")]
1731 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1732 fn xpending_count<
1733 K: ToRedisArgs,
1734 G: ToRedisArgs,
1735 S: ToRedisArgs,
1736 E: ToRedisArgs,
1737 C: ToRedisArgs
1738 >(
1739 key: K,
1740 group: G,
1741 start: S,
1742 end: E,
1743 count: C
1744 ) {
1745 cmd("XPENDING")
1746 .arg(key)
1747 .arg(group)
1748 .arg(start)
1749 .arg(end)
1750 .arg(count)
1751 }
1752
1753
1754 /// An alternate version of `xpending_count` which filters by `consumer` name.
1755 ///
1756 /// Start and end follow the same rules `xrange` args. Set start to `-`
1757 /// and end to `+` for the entire stream.
1758 ///
1759 /// Take note of the StreamPendingCountReply return type.
1760 ///
1761 /// ```text
1762 /// XPENDING <key> <group> <start> <stop> <count> <consumer>
1763 /// ```
1764 #[cfg(feature = "streams")]
1765 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1766 fn xpending_consumer_count<
1767 K: ToRedisArgs,
1768 G: ToRedisArgs,
1769 S: ToRedisArgs,
1770 E: ToRedisArgs,
1771 C: ToRedisArgs,
1772 CN: ToRedisArgs
1773 >(
1774 key: K,
1775 group: G,
1776 start: S,
1777 end: E,
1778 count: C,
1779 consumer: CN
1780 ) {
1781 cmd("XPENDING")
1782 .arg(key)
1783 .arg(group)
1784 .arg(start)
1785 .arg(end)
1786 .arg(count)
1787 .arg(consumer)
1788 }
1789
1790 /// Returns a range of messages in a given stream `key`.
1791 ///
1792 /// Set `start` to `-` to begin at the first message.
1793 /// Set `end` to `+` to end the most recent message.
1794 /// You can pass message `id` to both `start` and `end`.
1795 ///
1796 /// Take note of the StreamRangeReply return type.
1797 ///
1798 /// ```text
1799 /// XRANGE key start end
1800 /// ```
1801 #[cfg(feature = "streams")]
1802 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1803 fn xrange<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs>(
1804 key: K,
1805 start: S,
1806 end: E
1807 ) {
1808 cmd("XRANGE").arg(key).arg(start).arg(end)
1809 }
1810
1811
1812 /// A helper method for automatically returning all messages in a stream by `key`.
1813 /// **Use with caution!**
1814 ///
1815 /// ```text
1816 /// XRANGE key - +
1817 /// ```
1818 #[cfg(feature = "streams")]
1819 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1820 fn xrange_all<K: ToRedisArgs>(key: K) {
1821 cmd("XRANGE").arg(key).arg("-").arg("+")
1822 }
1823
1824
1825 /// A method for paginating a stream by `key`.
1826 ///
1827 /// ```text
1828 /// XRANGE key start end [COUNT <n>]
1829 /// ```
1830 #[cfg(feature = "streams")]
1831 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1832 fn xrange_count<K: ToRedisArgs, S: ToRedisArgs, E: ToRedisArgs, C: ToRedisArgs>(
1833 key: K,
1834 start: S,
1835 end: E,
1836 count: C
1837 ) {
1838 cmd("XRANGE")
1839 .arg(key)
1840 .arg(start)
1841 .arg(end)
1842 .arg("COUNT")
1843 .arg(count)
1844 }
1845
1846
1847 /// Read a list of `id`s for each stream `key`.
1848 /// This is the basic form of reading streams.
1849 /// For more advanced control, like blocking, limiting, or reading by consumer `group`,
1850 /// see `xread_options`.
1851 ///
1852 /// ```text
1853 /// XREAD STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N
1854 /// ```
1855 #[cfg(feature = "streams")]
1856 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1857 fn xread<K: ToRedisArgs, ID: ToRedisArgs>(
1858 keys: &'a [K],
1859 ids: &'a [ID]
1860 ) {
1861 cmd("XREAD").arg("STREAMS").arg(keys).arg(ids)
1862 }
1863
1864 /// This method handles setting optional arguments for
1865 /// `XREAD` or `XREADGROUP` Redis commands.
1866 /// ```no_run
1867 /// use redis::{Connection,RedisResult,Commands};
1868 /// use redis::streams::{StreamReadOptions,StreamReadReply};
1869 /// let client = redis::Client::open("redis://127.0.0.1/0").unwrap();
1870 /// let mut con = client.get_connection().unwrap();
1871 ///
1872 /// // Read 10 messages from the start of the stream,
1873 /// // without registering as a consumer group.
1874 ///
1875 /// let opts = StreamReadOptions::default()
1876 /// .count(10);
1877 /// let results: RedisResult<StreamReadReply> =
1878 /// con.xread_options(&["k1"], &["0"], &opts);
1879 ///
1880 /// // Read all undelivered messages for a given
1881 /// // consumer group. Be advised: the consumer group must already
1882 /// // exist before making this call. Also note: we're passing
1883 /// // '>' as the id here, which means all undelivered messages.
1884 ///
1885 /// let opts = StreamReadOptions::default()
1886 /// .group("group-1", "consumer-1");
1887 /// let results: RedisResult<StreamReadReply> =
1888 /// con.xread_options(&["k1"], &[">"], &opts);
1889 /// ```
1890 ///
1891 /// ```text
1892 /// XREAD [BLOCK <milliseconds>] [COUNT <count>]
1893 /// STREAMS key_1 key_2 ... key_N
1894 /// ID_1 ID_2 ... ID_N
1895 ///
1896 /// XREADGROUP [BLOCK <milliseconds>] [COUNT <count>] [NOACK] [GROUP group-name consumer-name]
1897 /// STREAMS key_1 key_2 ... key_N
1898 /// ID_1 ID_2 ... ID_N
1899 /// ```
1900 #[cfg(feature = "streams")]
1901 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1902 fn xread_options<K: ToRedisArgs, ID: ToRedisArgs>(
1903 keys: &'a [K],
1904 ids: &'a [ID],
1905 options: &'a streams::StreamReadOptions
1906 ) {
1907 cmd(if options.read_only() {
1908 "XREAD"
1909 } else {
1910 "XREADGROUP"
1911 })
1912 .arg(options)
1913 .arg("STREAMS")
1914 .arg(keys)
1915 .arg(ids)
1916 }
1917
1918 /// This is the reverse version of `xrange`.
1919 /// The same rules apply for `start` and `end` here.
1920 ///
1921 /// ```text
1922 /// XREVRANGE key end start
1923 /// ```
1924 #[cfg(feature = "streams")]
1925 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1926 fn xrevrange<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs>(
1927 key: K,
1928 end: E,
1929 start: S
1930 ) {
1931 cmd("XREVRANGE").arg(key).arg(end).arg(start)
1932 }
1933
1934 /// This is the reverse version of `xrange_all`.
1935 /// The same rules apply for `start` and `end` here.
1936 ///
1937 /// ```text
1938 /// XREVRANGE key + -
1939 /// ```
1940 fn xrevrange_all<K: ToRedisArgs>(key: K) {
1941 cmd("XREVRANGE").arg(key).arg("+").arg("-")
1942 }
1943
1944 /// This is the reverse version of `xrange_count`.
1945 /// The same rules apply for `start` and `end` here.
1946 ///
1947 /// ```text
1948 /// XREVRANGE key end start [COUNT <n>]
1949 /// ```
1950 #[cfg(feature = "streams")]
1951 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1952 fn xrevrange_count<K: ToRedisArgs, E: ToRedisArgs, S: ToRedisArgs, C: ToRedisArgs>(
1953 key: K,
1954 end: E,
1955 start: S,
1956 count: C
1957 ) {
1958 cmd("XREVRANGE")
1959 .arg(key)
1960 .arg(end)
1961 .arg(start)
1962 .arg("COUNT")
1963 .arg(count)
1964 }
1965
1966
1967 /// Trim a stream `key` to a MAXLEN count.
1968 ///
1969 /// ```text
1970 /// XTRIM <key> MAXLEN [~|=] <count> (Same as XADD MAXLEN option)
1971 /// ```
1972 #[cfg(feature = "streams")]
1973 #[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
1974 fn xtrim<K: ToRedisArgs>(
1975 key: K,
1976 maxlen: streams::StreamMaxlen
1977 ) {
1978 cmd("XTRIM").arg(key).arg(maxlen)
1979 }
1980}
1981
1982/// Allows pubsub callbacks to stop receiving messages.
1983///
1984/// Arbitrary data may be returned from `Break`.
1985pub enum ControlFlow<U> {
1986 /// Continues.
1987 Continue,
1988 /// Breaks with a value.
1989 Break(U),
1990}
1991
1992/// The PubSub trait allows subscribing to one or more channels
1993/// and receiving a callback whenever a message arrives.
1994///
1995/// Each method handles subscribing to the list of keys, waiting for
1996/// messages, and unsubscribing from the same list of channels once
1997/// a ControlFlow::Break is encountered.
1998///
1999/// Once (p)subscribe returns Ok(U), the connection is again safe to use
2000/// for calling other methods.
2001///
2002/// # Examples
2003///
2004/// ```rust,no_run
2005/// # fn do_something() -> redis::RedisResult<()> {
2006/// use redis::{PubSubCommands, ControlFlow};
2007/// let client = redis::Client::open("redis://127.0.0.1/")?;
2008/// let mut con = client.get_connection()?;
2009/// let mut count = 0;
2010/// con.subscribe(&["foo"], |msg| {
2011/// // do something with message
2012/// assert_eq!(msg.get_channel(), Ok(String::from("foo")));
2013///
2014/// // increment messages seen counter
2015/// count += 1;
2016/// match count {
2017/// // stop after receiving 10 messages
2018/// 10 => ControlFlow::Break(()),
2019/// _ => ControlFlow::Continue,
2020/// }
2021/// });
2022/// # Ok(()) }
2023/// ```
2024// TODO In the future, it would be nice to implement Try such that `?` will work
2025// within the closure.
2026pub trait PubSubCommands: Sized {
2027 /// Subscribe to a list of channels using SUBSCRIBE and run the provided
2028 /// closure for each message received.
2029 ///
2030 /// For every `Msg` passed to the provided closure, either
2031 /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2032 /// method will not return until `ControlFlow::Break` is observed.
2033 fn subscribe<C, F, U>(&mut self, _: C, _: F) -> RedisResult<U>
2034 where
2035 F: FnMut(Msg) -> ControlFlow<U>,
2036 C: ToRedisArgs;
2037
2038 /// Subscribe to a list of channels using PSUBSCRIBE and run the provided
2039 /// closure for each message received.
2040 ///
2041 /// For every `Msg` passed to the provided closure, either
2042 /// `ControlFlow::Break` or `ControlFlow::Continue` must be returned. This
2043 /// method will not return until `ControlFlow::Break` is observed.
2044 fn psubscribe<P, F, U>(&mut self, _: P, _: F) -> RedisResult<U>
2045 where
2046 F: FnMut(Msg) -> ControlFlow<U>,
2047 P: ToRedisArgs;
2048}
2049
2050impl<T> Commands for T where T: ConnectionLike {}
2051
2052#[cfg(feature = "aio")]
2053impl<T> AsyncCommands for T where T: crate::aio::ConnectionLike + Send + Sized {}
2054
2055impl PubSubCommands for Connection {
2056 fn subscribe<C, F, U>(&mut self, channels: C, mut func: F) -> RedisResult<U>
2057 where
2058 F: FnMut(Msg) -> ControlFlow<U>,
2059 C: ToRedisArgs,
2060 {
2061 let mut pubsub = self.as_pubsub();
2062 pubsub.subscribe(channels)?;
2063
2064 loop {
2065 let msg = pubsub.get_message()?;
2066 match func(msg) {
2067 ControlFlow::Continue => continue,
2068 ControlFlow::Break(value) => return Ok(value),
2069 }
2070 }
2071 }
2072
2073 fn psubscribe<P, F, U>(&mut self, patterns: P, mut func: F) -> RedisResult<U>
2074 where
2075 F: FnMut(Msg) -> ControlFlow<U>,
2076 P: ToRedisArgs,
2077 {
2078 let mut pubsub = self.as_pubsub();
2079 pubsub.psubscribe(patterns)?;
2080
2081 loop {
2082 let msg = pubsub.get_message()?;
2083 match func(msg) {
2084 ControlFlow::Continue => continue,
2085 ControlFlow::Break(value) => return Ok(value),
2086 }
2087 }
2088 }
2089}
2090
2091/// Options for the [LPOS] command
2092///
2093/// https://redis.io/commands/lpos
2094///
2095/// # Example
2096///
2097/// ```rust,no_run
2098/// use redis::{Commands, RedisResult, LposOptions};
2099/// fn fetch_list_position(
2100/// con: &mut redis::Connection,
2101/// key: &str,
2102/// value: &str,
2103/// count: usize,
2104/// rank: isize,
2105/// maxlen: usize,
2106/// ) -> RedisResult<Vec<usize>> {
2107/// let opts = LposOptions::default()
2108/// .count(count)
2109/// .rank(rank)
2110/// .maxlen(maxlen);
2111/// con.lpos(key, value, opts)
2112/// }
2113/// ```
2114#[derive(Default)]
2115pub struct LposOptions {
2116 count: Option<usize>,
2117 maxlen: Option<usize>,
2118 rank: Option<isize>,
2119}
2120
2121impl LposOptions {
2122 /// Limit the results to the first N matching items.
2123 pub fn count(mut self, n: usize) -> Self {
2124 self.count = Some(n);
2125 self
2126 }
2127
2128 /// Return the value of N from the matching items.
2129 pub fn rank(mut self, n: isize) -> Self {
2130 self.rank = Some(n);
2131 self
2132 }
2133
2134 /// Limit the search to N items in the list.
2135 pub fn maxlen(mut self, n: usize) -> Self {
2136 self.maxlen = Some(n);
2137 self
2138 }
2139}
2140
2141impl ToRedisArgs for LposOptions {
2142 fn write_redis_args<W>(&self, out: &mut W)
2143 where
2144 W: ?Sized + RedisWrite,
2145 {
2146 if let Some(n) = self.count {
2147 out.write_arg(b"COUNT");
2148 out.write_arg_fmt(n);
2149 }
2150
2151 if let Some(n) = self.rank {
2152 out.write_arg(b"RANK");
2153 out.write_arg_fmt(n);
2154 }
2155
2156 if let Some(n) = self.maxlen {
2157 out.write_arg(b"MAXLEN");
2158 out.write_arg_fmt(n);
2159 }
2160 }
2161
2162 fn is_single_arg(&self) -> bool {
2163 false
2164 }
2165}
2166
2167/// Enum for the LEFT | RIGHT args used by some commands
2168pub enum Direction {
2169 Left,
2170 Right,
2171}
2172
2173impl ToRedisArgs for Direction {
2174 fn write_redis_args<W>(&self, out: &mut W)
2175 where
2176 W: ?Sized + RedisWrite,
2177 {
2178 let s: &[u8] = match self {
2179 Direction::Left => b"LEFT",
2180 Direction::Right => b"RIGHT",
2181 };
2182 out.write_arg(s);
2183 }
2184}