sql_cli/data/
temp_table_registry.rs1use anyhow::{anyhow, Result};
5use std::collections::HashMap;
6use std::sync::Arc;
7use tracing::{debug, info};
8
9use crate::data::datatable::DataTable;
10
11#[derive(Debug, Clone)]
14pub struct TempTableRegistry {
15 tables: HashMap<String, Arc<DataTable>>,
16}
17
18impl TempTableRegistry {
19 pub fn new() -> Self {
21 debug!("Creating new TempTableRegistry");
22 Self {
23 tables: HashMap::new(),
24 }
25 }
26
27 pub fn insert(&mut self, name: String, table: Arc<DataTable>) -> Result<()> {
30 if !name.starts_with('#') {
31 return Err(anyhow!(
32 "Temporary table name must start with #, got: {}",
33 name
34 ));
35 }
36
37 if self.tables.contains_key(&name) {
38 return Err(anyhow!(
39 "Temporary table {} already exists. Drop it first or use a different name.",
40 name
41 ));
42 }
43
44 let row_count = table.row_count();
45 let col_count = table.column_count();
46
47 info!(
48 "Storing temporary table {} ({} rows, {} columns)",
49 name, row_count, col_count
50 );
51
52 self.tables.insert(name, table);
53 Ok(())
54 }
55
56 pub fn insert_or_replace(&mut self, name: String, table: Arc<DataTable>) -> Result<()> {
58 if !name.starts_with('#') {
59 return Err(anyhow!(
60 "Temporary table name must start with #, got: {}",
61 name
62 ));
63 }
64
65 let row_count = table.row_count();
66 let col_count = table.column_count();
67
68 if self.tables.contains_key(&name) {
69 info!(
70 "Replacing temporary table {} ({} rows, {} columns)",
71 name, row_count, col_count
72 );
73 } else {
74 info!(
75 "Storing temporary table {} ({} rows, {} columns)",
76 name, row_count, col_count
77 );
78 }
79
80 self.tables.insert(name, table);
81 Ok(())
82 }
83
84 pub fn get(&self, name: &str) -> Option<Arc<DataTable>> {
87 debug!("Looking up temporary table: {}", name);
88 self.tables.get(name).cloned()
89 }
90
91 pub fn contains(&self, name: &str) -> bool {
93 self.tables.contains_key(name)
94 }
95
96 pub fn drop(&mut self, name: &str) -> bool {
99 if let Some(_table) = self.tables.remove(name) {
100 info!("Dropped temporary table: {}", name);
101 true
102 } else {
103 debug!("Temporary table {} does not exist, cannot drop", name);
104 false
105 }
106 }
107
108 pub fn count(&self) -> usize {
110 self.tables.len()
111 }
112
113 pub fn list_tables(&self) -> Vec<String> {
115 self.tables.keys().cloned().collect()
116 }
117
118 pub fn clear(&mut self) {
121 let count = self.tables.len();
122 self.tables.clear();
123 if count > 0 {
124 info!("Cleared {} temporary tables", count);
125 }
126 }
127
128 pub fn is_empty(&self) -> bool {
130 self.tables.is_empty()
131 }
132}
133
134impl Default for TempTableRegistry {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use crate::data::datatable::{DataColumn, DataRow, DataValue};
144
145 fn create_test_table(rows: usize) -> DataTable {
146 let mut table = DataTable::new("test_table");
147
148 table.add_column(DataColumn::new("id".to_string()));
149 table.add_column(DataColumn::new("name".to_string()));
150
151 for i in 0..rows {
152 table.add_row(DataRow {
153 values: vec![
154 DataValue::Integer(i as i64),
155 DataValue::String(format!("row_{}", i)),
156 ],
157 });
158 }
159
160 table
161 }
162
163 #[test]
164 fn test_new_registry() {
165 let registry = TempTableRegistry::new();
166 assert_eq!(registry.count(), 0);
167 assert!(registry.is_empty());
168 }
169
170 #[test]
171 fn test_insert_and_get() {
172 let mut registry = TempTableRegistry::new();
173 let table = create_test_table(10);
174
175 let result = registry.insert("#test".to_string(), Arc::new(table));
176 assert!(result.is_ok());
177 assert_eq!(registry.count(), 1);
178
179 let retrieved = registry.get("#test");
180 assert!(retrieved.is_some());
181 assert_eq!(retrieved.unwrap().row_count(), 10);
182 }
183
184 #[test]
185 fn test_insert_without_hash_fails() {
186 let mut registry = TempTableRegistry::new();
187 let table = create_test_table(5);
188
189 let result = registry.insert("test".to_string(), Arc::new(table));
190 assert!(result.is_err());
191 assert!(result
192 .unwrap_err()
193 .to_string()
194 .contains("must start with #"));
195 }
196
197 #[test]
198 fn test_insert_duplicate_fails() {
199 let mut registry = TempTableRegistry::new();
200 let table1 = create_test_table(5);
201 let table2 = create_test_table(10);
202
203 registry
204 .insert("#test".to_string(), Arc::new(table1))
205 .unwrap();
206 let result = registry.insert("#test".to_string(), Arc::new(table2));
207
208 assert!(result.is_err());
209 assert!(result.unwrap_err().to_string().contains("already exists"));
210 }
211
212 #[test]
213 fn test_insert_or_replace() {
214 let mut registry = TempTableRegistry::new();
215 let table1 = create_test_table(5);
216 let table2 = create_test_table(10);
217
218 registry
219 .insert_or_replace("#test".to_string(), Arc::new(table1))
220 .unwrap();
221 assert_eq!(registry.get("#test").unwrap().row_count(), 5);
222
223 registry
224 .insert_or_replace("#test".to_string(), Arc::new(table2))
225 .unwrap();
226 assert_eq!(registry.get("#test").unwrap().row_count(), 10);
227 }
228
229 #[test]
230 fn test_contains() {
231 let mut registry = TempTableRegistry::new();
232 let table = create_test_table(5);
233
234 assert!(!registry.contains("#test"));
235 registry
236 .insert("#test".to_string(), Arc::new(table))
237 .unwrap();
238 assert!(registry.contains("#test"));
239 }
240
241 #[test]
242 fn test_drop() {
243 let mut registry = TempTableRegistry::new();
244 let table = create_test_table(5);
245
246 registry
247 .insert("#test".to_string(), Arc::new(table))
248 .unwrap();
249 assert_eq!(registry.count(), 1);
250
251 let dropped = registry.drop("#test");
252 assert!(dropped);
253 assert_eq!(registry.count(), 0);
254
255 let dropped_again = registry.drop("#test");
256 assert!(!dropped_again);
257 }
258
259 #[test]
260 fn test_list_tables() {
261 let mut registry = TempTableRegistry::new();
262 let table1 = create_test_table(5);
263 let table2 = create_test_table(10);
264
265 registry
266 .insert("#table1".to_string(), Arc::new(table1))
267 .unwrap();
268 registry
269 .insert("#table2".to_string(), Arc::new(table2))
270 .unwrap();
271
272 let tables = registry.list_tables();
273 assert_eq!(tables.len(), 2);
274 assert!(tables.contains(&"#table1".to_string()));
275 assert!(tables.contains(&"#table2".to_string()));
276 }
277
278 #[test]
279 fn test_clear() {
280 let mut registry = TempTableRegistry::new();
281 let table1 = create_test_table(5);
282 let table2 = create_test_table(10);
283
284 registry
285 .insert("#table1".to_string(), Arc::new(table1))
286 .unwrap();
287 registry
288 .insert("#table2".to_string(), Arc::new(table2))
289 .unwrap();
290
291 assert_eq!(registry.count(), 2);
292
293 registry.clear();
294 assert_eq!(registry.count(), 0);
295 assert!(registry.is_empty());
296 }
297
298 #[test]
299 fn test_multiple_tables() {
300 let mut registry = TempTableRegistry::new();
301
302 for i in 0..5 {
303 let table = create_test_table(i * 10);
304 registry
305 .insert(format!("#table{}", i), Arc::new(table))
306 .unwrap();
307 }
308
309 assert_eq!(registry.count(), 5);
310
311 for i in 0..5 {
312 let table = registry.get(&format!("#table{}", i));
313 assert!(table.is_some());
314 assert_eq!(table.unwrap().row_count(), i * 10);
315 }
316 }
317}