redis_imitate/commands/executor.rs
1//! # Command Executor Module
2//!
3//! This module provides the execution layer for Redis-like commands,
4//! handling command processing and storage interactions with thread-safe
5//! mechanisms using Arc and Mutex.
6
7use std::sync::Arc;
8use std::sync::Mutex;
9use crate::storage::memory::MemoryStorage;
10
11use super::parser::Command;
12
13/// A thread-safe command executor that processes Redis-like commands
14///
15/// Manages the execution of commands against a shared memory storage,
16/// providing atomic operations and transaction support.
17pub struct CommandExecutor {
18 storage: Arc<Mutex<MemoryStorage>>
19}
20
21impl CommandExecutor {
22 /// Creates a new CommandExecutor with the given shared storage
23 ///
24 /// # Arguments
25 ///
26 /// * `storage` - Thread-safe reference to the memory storage
27 pub fn new(storage: Arc<Mutex<MemoryStorage>>) -> Self {
28 CommandExecutor { storage }
29 }
30
31 /// Executes a single command and returns the result as a string
32 ///
33 /// # Arguments
34 ///
35 /// * `command` - The command to execute
36 ///
37 /// # Returns
38 ///
39 /// A string containing the command's result or error message
40 ///
41 /// # Command Results
42 ///
43 /// * SET - Returns "OK" on success
44 /// * GET - Returns the value or "(nil)" if not found
45 /// * DEL - Returns "1" if key was deleted, "0" if key didn't exist
46 /// * INCR/DECR - Returns the new value after increment/decrement
47 /// * LPUSH/RPUSH - Returns the new length of the list
48 /// * LPOP/RPOP - Returns the popped value or "(nil)" if list is empty
49 /// * LLEN - Returns the length of the list
50 /// * MULTI - Returns "OK" when transaction starts
51 /// * EXEC - Returns all transaction results followed by "OK"
52 /// * DISCARD - Returns "OK" if transaction was rolled back successfully
53 pub fn execute_command(&self, command: Command) -> String {
54 let mut storage = self.storage.lock().unwrap();
55 match command {
56 Command::Set(key, value) => {
57 storage.set(key, value);
58 "OK".to_string()
59 },
60 Command::Get(key) => {
61 match storage.get(&key) {
62 Some(value) => value.clone(),
63 None => "(nil)".to_string(),
64 }
65 },
66 Command::Del(key) => {
67 match storage.del(&key) {
68 true => "1".to_string(),
69 false => "0".to_string(),
70 }
71 },
72 Command::Incr(key) => {
73 storage.incr(&key).to_string()
74 },
75 Command::Decr(key) => {
76 storage.decr(&key).to_string()
77 },
78 Command::LPush(key, value) => {
79 storage.lpush(&key, value).to_string()
80 },
81 Command::RPush(key, value) => {
82 storage.rpush(&key, value).to_string()
83 },
84 Command::LPop(key) => {
85 match storage.lpop(&key) {
86 Some(value) => value,
87 None => "(nil)".to_string(),
88 }
89 },
90 Command::RPop(key) => {
91 match storage.rpop(&key) {
92 Some(value) => value,
93 None => "(nil)".to_string(),
94 }
95 },
96 Command::LLen(key) => {
97 storage.llen(&key).to_string()
98 },
99 Command::Multi =>{
100 storage.start_transaction();
101 "OK".to_string()
102 },
103 Command::Exec => {
104 match storage.commit_transaction() {
105 Ok(results) => {
106 let mut response = String::new();
107 for result in results {
108 response.push_str(&format!("{}\n", result));
109 }
110 response.push_str("OK\n");
111 response
112 },
113 Err(e) => format!("ERR: {}\n", e),
114 }
115 },
116 Command::Discard => {
117 match storage.rollback_transaction() {
118 Ok(_) => "OK".to_string(),
119 Err(e) => format!("ERR: {}", e),
120 }
121 },
122 Command::Unknown(cmd) => format!("ERR unknown command '{}'", cmd),
123 }
124 }
125
126 /// Executes a batch of commands as part of a transaction
127 ///
128 /// # Arguments
129 ///
130 /// * `commands` - A slice of commands to execute in order
131 ///
132 /// # Returns
133 ///
134 /// A vector of strings containing the results of each command
135 ///
136 /// # Transaction Behavior
137 ///
138 /// * All commands in the transaction are executed atomically
139 /// * If any command fails, the entire transaction is rolled back
140 /// * Results are collected and returned in the order of execution
141 pub fn execute_transaction(&self, commands: &[Command]) -> Vec<String> {
142 let mut results = Vec::new();
143 let mut storage = self.storage.lock().unwrap();
144
145 for command in commands {
146 let result = match command {
147 Command::Set(key, value) => {
148 storage.set(key.to_string(), value.to_string());
149 "OK".to_string()
150 },
151 Command::Get(key) => {
152 match storage.get(&key) {
153 Some(value) => value.clone(),
154 None => "(nil)".to_string(),
155 }
156 },
157 Command::Del(key) => {
158 match storage.del(&key) {
159 true => "1".to_string(),
160 false => "0".to_string(),
161 }
162 },
163 Command::Incr(key) => {
164 storage.incr(&key).to_string()
165 },
166 Command::Decr(key) => {
167 storage.decr(&key).to_string()
168 },
169 Command::LPush(key, value) => {
170 storage.lpush(&key, value.to_string()).to_string()
171 },
172 Command::RPush(key, value) => {
173 storage.rpush(&key, value.to_string()).to_string()
174 },
175 Command::LPop(key) => {
176 match storage.lpop(&key) {
177 Some(value) => value,
178 None => "(nil)".to_string(),
179 }
180 },
181 Command::RPop(key) => {
182 match storage.rpop(&key) {
183 Some(value) => value,
184 None => "(nil)".to_string(),
185 }
186 },
187 Command::LLen(key) => {
188 storage.llen(&key).to_string()
189 },
190 Command::Multi =>{
191 storage.start_transaction();
192 "OK".to_string()
193 },
194 Command::Exec => {
195 match storage.commit_transaction() {
196 Ok(results) => {
197 let mut response = String::new();
198 for result in results {
199 response.push_str(&format!("{}\n", result));
200 }
201 response.push_str("OK\n");
202 response
203 },
204 Err(e) => format!("ERR: {}\n", e),
205 }
206 },
207 Command::Discard => {
208 match storage.rollback_transaction() {
209 Ok(_) => "OK".to_string(),
210 Err(e) => format!("ERR: {}", e),
211 }
212 },
213 Command::Unknown(cmd) => format!("ERR unknown command '{}'", cmd),
214
215 };
216 results.push(result);
217 }
218
219 results
220 }
221
222}