glide/cmd.rs
1// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2//! GLIDE's owned command builder.
3//!
4//! [`Cmd`] represents a command keyword and arguments.
5
6use crate::ValkeyFuture;
7use crate::commands::core::AsyncCommands;
8use crate::value::FromValkeyValue;
9use crate::write::ToValkeyArgs;
10
11#[cfg(feature = "sync")]
12use crate::{ValkeyResult, commands::core::Commands};
13
14/// Create a new command with the given keyword.
15///
16/// This is the recommended way to start a command.
17/// Mirrors redis-rs's `cmd`.
18///
19/// ```
20/// glide::cmd("PING");
21/// ```
22pub fn cmd(name: &str) -> Cmd {
23 let mut command = Cmd::new();
24 command.arg(name);
25 command
26}
27
28/// A command to send to the server.
29///
30/// Build a command, then send it with one of:
31///
32/// - `crate::AsyncCommands::glide_send_command_as`
33/// - `crate::AsyncCommands::glide_send_command`
34/// - `crate::Commands::glide_send_command_as`
35/// - `crate::Commands::glide_send_command`
36///
37/// ```rust,no_run
38/// use glide::AsyncCommands;
39/// # async fn demo(client: glide::GlideClient) -> glide::ValkeyResult<()> {
40/// let set = glide::cmd("SET").arg("my_key").arg(42).clone();
41/// let _: () = client.glide_send_command_as(set).await?;
42///
43/// let get = glide::cmd("GET").arg("my_key").clone();
44/// let value: i64 = client.glide_send_command_as(get).await?;
45///
46/// # assert_eq!(value, 42);
47/// # Ok(()) }
48/// ```
49///
50/// Mirrors redis-rs's `Cmd`.
51#[derive(Clone, Default)]
52pub struct Cmd {
53 inner: redis::Cmd,
54}
55
56impl Cmd {
57 /// Create an empty command.
58 ///
59 /// It is recommended to use [`cmd`] instead
60 /// to explicitly specify the command keyword.
61 pub fn new() -> Self {
62 Cmd {
63 inner: redis::Cmd::new(),
64 }
65 }
66
67 /// Append an argument and return `&mut self` for chaining.
68 #[inline]
69 pub fn arg<A: ToValkeyArgs>(&mut self, arg: A) -> &mut Self {
70 arg.write_valkey_args(self);
71 self
72 }
73
74 /// Execute this command on an async GLIDE client.
75 ///
76 /// ```rust,no_run
77 /// use glide::cmd;
78 /// # async fn demo(client: &glide::GlideClient) -> glide::ValkeyResult<()> {
79 /// let v: i64 = cmd("GET").arg("k").query_async(client).await?;
80 /// # let _ = v; Ok(()) }
81 /// ```
82 ///
83 /// Mirrors `redis-rs`'s `query_async`.
84 #[inline]
85 pub fn query_async<'a, RV: FromValkeyValue>(
86 &self,
87 con: &'a impl AsyncCommands,
88 ) -> ValkeyFuture<'a, RV> {
89 con.glide_send_command_as(self.clone())
90 }
91
92 /// Execute this command on an async GLIDE client, discarding the reply.
93 ///
94 /// Mirrors `redis-rs`'s `exec_async`.
95 #[inline]
96 pub fn exec_async<'a>(&self, con: &'a impl AsyncCommands) -> ValkeyFuture<'a, ()> {
97 self.query_async(con)
98 }
99
100 /// Execute this command on a blocking GLIDE client.
101 ///
102 /// ```rust,no_run
103 /// use glide::cmd;
104 /// use glide::sync::SyncGlideClient;
105 /// # fn demo(client: &SyncGlideClient) -> glide::ValkeyResult<()> {
106 /// let v: i64 = cmd("GET").arg("k").query(client)?;
107 /// # let _ = v; Ok(()) }
108 /// ```
109 ///
110 /// Mirrors `redis-rs`'s `query`.
111 #[cfg(feature = "sync")]
112 #[inline]
113 pub fn query<RV: FromValkeyValue>(&self, con: &impl Commands) -> ValkeyResult<RV> {
114 con.glide_send_command_as(self.clone())
115 }
116
117 /// Execute this command on a blocking GLIDE client, discarding the reply.
118 ///
119 /// Mirrors `redis-rs`'s `exec`.
120 #[cfg(feature = "sync")]
121 #[inline]
122 pub fn exec(&self, con: &impl Commands) -> ValkeyResult<()> {
123 self.query(con)
124 }
125
126 /// Borrow the underlying `redis::Cmd`.
127 pub(crate) fn as_redis(&self) -> &redis::Cmd {
128 &self.inner
129 }
130
131 /// Mutably borrow the underlying `redis::Cmd`.
132 pub(crate) fn as_redis_mut(&mut self) -> &mut redis::Cmd {
133 &mut self.inner
134 }
135
136 /// Consume into the underlying `redis::Cmd`.
137 pub(crate) fn into_redis(self) -> redis::Cmd {
138 self.inner
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn matches_redis_cmd_single_arg() {
148 let mut v = Cmd::new();
149 v.arg("SET").arg("key").arg(42i64);
150
151 let mut r = redis::Cmd::new();
152 r.arg("SET").arg("key").arg(42i64);
153
154 assert_eq!(v.as_redis().get_packed_command(), r.get_packed_command());
155 }
156
157 #[test]
158 fn matches_redis_cmd_multi_arg() {
159 let mut v = Cmd::new();
160 v.arg("MGET").arg(&["a", "b", "c"][..]);
161
162 let mut r = redis::Cmd::new();
163 r.arg("MGET").arg(&["a", "b", "c"][..]);
164
165 assert_eq!(v.as_redis().get_packed_command(), r.get_packed_command());
166 }
167}