1#![allow(clippy::items_after_test_module)]
2pub mod hash;
7pub mod list;
8pub mod optimized;
9pub mod set;
10pub mod sorted_set;
11
12use crate::core::{error::RedisResult, value::RespValue};
13use crate::pipeline::PipelineCommand;
14use std::time::Duration;
15
16pub use hash::{
18 HDelCommand, HExistsCommand, HGetAllCommand, HGetCommand, HLenCommand, HMGetCommand,
19 HMSetCommand, HSetCommand,
20};
21
22pub use list::{
24 LIndexCommand, LLenCommand, LPopCommand, LPushCommand, LRangeCommand, LSetCommand, RPopCommand,
25 RPushCommand,
26};
27
28pub use set::{
30 SAddCommand, SCardCommand, SIsMemberCommand, SMembersCommand, SPopCommand, SRandMemberCommand,
31 SRemCommand,
32};
33
34pub use sorted_set::{
36 ZAddCommand, ZCardCommand, ZRangeCommand, ZRankCommand, ZRemCommand, ZRevRankCommand,
37 ZScoreCommand,
38};
39
40pub trait Command {
42 type Output;
44
45 fn command_name(&self) -> &str;
47
48 fn args(&self) -> Vec<RespValue>;
50
51 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output>;
53
54 fn keys(&self) -> Vec<&[u8]>;
56}
57
58pub struct GetCommand {
60 key: String,
61}
62
63impl GetCommand {
64 pub fn new(key: impl Into<String>) -> Self {
66 Self { key: key.into() }
67 }
68}
69
70impl Command for GetCommand {
71 type Output = Option<String>;
72
73 fn command_name(&self) -> &str {
74 "GET"
75 }
76
77 fn args(&self) -> Vec<RespValue> {
78 vec![RespValue::from(self.key.as_str())]
79 }
80
81 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
82 if response.is_null() {
83 Ok(None)
84 } else {
85 Ok(Some(response.as_string()?))
86 }
87 }
88
89 fn keys(&self) -> Vec<&[u8]> {
90 vec![self.key.as_bytes()]
91 }
92}
93
94pub struct SetCommand {
96 key: String,
97 value: String,
98 expiration: Option<Duration>,
99 nx: bool,
100 xx: bool,
101}
102
103impl SetCommand {
104 pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
106 Self {
107 key: key.into(),
108 value: value.into(),
109 expiration: None,
110 nx: false,
111 xx: false,
112 }
113 }
114
115 pub fn expire(mut self, duration: Duration) -> Self {
117 self.expiration = Some(duration);
118 self
119 }
120
121 pub fn only_if_not_exists(mut self) -> Self {
123 self.nx = true;
124 self
125 }
126
127 pub fn only_if_exists(mut self) -> Self {
129 self.xx = true;
130 self
131 }
132}
133
134impl Command for SetCommand {
135 type Output = bool;
136
137 fn command_name(&self) -> &str {
138 "SET"
139 }
140
141 fn args(&self) -> Vec<RespValue> {
142 let mut args = vec![
143 RespValue::from(self.key.as_str()),
144 RespValue::from(self.value.as_str()),
145 ];
146
147 if let Some(duration) = self.expiration {
148 args.push(RespValue::from("EX"));
149 args.push(RespValue::from(duration.as_secs().to_string()));
150 }
151
152 if self.nx {
153 args.push(RespValue::from("NX"));
154 }
155
156 if self.xx {
157 args.push(RespValue::from("XX"));
158 }
159
160 args
161 }
162
163 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
164 match response {
165 RespValue::SimpleString(ref s) if s == "OK" => Ok(true),
166 _ => Ok(false),
168 }
169 }
170
171 fn keys(&self) -> Vec<&[u8]> {
172 vec![self.key.as_bytes()]
173 }
174}
175
176pub struct DelCommand {
178 keys: Vec<String>,
179}
180
181impl DelCommand {
182 pub fn new(keys: Vec<String>) -> Self {
184 Self { keys }
185 }
186}
187
188impl Command for DelCommand {
189 type Output = i64;
190
191 fn command_name(&self) -> &str {
192 "DEL"
193 }
194
195 fn args(&self) -> Vec<RespValue> {
196 self.keys
197 .iter()
198 .map(|k| RespValue::from(k.as_str()))
199 .collect()
200 }
201
202 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
203 response.as_int()
204 }
205
206 fn keys(&self) -> Vec<&[u8]> {
207 self.keys.iter().map(String::as_bytes).collect()
208 }
209}
210
211pub struct ExistsCommand {
213 keys: Vec<String>,
214}
215
216impl ExistsCommand {
217 pub fn new(keys: Vec<String>) -> Self {
219 Self { keys }
220 }
221}
222
223impl Command for ExistsCommand {
224 type Output = i64;
225
226 fn command_name(&self) -> &str {
227 "EXISTS"
228 }
229
230 fn args(&self) -> Vec<RespValue> {
231 self.keys
232 .iter()
233 .map(|k| RespValue::from(k.as_str()))
234 .collect()
235 }
236
237 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
238 response.as_int()
239 }
240
241 fn keys(&self) -> Vec<&[u8]> {
242 self.keys.iter().map(String::as_bytes).collect()
243 }
244}
245
246pub struct ExpireCommand {
248 key: String,
249 seconds: i64,
250}
251
252impl ExpireCommand {
253 pub fn new(key: impl Into<String>, duration: Duration) -> Self {
255 #[allow(clippy::cast_possible_wrap)]
256 Self {
257 key: key.into(),
258 seconds: duration.as_secs() as i64,
259 }
260 }
261}
262
263impl Command for ExpireCommand {
264 type Output = bool;
265
266 fn command_name(&self) -> &str {
267 "EXPIRE"
268 }
269
270 fn args(&self) -> Vec<RespValue> {
271 vec![
272 RespValue::from(self.key.as_str()),
273 RespValue::from(self.seconds.to_string()),
274 ]
275 }
276
277 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
278 Ok(response.as_int()? == 1)
279 }
280
281 fn keys(&self) -> Vec<&[u8]> {
282 vec![self.key.as_bytes()]
283 }
284}
285
286pub struct TtlCommand {
288 key: String,
289}
290
291impl TtlCommand {
292 pub fn new(key: impl Into<String>) -> Self {
294 Self { key: key.into() }
295 }
296}
297
298impl Command for TtlCommand {
299 type Output = Option<i64>;
300
301 fn command_name(&self) -> &str {
302 "TTL"
303 }
304
305 fn args(&self) -> Vec<RespValue> {
306 vec![RespValue::from(self.key.as_str())]
307 }
308
309 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
310 let ttl = response.as_int()?;
311 if ttl < 0 {
312 Ok(None) } else {
314 Ok(Some(ttl))
315 }
316 }
317
318 fn keys(&self) -> Vec<&[u8]> {
319 vec![self.key.as_bytes()]
320 }
321}
322
323pub struct IncrCommand {
325 key: String,
326}
327
328impl IncrCommand {
329 pub fn new(key: impl Into<String>) -> Self {
331 Self { key: key.into() }
332 }
333}
334
335impl Command for IncrCommand {
336 type Output = i64;
337
338 fn command_name(&self) -> &str {
339 "INCR"
340 }
341
342 fn args(&self) -> Vec<RespValue> {
343 vec![RespValue::from(self.key.as_str())]
344 }
345
346 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
347 response.as_int()
348 }
349
350 fn keys(&self) -> Vec<&[u8]> {
351 vec![self.key.as_bytes()]
352 }
353}
354
355pub struct DecrCommand {
357 key: String,
358}
359
360impl DecrCommand {
361 pub fn new(key: impl Into<String>) -> Self {
363 Self { key: key.into() }
364 }
365}
366
367impl Command for DecrCommand {
368 type Output = i64;
369
370 fn command_name(&self) -> &str {
371 "DECR"
372 }
373
374 fn args(&self) -> Vec<RespValue> {
375 vec![RespValue::from(self.key.as_str())]
376 }
377
378 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
379 response.as_int()
380 }
381
382 fn keys(&self) -> Vec<&[u8]> {
383 vec![self.key.as_bytes()]
384 }
385}
386
387pub struct IncrByCommand {
389 key: String,
390 increment: i64,
391}
392
393impl IncrByCommand {
394 pub fn new(key: impl Into<String>, increment: i64) -> Self {
396 Self {
397 key: key.into(),
398 increment,
399 }
400 }
401}
402
403impl Command for IncrByCommand {
404 type Output = i64;
405
406 fn command_name(&self) -> &str {
407 "INCRBY"
408 }
409
410 fn args(&self) -> Vec<RespValue> {
411 vec![
412 RespValue::from(self.key.as_str()),
413 RespValue::from(self.increment.to_string()),
414 ]
415 }
416
417 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
418 response.as_int()
419 }
420
421 fn keys(&self) -> Vec<&[u8]> {
422 vec![self.key.as_bytes()]
423 }
424}
425
426pub struct DecrByCommand {
428 key: String,
429 decrement: i64,
430}
431
432impl DecrByCommand {
433 pub fn new(key: impl Into<String>, decrement: i64) -> Self {
435 Self {
436 key: key.into(),
437 decrement,
438 }
439 }
440}
441
442impl Command for DecrByCommand {
443 type Output = i64;
444
445 fn command_name(&self) -> &str {
446 "DECRBY"
447 }
448
449 fn args(&self) -> Vec<RespValue> {
450 vec![
451 RespValue::from(self.key.as_str()),
452 RespValue::from(self.decrement.to_string()),
453 ]
454 }
455
456 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
457 response.as_int()
458 }
459
460 fn keys(&self) -> Vec<&[u8]> {
461 vec![self.key.as_bytes()]
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use super::*;
468
469 #[test]
470 fn test_get_command() {
471 let cmd = GetCommand::new("mykey");
472 assert_eq!(cmd.command_name(), "GET");
473 assert_eq!(cmd.keys(), vec![b"mykey"]);
474 }
475
476 #[test]
477 fn test_set_command_basic() {
478 let cmd = SetCommand::new("key", "value");
479 assert_eq!(cmd.command_name(), "SET");
480 let args = <SetCommand as Command>::args(&cmd);
481 assert_eq!(args.len(), 2);
482 }
483
484 #[test]
485 fn test_set_command_with_expiration() {
486 let cmd = SetCommand::new("key", "value").expire(Duration::from_secs(60));
487 let args = <SetCommand as Command>::args(&cmd);
488 assert_eq!(args.len(), 4); }
490
491 #[test]
492 fn test_set_command_nx() {
493 let cmd = SetCommand::new("key", "value").only_if_not_exists();
494 let args = <SetCommand as Command>::args(&cmd);
495 assert!(args.len() >= 3); }
497
498 #[test]
499 fn test_del_command() {
500 let cmd = DelCommand::new(vec!["key1".to_string(), "key2".to_string()]);
501 assert_eq!(cmd.command_name(), "DEL");
502 assert_eq!(cmd.keys().len(), 2);
503 }
504
505 #[test]
506 fn test_incr_command() {
507 let cmd = IncrCommand::new("counter");
508 assert_eq!(cmd.command_name(), "INCR");
509 assert_eq!(cmd.keys(), vec![b"counter"]);
510 }
511}
512
513impl PipelineCommand for GetCommand {
515 fn name(&self) -> &str {
516 self.command_name()
517 }
518
519 fn args(&self) -> Vec<RespValue> {
520 <Self as Command>::args(self)
521 }
522
523 fn key(&self) -> Option<String> {
524 Some(self.key.clone())
525 }
526}
527
528impl PipelineCommand for SetCommand {
529 fn name(&self) -> &str {
530 self.command_name()
531 }
532
533 fn args(&self) -> Vec<RespValue> {
534 <Self as Command>::args(self)
535 }
536
537 fn key(&self) -> Option<String> {
538 Some(self.key.clone())
539 }
540}
541
542impl PipelineCommand for DelCommand {
543 fn name(&self) -> &str {
544 self.command_name()
545 }
546
547 fn args(&self) -> Vec<RespValue> {
548 <Self as Command>::args(self)
549 }
550
551 fn key(&self) -> Option<String> {
552 self.keys.first().cloned()
553 }
554}
555
556impl PipelineCommand for IncrCommand {
557 fn name(&self) -> &str {
558 self.command_name()
559 }
560
561 fn args(&self) -> Vec<RespValue> {
562 <Self as Command>::args(self)
563 }
564
565 fn key(&self) -> Option<String> {
566 Some(self.key.clone())
567 }
568}
569
570impl PipelineCommand for DecrCommand {
571 fn name(&self) -> &str {
572 self.command_name()
573 }
574
575 fn args(&self) -> Vec<RespValue> {
576 <Self as Command>::args(self)
577 }
578
579 fn key(&self) -> Option<String> {
580 Some(self.key.clone())
581 }
582}
583
584impl PipelineCommand for IncrByCommand {
585 fn name(&self) -> &str {
586 self.command_name()
587 }
588
589 fn args(&self) -> Vec<RespValue> {
590 <Self as Command>::args(self)
591 }
592
593 fn key(&self) -> Option<String> {
594 Some(self.key.clone())
595 }
596}
597
598impl PipelineCommand for DecrByCommand {
599 fn name(&self) -> &str {
600 self.command_name()
601 }
602
603 fn args(&self) -> Vec<RespValue> {
604 <Self as Command>::args(self)
605 }
606
607 fn key(&self) -> Option<String> {
608 Some(self.key.clone())
609 }
610}
611
612impl PipelineCommand for ExistsCommand {
613 fn name(&self) -> &str {
614 self.command_name()
615 }
616
617 fn args(&self) -> Vec<RespValue> {
618 <Self as Command>::args(self)
619 }
620
621 fn key(&self) -> Option<String> {
622 self.keys.first().cloned()
623 }
624}
625
626impl PipelineCommand for ExpireCommand {
627 fn name(&self) -> &str {
628 self.command_name()
629 }
630
631 fn args(&self) -> Vec<RespValue> {
632 <Self as Command>::args(self)
633 }
634
635 fn key(&self) -> Option<String> {
636 Some(self.key.clone())
637 }
638}
639
640impl PipelineCommand for TtlCommand {
641 fn name(&self) -> &str {
642 self.command_name()
643 }
644
645 fn args(&self) -> Vec<RespValue> {
646 <Self as Command>::args(self)
647 }
648
649 fn key(&self) -> Option<String> {
650 Some(self.key.clone())
651 }
652}