redis/commands/
macros.rs

1macro_rules! implement_commands {
2    (
3        $lifetime: lifetime
4        $(
5            $(#[$attr:meta])+
6            fn $name:ident<$($tyargs:ident : $ty:ident),*>(
7                $($argname:ident: $argty:ty),*) $body:block
8        )*
9    ) =>
10    (
11        /// Implements common redis commands for connection like objects.
12        ///
13        /// This allows you to send commands straight to a connection or client.
14        /// It is also implemented for redis results of clients which makes for
15        /// very convenient access in some basic cases.
16        ///
17        /// This allows you to use nicer syntax for some common operations.
18        /// For instance this code:
19        ///
20        /// ```rust,no_run
21        /// # fn do_something() -> redis::RedisResult<()> {
22        /// let client = redis::Client::open("redis://127.0.0.1/")?;
23        /// let mut con = client.get_connection()?;
24        /// redis::cmd("SET").arg("my_key").arg(42).exec(&mut con).unwrap();
25        /// assert_eq!(redis::cmd("GET").arg("my_key").query(&mut con), Ok(42));
26        /// # Ok(()) }
27        /// ```
28        ///
29        /// Will become this:
30        ///
31        /// ```rust,no_run
32        /// # fn do_something() -> redis::RedisResult<()> {
33        /// use redis::Commands;
34        /// let client = redis::Client::open("redis://127.0.0.1/")?;
35        /// let mut con = client.get_connection()?;
36        /// let _: () = con.set("my_key", 42)?;
37        /// assert_eq!(con.get("my_key"), Ok(42));
38        /// # Ok(()) }
39        /// ```
40        pub trait Commands : ConnectionLike+Sized {
41            $(
42                $(#[$attr])*
43                #[inline]
44                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
45                fn $name<$lifetime, $($tyargs: $ty, )* RV: FromRedisValue>(
46                    &mut self $(, $argname: $argty)*) -> RedisResult<RV>
47                    { Cmd::$name($($argname),*).query(self) }
48            )*
49
50            /// Incrementally iterate the keys space.
51            #[inline]
52            fn scan<RV: FromRedisValue>(&mut self) -> RedisResult<Iter<'_, RV>> {
53                let mut c = cmd("SCAN");
54                c.cursor_arg(0);
55                c.iter(self)
56            }
57
58            /// Incrementally iterate the keys space with options.
59            #[inline]
60            fn scan_options<RV: FromRedisValue>(&mut self, opts: ScanOptions) -> RedisResult<Iter<'_, RV>> {
61                let mut c = cmd("SCAN");
62                c.cursor_arg(0).arg(opts);
63                c.iter(self)
64            }
65
66            /// Incrementally iterate the keys space for keys matching a pattern.
67            #[inline]
68            fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> RedisResult<Iter<'_, RV>> {
69                let mut c = cmd("SCAN");
70                c.cursor_arg(0).arg("MATCH").arg(pattern);
71                c.iter(self)
72            }
73
74            /// Incrementally iterate hash fields and associated values.
75            #[inline]
76            fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
77                let mut c = cmd("HSCAN");
78                c.arg(key).cursor_arg(0);
79                c.iter(self)
80            }
81
82            /// Incrementally iterate hash fields and associated values for
83            /// field names matching a pattern.
84            #[inline]
85            fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
86                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
87                let mut c = cmd("HSCAN");
88                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
89                c.iter(self)
90            }
91
92            /// Incrementally iterate set elements.
93            #[inline]
94            fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
95                let mut c = cmd("SSCAN");
96                c.arg(key).cursor_arg(0);
97                c.iter(self)
98            }
99
100            /// Incrementally iterate set elements for elements matching a pattern.
101            #[inline]
102            fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
103                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
104                let mut c = cmd("SSCAN");
105                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
106                c.iter(self)
107            }
108
109            /// Incrementally iterate sorted set elements.
110            #[inline]
111            fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> RedisResult<Iter<'_, RV>> {
112                let mut c = cmd("ZSCAN");
113                c.arg(key).cursor_arg(0);
114                c.iter(self)
115            }
116
117            /// Incrementally iterate sorted set elements for elements matching a pattern.
118            #[inline]
119            fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
120                    (&mut self, key: K, pattern: P) -> RedisResult<Iter<'_, RV>> {
121                let mut c = cmd("ZSCAN");
122                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
123                c.iter(self)
124            }
125        }
126
127        impl Cmd {
128            $(
129                $(#[$attr])*
130                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
131                pub fn $name<$lifetime, $($tyargs: $ty),*>($($argname: $argty),*) -> Self {
132                    ::std::mem::replace($body, Cmd::new())
133                }
134            )*
135        }
136
137        /// Implements common redis commands over asynchronous connections.
138        ///
139        /// This allows you to send commands straight to a connection or client.
140        ///
141        /// This allows you to use nicer syntax for some common operations.
142        /// For instance this code:
143        ///
144        /// ```rust,no_run
145        /// use redis::AsyncCommands;
146        /// # async fn do_something() -> redis::RedisResult<()> {
147        /// let client = redis::Client::open("redis://127.0.0.1/")?;
148        /// let mut con = client.get_multiplexed_async_connection().await?;
149        /// redis::cmd("SET").arg("my_key").arg(42i32).exec_async(&mut con).await?;
150        /// assert_eq!(redis::cmd("GET").arg("my_key").query_async(&mut con).await, Ok(42i32));
151        /// # Ok(()) }
152        /// ```
153        ///
154        /// Will become this:
155        ///
156        /// ```rust,no_run
157        /// use redis::AsyncCommands;
158        /// # async fn do_something() -> redis::RedisResult<()> {
159        /// use redis::Commands;
160        /// let client = redis::Client::open("redis://127.0.0.1/")?;
161        /// let mut con = client.get_multiplexed_async_connection().await?;
162        /// let _: () = con.set("my_key", 42i32).await?;
163        /// assert_eq!(con.get("my_key").await, Ok(42i32));
164        /// # Ok(()) }
165        /// ```
166        #[cfg(feature = "aio")]
167        pub trait AsyncCommands : crate::aio::ConnectionLike + Send + Sized {
168            $(
169                $(#[$attr])*
170                #[inline]
171                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
172                fn $name<$lifetime, $($tyargs: $ty + Send + Sync + $lifetime,)* RV>(
173                    & $lifetime mut self
174                    $(, $argname: $argty)*
175                ) -> crate::types::RedisFuture<'a, RV>
176                where
177                    RV: FromRedisValue,
178                {
179                    Box::pin(async move { ($body).query_async(self).await })
180                }
181            )*
182
183            /// Incrementally iterate the keys space.
184            #[inline]
185            fn scan<RV: FromRedisValue>(&mut self) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
186                let mut c = cmd("SCAN");
187                c.cursor_arg(0);
188                Box::pin(async move { c.iter_async(self).await })
189            }
190
191            /// Incrementally iterate the keys space with options.
192            #[inline]
193            fn scan_options<RV: FromRedisValue>(&mut self, opts: ScanOptions) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
194                let mut c = cmd("SCAN");
195                c.cursor_arg(0).arg(opts);
196                Box::pin(async move { c.iter_async(self).await })
197            }
198
199            /// Incrementally iterate set elements for elements matching a pattern.
200            #[inline]
201            fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(&mut self, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
202                let mut c = cmd("SCAN");
203                c.cursor_arg(0).arg("MATCH").arg(pattern);
204                Box::pin(async move { c.iter_async(self).await })
205            }
206
207            /// Incrementally iterate hash fields and associated values.
208            #[inline]
209            fn hscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
210                let mut c = cmd("HSCAN");
211                c.arg(key).cursor_arg(0);
212                Box::pin(async move {c.iter_async(self).await })
213            }
214
215            /// Incrementally iterate hash fields and associated values for
216            /// field names matching a pattern.
217            #[inline]
218            fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
219                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
220                let mut c = cmd("HSCAN");
221                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
222                Box::pin(async move {c.iter_async(self).await })
223            }
224
225            /// Incrementally iterate set elements.
226            #[inline]
227            fn sscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
228                let mut c = cmd("SSCAN");
229                c.arg(key).cursor_arg(0);
230                Box::pin(async move {c.iter_async(self).await })
231            }
232
233            /// Incrementally iterate set elements for elements matching a pattern.
234            #[inline]
235            fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
236                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
237                let mut c = cmd("SSCAN");
238                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
239                Box::pin(async move {c.iter_async(self).await })
240            }
241
242            /// Incrementally iterate sorted set elements.
243            #[inline]
244            fn zscan<K: ToRedisArgs, RV: FromRedisValue>(&mut self, key: K) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
245                let mut c = cmd("ZSCAN");
246                c.arg(key).cursor_arg(0);
247                Box::pin(async move {c.iter_async(self).await })
248            }
249
250            /// Incrementally iterate sorted set elements for elements matching a pattern.
251            #[inline]
252            fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>
253                    (&mut self, key: K, pattern: P) -> crate::types::RedisFuture<crate::cmd::AsyncIter<'_, RV>> {
254                let mut c = cmd("ZSCAN");
255                c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
256                Box::pin(async move {c.iter_async(self).await })
257            }
258        }
259
260        /// Implements common redis commands for pipelines.  Unlike the regular
261        /// commands trait, this returns the pipeline rather than a result
262        /// directly.  Other than that it works the same however.
263        impl Pipeline {
264            $(
265                $(#[$attr])*
266                #[inline]
267                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
268                pub fn $name<$lifetime, $($tyargs: $ty),*>(
269                    &mut self $(, $argname: $argty)*
270                ) -> &mut Self {
271                    self.add_command(::std::mem::replace($body, Cmd::new()))
272                }
273            )*
274        }
275
276        // Implements common redis commands for cluster pipelines.  Unlike the regular
277        // commands trait, this returns the cluster pipeline rather than a result
278        // directly.  Other than that it works the same however.
279        #[cfg(feature = "cluster")]
280        impl ClusterPipeline {
281            $(
282                $(#[$attr])*
283                #[inline]
284                #[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
285                pub fn $name<$lifetime, $($tyargs: $ty),*>(
286                    &mut self $(, $argname: $argty)*
287                ) -> &mut Self {
288                    self.add_command(::std::mem::replace($body, Cmd::new()))
289                }
290            )*
291        }
292    )
293}