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