Skip to main content

cynos_storage/
cache.rs

1//! Cache management for Cynos database.
2//!
3//! This module provides the `TableCache` struct which manages multiple table stores.
4
5use crate::row_store::RowStore;
6use alloc::collections::BTreeMap;
7use alloc::format;
8use alloc::rc::Rc;
9use alloc::string::{String, ToString};
10use alloc::vec::Vec;
11use cynos_core::schema::Table;
12use cynos_core::{Error, Result, Row, RowId};
13
14/// Cache for managing multiple table stores.
15pub struct TableCache {
16    /// Table name → RowStore mapping.
17    tables: BTreeMap<String, RowStore>,
18}
19
20impl TableCache {
21    /// Creates a new empty table cache.
22    pub fn new() -> Self {
23        Self {
24            tables: BTreeMap::new(),
25        }
26    }
27
28    /// Creates a table in the cache.
29    pub fn create_table(&mut self, schema: Table) -> Result<()> {
30        let name = schema.name().to_string();
31        if self.tables.contains_key(&name) {
32            return Err(Error::invalid_schema(format!(
33                "Table already exists: {}",
34                name
35            )));
36        }
37        self.tables.insert(name, RowStore::new(schema));
38        Ok(())
39    }
40
41    /// Drops a table from the cache.
42    pub fn drop_table(&mut self, name: &str) -> Result<()> {
43        if self.tables.remove(name).is_none() {
44            return Err(Error::table_not_found(name));
45        }
46        Ok(())
47    }
48
49    /// Gets a reference to a table store.
50    pub fn get_table(&self, name: &str) -> Option<&RowStore> {
51        self.tables.get(name)
52    }
53
54    /// Gets a mutable reference to a table store.
55    pub fn get_table_mut(&mut self, name: &str) -> Option<&mut RowStore> {
56        self.tables.get_mut(name)
57    }
58
59    /// Returns the number of tables.
60    pub fn table_count(&self) -> usize {
61        self.tables.len()
62    }
63
64    /// Returns all table names.
65    pub fn table_names(&self) -> Vec<&str> {
66        self.tables.keys().map(|s| s.as_str()).collect()
67    }
68
69    /// Returns the total row count across all tables.
70    pub fn total_row_count(&self) -> usize {
71        self.tables.values().map(|t| t.len()).sum()
72    }
73
74    /// Gets a row by table name and row ID.
75    pub fn get_row(&self, table: &str, row_id: RowId) -> Option<Rc<Row>> {
76        self.tables.get(table).and_then(|t| t.get(row_id))
77    }
78
79    /// Gets multiple rows by table name and row IDs.
80    pub fn get_many(&self, table: &str, row_ids: &[RowId]) -> Vec<Option<Rc<Row>>> {
81        if let Some(store) = self.tables.get(table) {
82            store.get_many(row_ids)
83        } else {
84            row_ids.iter().map(|_| None).collect()
85        }
86    }
87
88    /// Checks if a table exists.
89    pub fn has_table(&self, name: &str) -> bool {
90        self.tables.contains_key(name)
91    }
92
93    /// Clears all tables.
94    pub fn clear(&mut self) {
95        for store in self.tables.values_mut() {
96            store.clear();
97        }
98    }
99
100    /// Clears a specific table.
101    pub fn clear_table(&mut self, name: &str) -> Result<()> {
102        if let Some(store) = self.tables.get_mut(name) {
103            store.clear();
104            Ok(())
105        } else {
106            Err(Error::table_not_found(name))
107        }
108    }
109}
110
111impl Default for TableCache {
112    fn default() -> Self {
113        Self::new()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use cynos_core::schema::TableBuilder;
121    use cynos_core::{DataType, Value};
122    use alloc::vec;
123
124    fn test_schema(name: &str) -> Table {
125        TableBuilder::new(name)
126            .unwrap()
127            .add_column("id", DataType::Int64)
128            .unwrap()
129            .add_column("name", DataType::String)
130            .unwrap()
131            .add_primary_key(&["id"], false)
132            .unwrap()
133            .build()
134            .unwrap()
135    }
136
137    #[test]
138    fn test_cache_create_table() {
139        let mut cache = TableCache::new();
140        let result = cache.create_table(test_schema("users"));
141        assert!(result.is_ok());
142        assert!(cache.has_table("users"));
143    }
144
145    #[test]
146    fn test_cache_create_duplicate_table() {
147        let mut cache = TableCache::new();
148        cache.create_table(test_schema("users")).unwrap();
149        let result = cache.create_table(test_schema("users"));
150        assert!(result.is_err());
151    }
152
153    #[test]
154    fn test_cache_drop_table() {
155        let mut cache = TableCache::new();
156        cache.create_table(test_schema("users")).unwrap();
157        let result = cache.drop_table("users");
158        assert!(result.is_ok());
159        assert!(!cache.has_table("users"));
160    }
161
162    #[test]
163    fn test_cache_drop_nonexistent_table() {
164        let mut cache = TableCache::new();
165        let result = cache.drop_table("nonexistent");
166        assert!(result.is_err());
167    }
168
169    #[test]
170    fn test_cache_get_table() {
171        let mut cache = TableCache::new();
172        cache.create_table(test_schema("users")).unwrap();
173
174        assert!(cache.get_table("users").is_some());
175        assert!(cache.get_table("nonexistent").is_none());
176    }
177
178    #[test]
179    fn test_cache_insert_and_get() {
180        let mut cache = TableCache::new();
181        cache.create_table(test_schema("users")).unwrap();
182
183        let row = Row::new(1, vec![Value::Int64(1), Value::String("Alice".into())]);
184        cache.get_table_mut("users").unwrap().insert(row).unwrap();
185
186        let retrieved = cache.get_row("users", 1);
187        assert!(retrieved.is_some());
188    }
189
190    #[test]
191    fn test_cache_total_row_count() {
192        let mut cache = TableCache::new();
193        cache.create_table(test_schema("users")).unwrap();
194        cache.create_table(test_schema("orders")).unwrap();
195
196        cache.get_table_mut("users").unwrap()
197            .insert(Row::new(1, vec![Value::Int64(1), Value::String("Alice".into())]))
198            .unwrap();
199        cache.get_table_mut("users").unwrap()
200            .insert(Row::new(2, vec![Value::Int64(2), Value::String("Bob".into())]))
201            .unwrap();
202        cache.get_table_mut("orders").unwrap()
203            .insert(Row::new(3, vec![Value::Int64(1), Value::String("Order1".into())]))
204            .unwrap();
205
206        assert_eq!(cache.total_row_count(), 3);
207    }
208
209    #[test]
210    fn test_cache_clear() {
211        let mut cache = TableCache::new();
212        cache.create_table(test_schema("users")).unwrap();
213        cache.get_table_mut("users").unwrap()
214            .insert(Row::new(1, vec![Value::Int64(1), Value::String("Alice".into())]))
215            .unwrap();
216
217        cache.clear();
218        assert_eq!(cache.total_row_count(), 0);
219        // Tables still exist, just empty
220        assert!(cache.has_table("users"));
221    }
222}