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 response.as_int().map(Some)
311 }
312
313 fn keys(&self) -> Vec<&[u8]> {
314 vec![self.key.as_bytes()]
315 }
316}
317
318pub struct IncrCommand {
320 key: String,
321}
322
323impl IncrCommand {
324 pub fn new(key: impl Into<String>) -> Self {
326 Self { key: key.into() }
327 }
328}
329
330impl Command for IncrCommand {
331 type Output = i64;
332
333 fn command_name(&self) -> &str {
334 "INCR"
335 }
336
337 fn args(&self) -> Vec<RespValue> {
338 vec![RespValue::from(self.key.as_str())]
339 }
340
341 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
342 response.as_int()
343 }
344
345 fn keys(&self) -> Vec<&[u8]> {
346 vec![self.key.as_bytes()]
347 }
348}
349
350pub struct DecrCommand {
352 key: String,
353}
354
355impl DecrCommand {
356 pub fn new(key: impl Into<String>) -> Self {
358 Self { key: key.into() }
359 }
360}
361
362impl Command for DecrCommand {
363 type Output = i64;
364
365 fn command_name(&self) -> &str {
366 "DECR"
367 }
368
369 fn args(&self) -> Vec<RespValue> {
370 vec![RespValue::from(self.key.as_str())]
371 }
372
373 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
374 response.as_int()
375 }
376
377 fn keys(&self) -> Vec<&[u8]> {
378 vec![self.key.as_bytes()]
379 }
380}
381
382pub struct IncrByCommand {
384 key: String,
385 increment: i64,
386}
387
388impl IncrByCommand {
389 pub fn new(key: impl Into<String>, increment: i64) -> Self {
391 Self {
392 key: key.into(),
393 increment,
394 }
395 }
396}
397
398impl Command for IncrByCommand {
399 type Output = i64;
400
401 fn command_name(&self) -> &str {
402 "INCRBY"
403 }
404
405 fn args(&self) -> Vec<RespValue> {
406 vec![
407 RespValue::from(self.key.as_str()),
408 RespValue::from(self.increment.to_string()),
409 ]
410 }
411
412 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
413 response.as_int()
414 }
415
416 fn keys(&self) -> Vec<&[u8]> {
417 vec![self.key.as_bytes()]
418 }
419}
420
421pub struct DecrByCommand {
423 key: String,
424 decrement: i64,
425}
426
427impl DecrByCommand {
428 pub fn new(key: impl Into<String>, decrement: i64) -> Self {
430 Self {
431 key: key.into(),
432 decrement,
433 }
434 }
435}
436
437impl Command for DecrByCommand {
438 type Output = i64;
439
440 fn command_name(&self) -> &str {
441 "DECRBY"
442 }
443
444 fn args(&self) -> Vec<RespValue> {
445 vec![
446 RespValue::from(self.key.as_str()),
447 RespValue::from(self.decrement.to_string()),
448 ]
449 }
450
451 fn parse_response(&self, response: RespValue) -> RedisResult<Self::Output> {
452 response.as_int()
453 }
454
455 fn keys(&self) -> Vec<&[u8]> {
456 vec![self.key.as_bytes()]
457 }
458}
459
460#[cfg(test)]
461mod tests {
462 use super::*;
463
464 #[test]
465 fn test_get_command() {
466 let cmd = GetCommand::new("mykey");
467 assert_eq!(cmd.command_name(), "GET");
468 assert_eq!(cmd.keys(), vec![b"mykey"]);
469 }
470
471 #[test]
472 fn test_set_command_basic() {
473 let cmd = SetCommand::new("key", "value");
474 assert_eq!(cmd.command_name(), "SET");
475 let args = <SetCommand as Command>::args(&cmd);
476 assert_eq!(args.len(), 2);
477 }
478
479 #[test]
480 fn test_set_command_with_expiration() {
481 let cmd = SetCommand::new("key", "value").expire(Duration::from_secs(60));
482 let args = <SetCommand as Command>::args(&cmd);
483 assert_eq!(args.len(), 4); }
485
486 #[test]
487 fn test_set_command_nx() {
488 let cmd = SetCommand::new("key", "value").only_if_not_exists();
489 let args = <SetCommand as Command>::args(&cmd);
490 assert!(args.len() >= 3); }
492
493 #[test]
494 fn test_del_command() {
495 let cmd = DelCommand::new(vec!["key1".to_string(), "key2".to_string()]);
496 assert_eq!(cmd.command_name(), "DEL");
497 assert_eq!(cmd.keys().len(), 2);
498 }
499
500 #[test]
501 fn test_incr_command() {
502 let cmd = IncrCommand::new("counter");
503 assert_eq!(cmd.command_name(), "INCR");
504 assert_eq!(cmd.keys(), vec![b"counter"]);
505 }
506}
507
508impl PipelineCommand for GetCommand {
510 fn name(&self) -> &str {
511 self.command_name()
512 }
513
514 fn args(&self) -> Vec<RespValue> {
515 <Self as Command>::args(self)
516 }
517
518 fn key(&self) -> Option<String> {
519 Some(self.key.clone())
520 }
521}
522
523impl PipelineCommand for SetCommand {
524 fn name(&self) -> &str {
525 self.command_name()
526 }
527
528 fn args(&self) -> Vec<RespValue> {
529 <Self as Command>::args(self)
530 }
531
532 fn key(&self) -> Option<String> {
533 Some(self.key.clone())
534 }
535}
536
537impl PipelineCommand for DelCommand {
538 fn name(&self) -> &str {
539 self.command_name()
540 }
541
542 fn args(&self) -> Vec<RespValue> {
543 <Self as Command>::args(self)
544 }
545
546 fn key(&self) -> Option<String> {
547 self.keys.first().cloned()
548 }
549}
550
551impl PipelineCommand for IncrCommand {
552 fn name(&self) -> &str {
553 self.command_name()
554 }
555
556 fn args(&self) -> Vec<RespValue> {
557 <Self as Command>::args(self)
558 }
559
560 fn key(&self) -> Option<String> {
561 Some(self.key.clone())
562 }
563}
564
565impl PipelineCommand for DecrCommand {
566 fn name(&self) -> &str {
567 self.command_name()
568 }
569
570 fn args(&self) -> Vec<RespValue> {
571 <Self as Command>::args(self)
572 }
573
574 fn key(&self) -> Option<String> {
575 Some(self.key.clone())
576 }
577}
578
579impl PipelineCommand for IncrByCommand {
580 fn name(&self) -> &str {
581 self.command_name()
582 }
583
584 fn args(&self) -> Vec<RespValue> {
585 <Self as Command>::args(self)
586 }
587
588 fn key(&self) -> Option<String> {
589 Some(self.key.clone())
590 }
591}
592
593impl PipelineCommand for DecrByCommand {
594 fn name(&self) -> &str {
595 self.command_name()
596 }
597
598 fn args(&self) -> Vec<RespValue> {
599 <Self as Command>::args(self)
600 }
601
602 fn key(&self) -> Option<String> {
603 Some(self.key.clone())
604 }
605}
606
607impl PipelineCommand for ExistsCommand {
608 fn name(&self) -> &str {
609 self.command_name()
610 }
611
612 fn args(&self) -> Vec<RespValue> {
613 <Self as Command>::args(self)
614 }
615
616 fn key(&self) -> Option<String> {
617 self.keys.first().cloned()
618 }
619}
620
621impl PipelineCommand for ExpireCommand {
622 fn name(&self) -> &str {
623 self.command_name()
624 }
625
626 fn args(&self) -> Vec<RespValue> {
627 <Self as Command>::args(self)
628 }
629
630 fn key(&self) -> Option<String> {
631 Some(self.key.clone())
632 }
633}
634
635impl PipelineCommand for TtlCommand {
636 fn name(&self) -> &str {
637 self.command_name()
638 }
639
640 fn args(&self) -> Vec<RespValue> {
641 <Self as Command>::args(self)
642 }
643
644 fn key(&self) -> Option<String> {
645 Some(self.key.clone())
646 }
647}