1use std::collections::HashMap;
2use crate::index::btree::BTreeIndex;
3
4#[derive(Debug, Clone)]
6pub struct IndexMeta {
7 pub table: String,
8 pub columns: Vec<String>, pub is_unique: bool, }
11
12#[derive(Debug)]
14pub struct IndexManager {
15 indexes: HashMap<String, BTreeIndex>,
17 index_meta: HashMap<String, IndexMeta>,
19 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 fn make_index_key(table: &str, columns: &[&str]) -> String {
34 format!("{}:{}", table, columns.join(","))
35 }
36
37 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 self.table_indexes
54 .entry(table.to_string())
55 .or_insert_with(Vec::new)
56 .push(key);
57 }
58 }
59
60 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 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 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 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 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 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 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 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 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 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 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 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")); }
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 manager.create_index("users", &["age", "city"]);
261 manager.create_index("users", &["email"]);
263
264 let result = manager.find_best_index("users", &["age", "city"]);
266 assert!(result.is_some());
267
268 let result = manager.find_best_index("users", &["age"]);
270 assert!(result.is_some());
271
272 let result = manager.find_best_index("users", &["email"]);
274 assert!(result.is_some());
275
276 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()); }
293}