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}