redis_oxide/commands/
set.rs1use crate::commands::Command;
4use crate::core::{
5 error::{RedisError, RedisResult},
6 value::RespValue,
7};
8use crate::pipeline::PipelineCommand;
9use std::collections::HashSet;
10
11#[derive(Debug, Clone)]
13pub struct SAddCommand {
14 key: String,
15 members: Vec<String>,
16}
17
18impl SAddCommand {
19 #[must_use]
21 pub fn new(key: impl Into<String>, members: Vec<String>) -> Self {
22 Self {
23 key: key.into(),
24 members,
25 }
26 }
27}
28
29impl Command for SAddCommand {
30 type Output = i64;
31
32 fn command_name(&self) -> &str {
33 "SADD"
34 }
35
36 fn args(&self) -> Vec<RespValue> {
37 let mut args = vec![RespValue::from(self.key.clone())];
38 for member in &self.members {
39 args.push(RespValue::from(member.clone()));
40 }
41 args
42 }
43
44 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
45 response.as_int()
46 }
47
48 fn keys(&self) -> Vec<&[u8]> {
49 vec![self.key.as_bytes()]
50 }
51}
52
53impl PipelineCommand for SAddCommand {
54 fn name(&self) -> &str {
55 self.command_name()
56 }
57
58 fn args(&self) -> Vec<RespValue> {
59 <Self as Command>::args(self)
60 }
61
62 fn key(&self) -> Option<String> {
63 Some(self.key.clone())
64 }
65}
66
67#[derive(Debug, Clone)]
69pub struct SRemCommand {
70 key: String,
71 members: Vec<String>,
72}
73
74impl SRemCommand {
75 #[must_use]
77 pub fn new(key: impl Into<String>, members: Vec<String>) -> Self {
78 Self {
79 key: key.into(),
80 members,
81 }
82 }
83}
84
85impl Command for SRemCommand {
86 type Output = i64;
87
88 fn command_name(&self) -> &str {
89 "SREM"
90 }
91
92 fn args(&self) -> Vec<RespValue> {
93 let mut args = vec![RespValue::from(self.key.clone())];
94 for member in &self.members {
95 args.push(RespValue::from(member.clone()));
96 }
97 args
98 }
99
100 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
101 response.as_int()
102 }
103
104 fn keys(&self) -> Vec<&[u8]> {
105 vec![self.key.as_bytes()]
106 }
107}
108
109impl PipelineCommand for SRemCommand {
110 fn name(&self) -> &str {
111 self.command_name()
112 }
113
114 fn args(&self) -> Vec<RespValue> {
115 <Self as Command>::args(self)
116 }
117
118 fn key(&self) -> Option<String> {
119 Some(self.key.clone())
120 }
121}
122
123#[derive(Debug, Clone)]
125pub struct SMembersCommand {
126 key: String,
127}
128
129impl SMembersCommand {
130 #[must_use]
132 pub fn new(key: impl Into<String>) -> Self {
133 Self { key: key.into() }
134 }
135}
136
137impl Command for SMembersCommand {
138 type Output = HashSet<String>;
139
140 fn command_name(&self) -> &str {
141 "SMEMBERS"
142 }
143
144 fn args(&self) -> Vec<RespValue> {
145 vec![RespValue::from(self.key.clone())]
146 }
147
148 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
149 match response {
150 RespValue::Array(items) => {
151 let mut result = HashSet::new();
152 for item in items {
153 match item {
154 RespValue::BulkString(b) => {
155 let s = String::from_utf8(b.to_vec())
156 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}")))?;
157 result.insert(s);
158 }
159 RespValue::Null => {
160 }
162 _ => {
163 return Err(RedisError::Type(format!(
164 "Unexpected item type in SMEMBERS response: {:?}",
165 item
166 )))
167 }
168 }
169 }
170 Ok(result)
171 }
172 _ => Err(RedisError::Type(format!(
173 "Unexpected response type for SMEMBERS: {:?}",
174 response
175 ))),
176 }
177 }
178
179 fn keys(&self) -> Vec<&[u8]> {
180 vec![self.key.as_bytes()]
181 }
182}
183
184impl PipelineCommand for SMembersCommand {
185 fn name(&self) -> &str {
186 self.command_name()
187 }
188
189 fn args(&self) -> Vec<RespValue> {
190 <Self as Command>::args(self)
191 }
192
193 fn key(&self) -> Option<String> {
194 Some(self.key.clone())
195 }
196}
197
198#[derive(Debug, Clone)]
200pub struct SIsMemberCommand {
201 key: String,
202 member: String,
203}
204
205impl SIsMemberCommand {
206 #[must_use]
208 pub fn new(key: impl Into<String>, member: impl Into<String>) -> Self {
209 Self {
210 key: key.into(),
211 member: member.into(),
212 }
213 }
214}
215
216impl Command for SIsMemberCommand {
217 type Output = bool;
218
219 fn command_name(&self) -> &str {
220 "SISMEMBER"
221 }
222
223 fn args(&self) -> Vec<RespValue> {
224 vec![
225 RespValue::from(self.key.clone()),
226 RespValue::from(self.member.clone()),
227 ]
228 }
229
230 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
231 match response {
232 RespValue::Integer(1) => Ok(true),
233 RespValue::Integer(0) => Ok(false),
234 _ => Err(RedisError::Type(format!(
235 "Unexpected response type for SISMEMBER: {:?}",
236 response
237 ))),
238 }
239 }
240
241 fn keys(&self) -> Vec<&[u8]> {
242 vec![self.key.as_bytes()]
243 }
244}
245
246impl PipelineCommand for SIsMemberCommand {
247 fn name(&self) -> &str {
248 self.command_name()
249 }
250
251 fn args(&self) -> Vec<RespValue> {
252 <Self as Command>::args(self)
253 }
254
255 fn key(&self) -> Option<String> {
256 Some(self.key.clone())
257 }
258}
259
260#[derive(Debug, Clone)]
262pub struct SCardCommand {
263 key: String,
264}
265
266impl SCardCommand {
267 #[must_use]
269 pub fn new(key: impl Into<String>) -> Self {
270 Self { key: key.into() }
271 }
272}
273
274impl Command for SCardCommand {
275 type Output = i64;
276
277 fn command_name(&self) -> &str {
278 "SCARD"
279 }
280
281 fn args(&self) -> Vec<RespValue> {
282 vec![RespValue::from(self.key.clone())]
283 }
284
285 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
286 response.as_int()
287 }
288
289 fn keys(&self) -> Vec<&[u8]> {
290 vec![self.key.as_bytes()]
291 }
292}
293
294impl PipelineCommand for SCardCommand {
295 fn name(&self) -> &str {
296 self.command_name()
297 }
298
299 fn args(&self) -> Vec<RespValue> {
300 <Self as Command>::args(self)
301 }
302
303 fn key(&self) -> Option<String> {
304 Some(self.key.clone())
305 }
306}
307
308#[derive(Debug, Clone)]
310pub struct SPopCommand {
311 key: String,
312}
313
314impl SPopCommand {
315 #[must_use]
317 pub fn new(key: impl Into<String>) -> Self {
318 Self { key: key.into() }
319 }
320}
321
322impl Command for SPopCommand {
323 type Output = Option<String>;
324
325 fn command_name(&self) -> &str {
326 "SPOP"
327 }
328
329 fn args(&self) -> Vec<RespValue> {
330 vec![RespValue::from(self.key.clone())]
331 }
332
333 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
334 match response {
335 RespValue::BulkString(b) => String::from_utf8(b.to_vec())
336 .map(Some)
337 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}"))),
338 RespValue::Null => Ok(None),
339 _ => Err(RedisError::Type(format!(
340 "Unexpected response type for SPOP: {:?}",
341 response
342 ))),
343 }
344 }
345
346 fn keys(&self) -> Vec<&[u8]> {
347 vec![self.key.as_bytes()]
348 }
349}
350
351impl PipelineCommand for SPopCommand {
352 fn name(&self) -> &str {
353 self.command_name()
354 }
355
356 fn args(&self) -> Vec<RespValue> {
357 <Self as Command>::args(self)
358 }
359
360 fn key(&self) -> Option<String> {
361 Some(self.key.clone())
362 }
363}
364
365#[derive(Debug, Clone)]
367pub struct SRandMemberCommand {
368 key: String,
369}
370
371impl SRandMemberCommand {
372 #[must_use]
374 pub fn new(key: impl Into<String>) -> Self {
375 Self { key: key.into() }
376 }
377}
378
379impl Command for SRandMemberCommand {
380 type Output = Option<String>;
381
382 fn command_name(&self) -> &str {
383 "SRANDMEMBER"
384 }
385
386 fn args(&self) -> Vec<RespValue> {
387 vec![RespValue::from(self.key.clone())]
388 }
389
390 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
391 match response {
392 RespValue::BulkString(b) => String::from_utf8(b.to_vec())
393 .map(Some)
394 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}"))),
395 RespValue::Null => Ok(None),
396 _ => Err(RedisError::Type(format!(
397 "Unexpected response type for SRANDMEMBER: {:?}",
398 response
399 ))),
400 }
401 }
402
403 fn keys(&self) -> Vec<&[u8]> {
404 vec![self.key.as_bytes()]
405 }
406}
407
408impl PipelineCommand for SRandMemberCommand {
409 fn name(&self) -> &str {
410 self.command_name()
411 }
412
413 fn args(&self) -> Vec<RespValue> {
414 <Self as Command>::args(self)
415 }
416
417 fn key(&self) -> Option<String> {
418 Some(self.key.clone())
419 }
420}