Skip to main content

regulus_db/index/
manager.rs

1use std::collections::HashMap;
2use crate::index::btree::BTreeIndex;
3
4/// 索引元数据
5#[derive(Debug, Clone)]
6pub struct IndexMeta {
7    pub table: String,
8    pub columns: Vec<String>,  // 支持多列
9    pub is_unique: bool,       // 是否唯一索引
10}
11
12/// 索引管理器
13#[derive(Debug)]
14pub struct IndexManager {
15    /// 索引键 "table:col1,col2" -> BTreeIndex
16    indexes: HashMap<String, BTreeIndex>,
17    /// 索引键 "table:col1,col2" -> IndexMeta
18    index_meta: HashMap<String, IndexMeta>,
19    /// 表 -> 索引键列表 (用于快速查找表的所有索引)
20    table_indexes: HashMap<String, Vec<String>>,
21}
22
23impl IndexManager {
24    pub fn new() -> Self {
25        IndexManager {
26            indexes: HashMap::new(),
27            index_meta: HashMap::new(),
28            table_indexes: HashMap::new(),
29        }
30    }
31
32    /// 生成索引键
33    fn make_index_key(table: &str, columns: &[&str]) -> String {
34        format!("{}:{}", table, columns.join(","))
35    }
36
37    /// 为表列创建索引(支持复合索引)
38    pub fn create_index(&mut self, table: &str, columns: &[&str]) {
39        let key = Self::make_index_key(table, columns);
40
41        if !self.indexes.contains_key(&key) {
42            let index = BTreeIndex::new_composite(4, columns);
43            let meta = IndexMeta {
44                table: table.to_string(),
45                columns: columns.iter().map(|s| s.to_string()).collect(),
46                is_unique: false,
47            };
48
49            self.indexes.insert(key.clone(), index);
50            self.index_meta.insert(key.clone(), meta);
51
52            // 更新表的索引列表
53            self.table_indexes
54                .entry(table.to_string())
55                .or_insert_with(Vec::new)
56                .push(key);
57        }
58    }
59
60    /// 创建唯一索引
61    pub fn create_unique_index(&mut self, table: &str, columns: &[&str]) {
62        let key = Self::make_index_key(table, columns);
63
64        if !self.indexes.contains_key(&key) {
65            let index = BTreeIndex::new_composite(4, columns);
66            let meta = IndexMeta {
67                table: table.to_string(),
68                columns: columns.iter().map(|s| s.to_string()).collect(),
69                is_unique: true,
70            };
71
72            self.indexes.insert(key.clone(), index);
73            self.index_meta.insert(key.clone(), meta);
74
75            self.table_indexes
76                .entry(table.to_string())
77                .or_insert_with(Vec::new)
78                .push(key);
79        }
80    }
81
82    /// 删除索引
83    pub fn drop_index(&mut self, table: &str, columns: &[&str]) -> bool {
84        let key = Self::make_index_key(table, columns);
85
86        if self.indexes.remove(&key).is_some() {
87            self.index_meta.remove(&key);
88            if let Some(index_list) = self.table_indexes.get_mut(table) {
89                if let Some(pos) = index_list.iter().position(|k| k == &key) {
90                    index_list.remove(pos);
91                }
92            }
93            return true;
94        }
95        false
96    }
97
98    /// 检查列是否有索引(单列检查)
99    pub fn has_index(&self, table: &str, column: &str) -> bool {
100        let key = Self::make_index_key(table, &[column]);
101        self.indexes.contains_key(&key)
102    }
103
104    /// 检查复合索引是否存在
105    pub fn has_composite_index(&self, table: &str, columns: &[&str]) -> bool {
106        let key = Self::make_index_key(table, columns);
107        self.indexes.contains_key(&key)
108    }
109
110    /// 获取索引(不可变引用,单列)
111    pub fn get_index(&self, table: &str, column: &str) -> Option<&BTreeIndex> {
112        let key = Self::make_index_key(table, &[column]);
113        self.indexes.get(&key)
114    }
115
116    /// 获取复合索引(不可变引用)
117    pub fn get_composite_index(&self, table: &str, columns: &[&str]) -> Option<&BTreeIndex> {
118        let key = Self::make_index_key(table, columns);
119        self.indexes.get(&key)
120    }
121
122    /// 获取索引(可变引用,单列)
123    pub fn get_index_mut(&mut self, table: &str, column: &str) -> Option<&mut BTreeIndex> {
124        let key = Self::make_index_key(table, &[column]);
125        self.indexes.get_mut(&key)
126    }
127
128    /// 获取复合索引(可变引用)
129    pub fn get_composite_index_mut(&mut self, table: &str, columns: &[&str]) -> Option<&mut BTreeIndex> {
130        let key = Self::make_index_key(table, columns);
131        self.indexes.get_mut(&key)
132    }
133
134    /// 获取表的所有索引元数据
135    pub fn get_table_indexes(&self, table: &str) -> Vec<&IndexMeta> {
136        self.table_indexes
137            .get(table)
138            .map(|keys| keys.iter().filter_map(|k| self.index_meta.get(k)).collect())
139            .unwrap_or_default()
140    }
141
142    /// 删除表的所有索引
143    pub fn drop_table_indexes(&mut self, table: &str) {
144        if let Some(keys) = self.table_indexes.remove(table) {
145            for key in &keys {
146                self.indexes.remove(key);
147                self.index_meta.remove(key);
148            }
149        }
150    }
151
152    /// 查找适合给定列的最佳索引(用于查询优化)
153    pub fn find_best_index(&self, table: &str, filter_columns: &[&str]) -> Option<(&IndexMeta, &BTreeIndex)> {
154        if let Some(keys) = self.table_indexes.get(table) {
155            for key in keys {
156                if let Some(meta) = self.index_meta.get(key) {
157                    if let Some(index) = self.indexes.get(key) {
158                        // 检查索引列是否匹配过滤列(前缀匹配)
159                        if meta.columns.len() >= filter_columns.len() {
160                            let matches = filter_columns.iter().enumerate().all(|(i, col)| {
161                                meta.columns.get(i).map(|s| s.as_str()) == Some(*col)
162                            });
163                            if matches {
164                                return Some((meta, index));
165                            }
166                        }
167                    }
168                }
169            }
170        }
171        None
172    }
173}
174
175impl Default for IndexManager {
176    fn default() -> Self {
177        Self::new()
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn test_create_index() {
187        let mut manager = IndexManager::new();
188
189        manager.create_index("users", &["email"]);
190
191        assert!(manager.has_index("users", "email"));
192        assert!(!manager.has_index("users", "name"));
193    }
194
195    #[test]
196    fn test_drop_index() {
197        let mut manager = IndexManager::new();
198
199        manager.create_index("users", &["email"]);
200        assert!(manager.has_index("users", "email"));
201
202        manager.drop_index("users", &["email"]);
203        assert!(!manager.has_index("users", "email"));
204    }
205
206    #[test]
207    fn test_drop_table_indexes() {
208        let mut manager = IndexManager::new();
209
210        manager.create_index("users", &["email"]);
211        manager.create_index("users", &["name"]);
212        manager.create_index("orders", &["user_id"]);
213
214        manager.drop_table_indexes("users");
215
216        assert!(!manager.has_index("users", "email"));
217        assert!(!manager.has_index("users", "name"));
218        assert!(manager.has_index("orders", "user_id"));
219    }
220
221    #[test]
222    fn test_get_table_indexes() {
223        let mut manager = IndexManager::new();
224
225        manager.create_index("users", &["email"]);
226        manager.create_index("users", &["name"]);
227
228        let indexes = manager.get_table_indexes("users");
229        assert_eq!(indexes.len(), 2);
230    }
231
232    #[test]
233    fn test_composite_index_creation() {
234        let mut manager = IndexManager::new();
235
236        manager.create_index("users", &["age", "city"]);
237
238        assert!(manager.has_composite_index("users", &["age", "city"]));
239        assert!(!manager.has_index("users", "age")); // 单列检查应该返回 false
240    }
241
242    #[test]
243    fn test_unique_index_creation() {
244        let mut manager = IndexManager::new();
245
246        manager.create_unique_index("orders", &["user_id", "product_id"]);
247
248        assert!(manager.has_composite_index("orders", &["user_id", "product_id"]));
249
250        let indexes = manager.get_table_indexes("orders");
251        assert_eq!(indexes.len(), 1);
252        assert!(indexes[0].is_unique);
253    }
254
255    #[test]
256    fn test_find_best_index() {
257        let mut manager = IndexManager::new();
258
259        // 创建复合索引 (age, city)
260        manager.create_index("users", &["age", "city"]);
261        // 创建单列索引 (email)
262        manager.create_index("users", &["email"]);
263
264        // 查找 age, city 的最佳索引
265        let result = manager.find_best_index("users", &["age", "city"]);
266        assert!(result.is_some());
267
268        // 查找 age 的最佳索引(前缀匹配)
269        let result = manager.find_best_index("users", &["age"]);
270        assert!(result.is_some());
271
272        // 查找 email 的最佳索引
273        let result = manager.find_best_index("users", &["email"]);
274        assert!(result.is_some());
275
276        // 查找不存在的索引
277        let result = manager.find_best_index("users", &["name"]);
278        assert!(result.is_none());
279    }
280
281    #[test]
282    fn test_get_composite_index() {
283        let mut manager = IndexManager::new();
284
285        manager.create_index("users", &["age", "city"]);
286
287        let index = manager.get_composite_index("users", &["age", "city"]);
288        assert!(index.is_some());
289
290        let index = manager.get_composite_index("users", &["age"]);
291        assert!(index.is_none()); // 复合索引不能用单列获取
292    }
293}