1use std::collections::HashMap;
2use std::sync::Arc;
3
4use parking_lot::RwLock;
5use serde::{Deserialize, Serialize};
6
7use crate::types::expr::Expression;
8use crate::wal::redo::{CreateMacroRedo, DropMacroRedo};
9use crate::wal::traits::WalWriter;
10use crate::wal::types::WalOpType;
11use crate::StorageError;
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15pub struct MacroParamDef {
16 pub name: String,
18 pub default: Option<Expression>,
20}
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct MacroDef {
29 pub name: String,
31 pub params: Vec<MacroParamDef>,
33 pub body: Expression,
36}
37
38impl MacroDef {
39 pub fn new(name: String, params: Vec<MacroParamDef>, body: Expression) -> Self {
40 Self { name, params, body }
41 }
42
43 pub fn required_params(&self) -> usize {
45 self.params.iter().filter(|p| p.default.is_none()).count()
46 }
47}
48
49pub trait MacroStorage: Send + Sync {
54 fn load_all(&self) -> Result<Vec<MacroDef>, StorageError>;
56 fn save(&self, def: &MacroDef) -> Result<(), StorageError>;
58 fn delete(&self, name: &str) -> Result<(), StorageError>;
60}
61
62#[derive(Debug, Default)]
64pub struct MemMacroStorage {
65 data: RwLock<HashMap<String, MacroDef>>,
66}
67
68impl MemMacroStorage {
69 pub fn new() -> Self {
70 Self {
71 data: RwLock::new(HashMap::new()),
72 }
73 }
74}
75
76impl MacroStorage for MemMacroStorage {
77 fn load_all(&self) -> Result<Vec<MacroDef>, StorageError> {
78 Ok(self.data.read().values().cloned().collect())
79 }
80
81 fn save(&self, def: &MacroDef) -> Result<(), StorageError> {
82 self.data.write().insert(def.name.clone(), def.clone());
83 Ok(())
84 }
85
86 fn delete(&self, name: &str) -> Result<(), StorageError> {
87 self.data.write().remove(name);
88 Ok(())
89 }
90}
91
92pub struct MacroManager {
98 macros: RwLock<HashMap<String, Arc<MacroDef>>>,
99 storage: Option<Arc<dyn MacroStorage>>,
100 wal_writer: Option<Arc<parking_lot::Mutex<dyn WalWriter>>>,
101}
102
103impl MacroManager {
104 pub fn new() -> Self {
106 Self {
107 macros: RwLock::new(HashMap::new()),
108 storage: None,
109 wal_writer: None,
110 }
111 }
112
113 pub fn with_storage(storage: Arc<dyn MacroStorage>) -> Self {
115 Self {
116 macros: RwLock::new(HashMap::new()),
117 storage: Some(storage),
118 wal_writer: None,
119 }
120 }
121
122 pub fn with_wal(
124 storage: Arc<dyn MacroStorage>,
125 wal_writer: Arc<parking_lot::Mutex<dyn WalWriter>>,
126 ) -> Self {
127 Self {
128 macros: RwLock::new(HashMap::new()),
129 storage: Some(storage),
130 wal_writer: Some(wal_writer),
131 }
132 }
133
134 fn canonical(name: &str) -> String {
135 name.to_ascii_uppercase()
136 }
137
138 pub fn initialize(&self) -> Result<(), StorageError> {
140 if let Some(ref storage) = self.storage {
141 let defs = storage.load_all()?;
142 let mut map = self.macros.write();
143 for def in defs {
144 map.insert(Self::canonical(&def.name), Arc::new(def));
145 }
146 }
147 Ok(())
148 }
149
150 pub fn validate_definition(def: &MacroDef) -> Result<(), StorageError> {
158 if def.name.trim().is_empty() {
159 return Err(StorageError::db_error("Macro name must not be empty"));
160 }
161 let mut seen = std::collections::HashSet::new();
162 for param in &def.params {
163 if param.name.trim().is_empty() {
164 return Err(StorageError::db_error(format!(
165 "Macro '{}' has an empty parameter name",
166 def.name
167 )));
168 }
169 let key = param.name.to_ascii_uppercase();
170 if !seen.insert(key) {
171 return Err(StorageError::db_error(format!(
172 "Macro '{}' has duplicate parameter '{}'",
173 def.name, param.name
174 )));
175 }
176 }
177 Ok(())
178 }
179
180 pub fn create_macro(&self, def: MacroDef) -> Result<(), StorageError> {
182 Self::validate_definition(&def)?;
183 let key = Self::canonical(&def.name);
184 {
185 let map = self.macros.read();
186 if map.contains_key(&key) {
187 return Err(StorageError::db_error(format!(
188 "Macro '{}' already exists",
189 def.name
190 )));
191 }
192 }
193
194 if let Some(ref storage) = self.storage {
195 storage.save(&def)?;
196 }
197 self.write_wal_create(&def)?;
198
199 let mut map = self.macros.write();
200 if map.contains_key(&key) {
202 return Err(StorageError::db_error(format!(
203 "Macro '{}' already exists",
204 def.name
205 )));
206 }
207 map.insert(key, Arc::new(def));
208 Ok(())
209 }
210
211 pub fn drop_macro(&self, name: &str) -> Result<(), StorageError> {
213 let key = Self::canonical(name);
214 {
215 let mut map = self.macros.write();
216 if map.remove(&key).is_none() {
217 return Err(StorageError::db_error(format!(
218 "Macro '{}' does not exist",
219 name
220 )));
221 }
222 }
223
224 if let Some(ref storage) = self.storage {
225 storage.delete(name)?;
226 }
227 self.write_wal_drop(name)?;
228 Ok(())
229 }
230
231 pub fn get_macro(&self, name: &str) -> Option<Arc<MacroDef>> {
233 let map = self.macros.read();
234 map.get(&Self::canonical(name)).cloned()
235 }
236
237 pub fn exists(&self, name: &str) -> bool {
239 let map = self.macros.read();
240 map.contains_key(&Self::canonical(name))
241 }
242
243 pub fn list_macros(&self) -> Vec<Arc<MacroDef>> {
245 let map = self.macros.read();
246 let mut defs: Vec<Arc<MacroDef>> = map.values().cloned().collect();
247 defs.sort_by(|a, b| a.name.cmp(&b.name));
248 defs
249 }
250
251 fn wal_timestamp() -> u64 {
252 std::time::SystemTime::now()
253 .duration_since(std::time::UNIX_EPOCH)
254 .unwrap_or_default()
255 .as_millis() as u64
256 }
257
258 fn write_wal_create(&self, def: &MacroDef) -> Result<(), StorageError> {
259 if let Some(ref wal_writer) = self.wal_writer {
260 let redo = CreateMacroRedo {
261 space_name: String::new(),
262 name: def.name.clone(),
263 params: def.params.clone(),
264 body: def.body.clone(),
265 };
266 let payload = postcard::to_allocvec(&redo)
267 .map_err(|e| StorageError::serialize_error(e.to_string()))?;
268 let mut writer = wal_writer.lock();
269 writer
270 .append_entry(WalOpType::CreateMacro, Self::wal_timestamp(), &payload)
271 .map_err(|e| StorageError::db_error(format!("WAL write error: {}", e)))?;
272 }
273 Ok(())
274 }
275
276 fn write_wal_drop(&self, name: &str) -> Result<(), StorageError> {
277 if let Some(ref wal_writer) = self.wal_writer {
278 let redo = DropMacroRedo {
279 space_name: String::new(),
280 name: name.to_string(),
281 };
282 let payload = postcard::to_allocvec(&redo)
283 .map_err(|e| StorageError::serialize_error(e.to_string()))?;
284 let mut writer = wal_writer.lock();
285 writer
286 .append_entry(WalOpType::DropMacro, Self::wal_timestamp(), &payload)
287 .map_err(|e| StorageError::db_error(format!("WAL write error: {}", e)))?;
288 }
289 Ok(())
290 }
291
292 pub fn replay_create(&self, redo: &CreateMacroRedo) -> Result<(), StorageError> {
294 let def = MacroDef::new(redo.name.clone(), redo.params.clone(), redo.body.clone());
295 Self::validate_definition(&def)?;
296 let mut map = self.macros.write();
297 map.insert(Self::canonical(&def.name), Arc::new(def));
298 Ok(())
299 }
300
301 pub fn replay_drop(&self, redo: &DropMacroRedo) -> Result<(), StorageError> {
303 let mut map = self.macros.write();
304 map.remove(&Self::canonical(&redo.name));
305 Ok(())
306 }
307}
308
309impl Default for MacroManager {
310 fn default() -> Self {
311 Self::new()
312 }
313}
314
315impl std::fmt::Debug for MacroManager {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 f.debug_struct("MacroManager")
318 .field("count", &self.macros.read().len())
319 .finish()
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326 use crate::types::expr::Expression;
327
328 fn sample_def(name: &str) -> MacroDef {
329 MacroDef::new(
330 name.to_string(),
331 vec![MacroParamDef {
332 name: "x".to_string(),
333 default: None,
334 }],
335 Expression::Binary {
336 left: Box::new(Expression::variable("x")),
337 op: crate::types::operators::BinaryOperator::Multiply,
338 right: Box::new(Expression::literal(crate::Value::Int(2))),
339 },
340 )
341 }
342
343 #[test]
344 fn test_macro_create_get_drop() {
345 let manager = MacroManager::new();
346 manager.create_macro(sample_def("double")).unwrap();
347 assert!(manager.exists("double"));
348 assert!(manager.exists("DOUBLE"));
349 let def = manager.get_macro("Double").unwrap();
350 assert_eq!(def.params.len(), 1);
351 assert_eq!(def.required_params(), 1);
352 manager.drop_macro("double").unwrap();
353 assert!(!manager.exists("double"));
354 }
355
356 #[test]
357 fn test_macro_duplicate_create() {
358 let manager = MacroManager::new();
359 manager.create_macro(sample_def("m")).unwrap();
360 assert!(manager.create_macro(sample_def("M")).is_err());
361 }
362
363 #[test]
364 fn test_macro_drop_missing() {
365 let manager = MacroManager::new();
366 assert!(manager.drop_macro("nope").is_err());
367 }
368
369 #[test]
370 fn test_macro_duplicate_params_rejected() {
371 let mut def = sample_def("bad");
372 def.params.push(MacroParamDef {
373 name: "X".to_string(),
374 default: None,
375 });
376 assert!(MacroManager::validate_definition(&def).is_err());
377 }
378
379 #[test]
380 fn test_macro_list_sorted() {
381 let manager = MacroManager::new();
382 manager.create_macro(sample_def("b")).unwrap();
383 manager.create_macro(sample_def("a")).unwrap();
384 let names: Vec<String> = manager
385 .list_macros()
386 .iter()
387 .map(|d| d.name.clone())
388 .collect();
389 assert_eq!(names, vec!["a".to_string(), "b".to_string()]);
390 }
391
392 #[test]
393 fn test_macro_with_storage() {
394 let storage = Arc::new(MemMacroStorage::new());
395 let manager = MacroManager::with_storage(storage);
396 manager.create_macro(sample_def("m1")).unwrap();
397 assert!(manager.exists("m1"));
398 manager.initialize().unwrap();
399 assert!(manager.exists("m1"));
400 }
401
402 #[test]
403 fn test_macro_replay() {
404 let manager = MacroManager::new();
405 let def = sample_def("r");
406 manager
407 .replay_create(&CreateMacroRedo {
408 space_name: String::new(),
409 name: def.name.clone(),
410 params: def.params.clone(),
411 body: def.body.clone(),
412 })
413 .unwrap();
414 assert!(manager.exists("r"));
415 manager
416 .replay_drop(&DropMacroRedo {
417 space_name: String::new(),
418 name: "r".to_string(),
419 })
420 .unwrap();
421 assert!(!manager.exists("r"));
422 }
423}