1use crate::error::{DbxError, DbxResult};
6use ahash::AHashMap;
7use dashmap::DashMap;
8use std::sync::RwLock;
9
10type ColumnIndex = DashMap<String, RwLock<AHashMap<Vec<u8>, Vec<usize>>>>;
12
13pub struct HashIndex {
18 indexes: DashMap<String, ColumnIndex>,
20}
21
22impl HashIndex {
23 pub fn new() -> Self {
25 Self {
26 indexes: DashMap::new(),
27 }
28 }
29
30 pub fn create_index(&self, table: &str, column: &str) -> DbxResult<()> {
45 let table_indexes = self.indexes.entry(table.to_string()).or_default();
46
47 if table_indexes.contains_key(column) {
48 return Err(DbxError::IndexAlreadyExists {
49 table: table.to_string(),
50 column: column.to_string(),
51 });
52 }
53
54 table_indexes.insert(column.to_string(), RwLock::new(AHashMap::new()));
55 Ok(())
56 }
57
58 pub fn drop_index(&self, table: &str, column: &str) -> DbxResult<()> {
65 if let Some(table_indexes) = self.indexes.get(table) {
66 if table_indexes.remove(column).is_none() {
67 return Err(DbxError::IndexNotFound {
68 table: table.to_string(),
69 column: column.to_string(),
70 });
71 }
72 Ok(())
73 } else {
74 Err(DbxError::IndexNotFound {
75 table: table.to_string(),
76 column: column.to_string(),
77 })
78 }
79 }
80
81 pub fn lookup(&self, table: &str, column: &str, value: &[u8]) -> DbxResult<Vec<usize>> {
93 if let Some(table_indexes) = self.indexes.get(table) {
94 if let Some(index) = table_indexes.get(column) {
95 let index_read = index.read().unwrap();
96 Ok(index_read.get(value).cloned().unwrap_or_default())
97 } else {
98 Err(DbxError::IndexNotFound {
99 table: table.to_string(),
100 column: column.to_string(),
101 })
102 }
103 } else {
104 Err(DbxError::IndexNotFound {
105 table: table.to_string(),
106 column: column.to_string(),
107 })
108 }
109 }
110
111 pub fn update_on_insert(
120 &self,
121 table: &str,
122 column: &str,
123 value: &[u8],
124 row_id: usize,
125 ) -> DbxResult<()> {
126 if let Some(table_indexes) = self.indexes.get(table)
127 && let Some(index) = table_indexes.get(column)
128 {
129 let mut index_write = index.write().unwrap();
130 index_write.entry(value.to_vec()).or_default().push(row_id);
131 }
132 Ok(())
133 }
134
135 pub fn update_on_delete(
144 &self,
145 table: &str,
146 column: &str,
147 value: &[u8],
148 row_id: usize,
149 ) -> DbxResult<()> {
150 if let Some(table_indexes) = self.indexes.get(table)
151 && let Some(index) = table_indexes.get(column)
152 {
153 let mut index_write = index.write().unwrap();
154 if let Some(row_ids) = index_write.get_mut(value) {
155 row_ids.retain(|&id| id != row_id);
156 if row_ids.is_empty() {
157 index_write.remove(value);
158 }
159 }
160 }
161 Ok(())
162 }
163
164 pub fn has_index(&self, table: &str, column: &str) -> bool {
166 self.indexes
167 .get(table)
168 .map(|t| t.contains_key(column))
169 .unwrap_or(false)
170 }
171}
172
173impl Default for HashIndex {
174 fn default() -> Self {
175 Self::new()
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_create_index() {
185 let index = HashIndex::new();
186 assert!(index.create_index("users", "id").is_ok());
187 assert!(index.has_index("users", "id"));
188 }
189
190 #[test]
191 fn test_create_duplicate_index() {
192 let index = HashIndex::new();
193 index.create_index("users", "id").unwrap();
194 assert!(index.create_index("users", "id").is_err());
195 }
196
197 #[test]
198 fn test_drop_index() {
199 let index = HashIndex::new();
200 index.create_index("users", "id").unwrap();
201 assert!(index.drop_index("users", "id").is_ok());
202 assert!(!index.has_index("users", "id"));
203 }
204
205 #[test]
206 fn test_drop_nonexistent_index() {
207 let index = HashIndex::new();
208 assert!(index.drop_index("users", "id").is_err());
209 }
210
211 #[test]
212 fn test_insert_and_lookup() {
213 let index = HashIndex::new();
214 index.create_index("users", "id").unwrap();
215
216 let value = b"user:123";
217 index.update_on_insert("users", "id", value, 0).unwrap();
218 index.update_on_insert("users", "id", value, 1).unwrap();
219
220 let result = index.lookup("users", "id", value).unwrap();
221 assert_eq!(result, vec![0, 1]);
222 }
223
224 #[test]
225 fn test_delete_and_lookup() {
226 let index = HashIndex::new();
227 index.create_index("users", "id").unwrap();
228
229 let value = b"user:123";
230 index.update_on_insert("users", "id", value, 0).unwrap();
231 index.update_on_insert("users", "id", value, 1).unwrap();
232
233 index.update_on_delete("users", "id", value, 0).unwrap();
234
235 let result = index.lookup("users", "id", value).unwrap();
236 assert_eq!(result, vec![1]);
237 }
238
239 #[test]
240 fn test_lookup_nonexistent() {
241 let index = HashIndex::new();
242 index.create_index("users", "id").unwrap();
243
244 let result = index.lookup("users", "id", b"nonexistent").unwrap();
245 assert!(result.is_empty());
246 }
247}