1use std::collections::{BTreeMap, HashMap, HashSet};
9use std::sync::RwLock;
10
11use aegis_common::Value;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[derive(Default)]
20pub enum IndexType {
21 #[default]
23 BTree,
24 Hash,
26}
27
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub struct IndexKey {
36 pub values: Vec<IndexValue>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
41pub enum IndexValue {
42 Null,
43 Bool(bool),
44 Int(i64),
45 String(String),
46 Float(OrderedFloat),
48}
49
50#[derive(Debug, Clone, Copy)]
52pub struct OrderedFloat(pub f64);
53
54impl PartialEq for OrderedFloat {
55 fn eq(&self, other: &Self) -> bool {
56 self.0.to_bits() == other.0.to_bits()
57 }
58}
59
60impl Eq for OrderedFloat {}
61
62impl std::hash::Hash for OrderedFloat {
63 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
64 self.0.to_bits().hash(state);
65 }
66}
67
68impl PartialOrd for OrderedFloat {
69 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
70 Some(self.cmp(other))
71 }
72}
73
74impl Ord for OrderedFloat {
75 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
76 self.0.partial_cmp(&other.0).unwrap_or(std::cmp::Ordering::Equal)
77 }
78}
79
80impl IndexKey {
81 pub fn new(values: Vec<IndexValue>) -> Self {
82 Self { values }
83 }
84
85 pub fn single(value: IndexValue) -> Self {
86 Self { values: vec![value] }
87 }
88
89 pub fn from_value(value: &Value) -> IndexValue {
91 match value {
92 Value::Null => IndexValue::Null,
93 Value::Boolean(b) => IndexValue::Bool(*b),
94 Value::Integer(i) => IndexValue::Int(*i),
95 Value::Float(f) => IndexValue::Float(OrderedFloat(*f)),
96 Value::String(s) => IndexValue::String(s.clone()),
97 Value::Timestamp(t) => IndexValue::Int(t.timestamp()),
98 Value::Bytes(b) => IndexValue::String(format!("{:?}", b)),
99 Value::Array(arr) => IndexValue::String(format!("{:?}", arr)),
100 Value::Object(obj) => IndexValue::String(format!("{:?}", obj)),
101 }
102 }
103
104 pub fn from_values(values: &[Value]) -> Self {
106 Self {
107 values: values.iter().map(Self::from_value).collect(),
108 }
109 }
110}
111
112impl PartialOrd for IndexKey {
113 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
114 Some(self.cmp(other))
115 }
116}
117
118impl Ord for IndexKey {
119 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
120 self.values.cmp(&other.values)
121 }
122}
123
124pub type RowId = usize;
130
131pub struct BTreeIndex {
137 pub name: String,
139 pub table: String,
141 pub columns: Vec<String>,
143 pub unique: bool,
145 tree: RwLock<BTreeMap<IndexKey, HashSet<RowId>>>,
147 entry_count: RwLock<usize>,
149}
150
151impl BTreeIndex {
152 pub fn new(name: String, table: String, columns: Vec<String>, unique: bool) -> Self {
154 Self {
155 name,
156 table,
157 columns,
158 unique,
159 tree: RwLock::new(BTreeMap::new()),
160 entry_count: RwLock::new(0),
161 }
162 }
163
164 pub fn insert(&self, key: IndexKey, row_id: RowId) -> Result<(), IndexError> {
166 let mut tree = self.tree.write().expect("BTreeIndex tree lock poisoned");
167
168 if self.unique {
169 if let Some(existing) = tree.get(&key) {
170 if !existing.is_empty() {
171 return Err(IndexError::DuplicateKey(format!(
172 "Duplicate key in unique index '{}'",
173 self.name
174 )));
175 }
176 }
177 }
178
179 let entry = tree.entry(key).or_default();
180 if entry.insert(row_id) {
181 *self.entry_count.write().expect("BTreeIndex entry_count lock poisoned") += 1;
182 }
183 Ok(())
184 }
185
186 pub fn remove(&self, key: &IndexKey, row_id: RowId) -> bool {
188 let mut tree = self.tree.write().expect("BTreeIndex tree lock poisoned");
189 if let Some(row_ids) = tree.get_mut(key) {
190 if row_ids.remove(&row_id) {
191 *self.entry_count.write().expect("BTreeIndex entry_count lock poisoned") -= 1;
192 if row_ids.is_empty() {
193 tree.remove(key);
194 }
195 return true;
196 }
197 }
198 false
199 }
200
201 pub fn get(&self, key: &IndexKey) -> Vec<RowId> {
203 let tree = self.tree.read().expect("BTreeIndex tree lock poisoned");
204 tree.get(key)
205 .map(|ids| ids.iter().copied().collect())
206 .unwrap_or_default()
207 }
208
209 pub fn range(
211 &self,
212 start: Option<&IndexKey>,
213 end: Option<&IndexKey>,
214 start_inclusive: bool,
215 end_inclusive: bool,
216 ) -> Vec<RowId> {
217 let tree = self.tree.read().expect("BTreeIndex tree lock poisoned");
218 let mut result = Vec::new();
219
220 use std::ops::Bound;
221
222 let start_bound = match start {
223 Some(k) if start_inclusive => Bound::Included(k.clone()),
224 Some(k) => Bound::Excluded(k.clone()),
225 None => Bound::Unbounded,
226 };
227
228 let end_bound = match end {
229 Some(k) if end_inclusive => Bound::Included(k.clone()),
230 Some(k) => Bound::Excluded(k.clone()),
231 None => Bound::Unbounded,
232 };
233
234 for (_, row_ids) in tree.range((start_bound, end_bound)) {
235 result.extend(row_ids.iter().copied());
236 }
237
238 result
239 }
240
241 pub fn scan_all(&self) -> Vec<RowId> {
243 let tree = self.tree.read().expect("BTreeIndex tree lock poisoned");
244 tree.values().flat_map(|ids| ids.iter().copied()).collect()
245 }
246
247 pub fn len(&self) -> usize {
249 *self.entry_count.read().expect("BTreeIndex entry_count lock poisoned")
250 }
251
252 pub fn is_empty(&self) -> bool {
254 self.len() == 0
255 }
256
257 pub fn clear(&self) {
259 let mut tree = self.tree.write().expect("BTreeIndex tree lock poisoned");
260 tree.clear();
261 *self.entry_count.write().expect("BTreeIndex entry_count lock poisoned") = 0;
262 }
263}
264
265pub struct HashIndex {
271 pub name: String,
273 pub table: String,
275 pub columns: Vec<String>,
277 pub unique: bool,
279 map: RwLock<HashMap<IndexKey, HashSet<RowId>>>,
281 entry_count: RwLock<usize>,
283}
284
285impl HashIndex {
286 pub fn new(name: String, table: String, columns: Vec<String>, unique: bool) -> Self {
288 Self {
289 name,
290 table,
291 columns,
292 unique,
293 map: RwLock::new(HashMap::new()),
294 entry_count: RwLock::new(0),
295 }
296 }
297
298 pub fn insert(&self, key: IndexKey, row_id: RowId) -> Result<(), IndexError> {
300 let mut map = self.map.write().expect("HashIndex map lock poisoned");
301
302 if self.unique {
303 if let Some(existing) = map.get(&key) {
304 if !existing.is_empty() {
305 return Err(IndexError::DuplicateKey(format!(
306 "Duplicate key in unique index '{}'",
307 self.name
308 )));
309 }
310 }
311 }
312
313 let entry = map.entry(key).or_default();
314 if entry.insert(row_id) {
315 *self.entry_count.write().expect("HashIndex entry_count lock poisoned") += 1;
316 }
317 Ok(())
318 }
319
320 pub fn remove(&self, key: &IndexKey, row_id: RowId) -> bool {
322 let mut map = self.map.write().expect("HashIndex map lock poisoned");
323 if let Some(row_ids) = map.get_mut(key) {
324 if row_ids.remove(&row_id) {
325 *self.entry_count.write().expect("HashIndex entry_count lock poisoned") -= 1;
326 if row_ids.is_empty() {
327 map.remove(key);
328 }
329 return true;
330 }
331 }
332 false
333 }
334
335 pub fn get(&self, key: &IndexKey) -> Vec<RowId> {
337 let map = self.map.read().expect("HashIndex map lock poisoned");
338 map.get(key)
339 .map(|ids| ids.iter().copied().collect())
340 .unwrap_or_default()
341 }
342
343 pub fn len(&self) -> usize {
345 *self.entry_count.read().expect("HashIndex entry_count lock poisoned")
346 }
347
348 pub fn is_empty(&self) -> bool {
350 self.len() == 0
351 }
352
353 pub fn clear(&self) {
355 let mut map = self.map.write().expect("HashIndex map lock poisoned");
356 map.clear();
357 *self.entry_count.write().expect("HashIndex entry_count lock poisoned") = 0;
358 }
359}
360
361pub trait Index: Send + Sync {
367 fn name(&self) -> &str;
369
370 fn table(&self) -> &str;
372
373 fn columns(&self) -> &[String];
375
376 fn is_unique(&self) -> bool;
378
379 fn index_type(&self) -> IndexType;
381
382 fn insert(&self, key: IndexKey, row_id: RowId) -> Result<(), IndexError>;
384
385 fn remove(&self, key: &IndexKey, row_id: RowId) -> bool;
387
388 fn get(&self, key: &IndexKey) -> Vec<RowId>;
390
391 fn len(&self) -> usize;
393
394 fn is_empty(&self) -> bool;
396
397 fn clear(&self);
399}
400
401impl Index for BTreeIndex {
402 fn name(&self) -> &str { &self.name }
403 fn table(&self) -> &str { &self.table }
404 fn columns(&self) -> &[String] { &self.columns }
405 fn is_unique(&self) -> bool { self.unique }
406 fn index_type(&self) -> IndexType { IndexType::BTree }
407 fn insert(&self, key: IndexKey, row_id: RowId) -> Result<(), IndexError> { self.insert(key, row_id) }
408 fn remove(&self, key: &IndexKey, row_id: RowId) -> bool { self.remove(key, row_id) }
409 fn get(&self, key: &IndexKey) -> Vec<RowId> { self.get(key) }
410 fn len(&self) -> usize { self.len() }
411 fn is_empty(&self) -> bool { self.is_empty() }
412 fn clear(&self) { self.clear() }
413}
414
415impl Index for HashIndex {
416 fn name(&self) -> &str { &self.name }
417 fn table(&self) -> &str { &self.table }
418 fn columns(&self) -> &[String] { &self.columns }
419 fn is_unique(&self) -> bool { self.unique }
420 fn index_type(&self) -> IndexType { IndexType::Hash }
421 fn insert(&self, key: IndexKey, row_id: RowId) -> Result<(), IndexError> { self.insert(key, row_id) }
422 fn remove(&self, key: &IndexKey, row_id: RowId) -> bool { self.remove(key, row_id) }
423 fn get(&self, key: &IndexKey) -> Vec<RowId> { self.get(key) }
424 fn len(&self) -> usize { self.len() }
425 fn is_empty(&self) -> bool { self.is_empty() }
426 fn clear(&self) { self.clear() }
427}
428
429#[derive(Debug, Clone)]
435pub enum IndexError {
436 DuplicateKey(String),
437 IndexNotFound(String),
438 InvalidKey(String),
439}
440
441impl std::fmt::Display for IndexError {
442 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
443 match self {
444 IndexError::DuplicateKey(msg) => write!(f, "Duplicate key: {}", msg),
445 IndexError::IndexNotFound(msg) => write!(f, "Index not found: {}", msg),
446 IndexError::InvalidKey(msg) => write!(f, "Invalid key: {}", msg),
447 }
448 }
449}
450
451impl std::error::Error for IndexError {}
452
453pub struct TableIndexManager {
459 table: String,
461 btree_indexes: RwLock<HashMap<String, BTreeIndex>>,
463 hash_indexes: RwLock<HashMap<String, HashIndex>>,
465}
466
467impl TableIndexManager {
468 pub fn new(table: String) -> Self {
470 Self {
471 table,
472 btree_indexes: RwLock::new(HashMap::new()),
473 hash_indexes: RwLock::new(HashMap::new()),
474 }
475 }
476
477 pub fn create_index(
479 &self,
480 name: String,
481 columns: Vec<String>,
482 unique: bool,
483 index_type: IndexType,
484 ) -> Result<(), IndexError> {
485 match index_type {
486 IndexType::BTree => {
487 let mut indexes = self.btree_indexes.write().expect("TableIndexManager btree_indexes lock poisoned");
488 if indexes.contains_key(&name) {
489 return Err(IndexError::DuplicateKey(format!("Index '{}' already exists", name)));
490 }
491 indexes.insert(
492 name.clone(),
493 BTreeIndex::new(name, self.table.clone(), columns, unique),
494 );
495 }
496 IndexType::Hash => {
497 let mut indexes = self.hash_indexes.write().expect("TableIndexManager hash_indexes lock poisoned");
498 if indexes.contains_key(&name) {
499 return Err(IndexError::DuplicateKey(format!("Index '{}' already exists", name)));
500 }
501 indexes.insert(
502 name.clone(),
503 HashIndex::new(name, self.table.clone(), columns, unique),
504 );
505 }
506 }
507 Ok(())
508 }
509
510 pub fn drop_index(&self, name: &str) -> Result<(), IndexError> {
512 let mut btree = self.btree_indexes.write().expect("TableIndexManager btree_indexes lock poisoned");
513 if btree.remove(name).is_some() {
514 return Ok(());
515 }
516
517 let mut hash = self.hash_indexes.write().expect("TableIndexManager hash_indexes lock poisoned");
518 if hash.remove(name).is_some() {
519 return Ok(());
520 }
521
522 Err(IndexError::IndexNotFound(name.to_string()))
523 }
524
525 pub fn insert_row(
527 &self,
528 row_id: RowId,
529 column_values: &HashMap<String, Value>,
530 ) -> Result<(), IndexError> {
531 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
533 for index in btree.values() {
534 let key = self.build_key(&index.columns, column_values);
535 index.insert(key, row_id)?;
536 }
537
538 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
540 for index in hash.values() {
541 let key = self.build_key(&index.columns, column_values);
542 index.insert(key, row_id)?;
543 }
544
545 Ok(())
546 }
547
548 pub fn remove_row(&self, row_id: RowId, column_values: &HashMap<String, Value>) {
550 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
552 for index in btree.values() {
553 let key = self.build_key(&index.columns, column_values);
554 index.remove(&key, row_id);
555 }
556
557 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
559 for index in hash.values() {
560 let key = self.build_key(&index.columns, column_values);
561 index.remove(&key, row_id);
562 }
563 }
564
565 pub fn update_row(
567 &self,
568 row_id: RowId,
569 old_values: &HashMap<String, Value>,
570 new_values: &HashMap<String, Value>,
571 ) -> Result<(), IndexError> {
572 self.remove_row(row_id, old_values);
573 self.insert_row(row_id, new_values)
574 }
575
576 pub fn lookup_eq(&self, index_name: &str, key: &IndexKey) -> Option<Vec<RowId>> {
578 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
580 if let Some(index) = btree.get(index_name) {
581 return Some(index.get(key));
582 }
583
584 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
586 if let Some(index) = hash.get(index_name) {
587 return Some(index.get(key));
588 }
589
590 None
591 }
592
593 pub fn lookup_range(
595 &self,
596 index_name: &str,
597 start: Option<&IndexKey>,
598 end: Option<&IndexKey>,
599 start_inclusive: bool,
600 end_inclusive: bool,
601 ) -> Option<Vec<RowId>> {
602 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
603 btree.get(index_name).map(|index| {
604 index.range(start, end, start_inclusive, end_inclusive)
605 })
606 }
607
608 pub fn find_index_for_columns(&self, columns: &[String]) -> Option<(String, IndexType)> {
610 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
612 for (name, index) in hash.iter() {
613 if index.columns == columns {
614 return Some((name.clone(), IndexType::Hash));
615 }
616 }
617
618 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
620 for (name, index) in btree.iter() {
621 if columns.len() <= index.columns.len()
622 && index.columns[..columns.len()] == columns[..]
623 {
624 return Some((name.clone(), IndexType::BTree));
625 }
626 }
627
628 None
629 }
630
631 pub fn index_names(&self) -> Vec<String> {
633 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
634 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
635 btree.keys().chain(hash.keys()).cloned().collect()
636 }
637
638 pub fn get_index_info(&self, name: &str) -> Option<(Vec<String>, bool, IndexType)> {
640 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
641 if let Some(index) = btree.get(name) {
642 return Some((index.columns.clone(), index.unique, IndexType::BTree));
643 }
644
645 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
646 if let Some(index) = hash.get(name) {
647 return Some((index.columns.clone(), index.unique, IndexType::Hash));
648 }
649
650 None
651 }
652
653 pub fn insert_into_index(
655 &self,
656 index_name: &str,
657 key: IndexKey,
658 row_id: RowId,
659 ) -> Result<(), IndexError> {
660 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
662 if let Some(index) = btree.get(index_name) {
663 return index.insert(key, row_id);
664 }
665 drop(btree);
666
667 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
669 if let Some(index) = hash.get(index_name) {
670 return index.insert(key, row_id);
671 }
672
673 Err(IndexError::IndexNotFound(index_name.to_string()))
674 }
675
676 pub fn remove_from_index(
678 &self,
679 index_name: &str,
680 key: &IndexKey,
681 row_id: RowId,
682 ) -> Result<bool, IndexError> {
683 let btree = self.btree_indexes.read().expect("TableIndexManager btree_indexes lock poisoned");
685 if let Some(index) = btree.get(index_name) {
686 return Ok(index.remove(key, row_id));
687 }
688 drop(btree);
689
690 let hash = self.hash_indexes.read().expect("TableIndexManager hash_indexes lock poisoned");
692 if let Some(index) = hash.get(index_name) {
693 return Ok(index.remove(key, row_id));
694 }
695
696 Err(IndexError::IndexNotFound(index_name.to_string()))
697 }
698
699 fn build_key(&self, columns: &[String], values: &HashMap<String, Value>) -> IndexKey {
700 let key_values: Vec<IndexValue> = columns
701 .iter()
702 .map(|col| {
703 values
704 .get(col)
705 .map(IndexKey::from_value)
706 .unwrap_or(IndexValue::Null)
707 })
708 .collect();
709 IndexKey::new(key_values)
710 }
711}
712
713#[cfg(test)]
718mod tests {
719 use super::*;
720
721 #[test]
722 fn test_btree_index_basic() {
723 let index = BTreeIndex::new(
724 "idx_test".to_string(),
725 "users".to_string(),
726 vec!["id".to_string()],
727 false,
728 );
729
730 index.insert(IndexKey::single(IndexValue::Int(1)), 0).unwrap();
732 index.insert(IndexKey::single(IndexValue::Int(2)), 1).unwrap();
733 index.insert(IndexKey::single(IndexValue::Int(3)), 2).unwrap();
734
735 assert_eq!(index.get(&IndexKey::single(IndexValue::Int(2))), vec![1]);
737 assert_eq!(index.get(&IndexKey::single(IndexValue::Int(4))), Vec::<RowId>::new());
738 }
739
740 #[test]
741 fn test_btree_index_range() {
742 let index = BTreeIndex::new(
743 "idx_test".to_string(),
744 "users".to_string(),
745 vec!["age".to_string()],
746 false,
747 );
748
749 for i in 0..10 {
750 index.insert(IndexKey::single(IndexValue::Int(i * 10)), i as RowId).unwrap();
751 }
752
753 let result = index.range(
755 Some(&IndexKey::single(IndexValue::Int(20))),
756 Some(&IndexKey::single(IndexValue::Int(50))),
757 true,
758 true,
759 );
760 assert_eq!(result.len(), 4); let result = index.range(
764 Some(&IndexKey::single(IndexValue::Int(20))),
765 Some(&IndexKey::single(IndexValue::Int(50))),
766 false,
767 false,
768 );
769 assert_eq!(result.len(), 2); }
771
772 #[test]
773 fn test_btree_unique_constraint() {
774 let index = BTreeIndex::new(
775 "idx_unique".to_string(),
776 "users".to_string(),
777 vec!["email".to_string()],
778 true,
779 );
780
781 index.insert(IndexKey::single(IndexValue::String("a@b.com".to_string())), 0).unwrap();
782
783 let result = index.insert(IndexKey::single(IndexValue::String("a@b.com".to_string())), 1);
784 assert!(matches!(result, Err(IndexError::DuplicateKey(_))));
785 }
786
787 #[test]
788 fn test_hash_index_basic() {
789 let index = HashIndex::new(
790 "idx_hash".to_string(),
791 "users".to_string(),
792 vec!["status".to_string()],
793 false,
794 );
795
796 index.insert(IndexKey::single(IndexValue::String("active".to_string())), 0).unwrap();
797 index.insert(IndexKey::single(IndexValue::String("active".to_string())), 1).unwrap();
798 index.insert(IndexKey::single(IndexValue::String("inactive".to_string())), 2).unwrap();
799
800 let active = index.get(&IndexKey::single(IndexValue::String("active".to_string())));
801 assert_eq!(active.len(), 2);
802
803 let inactive = index.get(&IndexKey::single(IndexValue::String("inactive".to_string())));
804 assert_eq!(inactive.len(), 1);
805 }
806
807 #[test]
808 fn test_composite_key() {
809 let index = BTreeIndex::new(
810 "idx_composite".to_string(),
811 "orders".to_string(),
812 vec!["user_id".to_string(), "order_date".to_string()],
813 false,
814 );
815
816 let key1 = IndexKey::new(vec![
817 IndexValue::Int(1),
818 IndexValue::String("2024-01-01".to_string()),
819 ]);
820 let key2 = IndexKey::new(vec![
821 IndexValue::Int(1),
822 IndexValue::String("2024-01-02".to_string()),
823 ]);
824 let key3 = IndexKey::new(vec![
825 IndexValue::Int(2),
826 IndexValue::String("2024-01-01".to_string()),
827 ]);
828
829 index.insert(key1.clone(), 0).unwrap();
830 index.insert(key2.clone(), 1).unwrap();
831 index.insert(key3.clone(), 2).unwrap();
832
833 assert_eq!(index.get(&key1), vec![0]);
834 assert_eq!(index.get(&key2), vec![1]);
835 assert_eq!(index.len(), 3);
836 }
837
838 #[test]
839 fn test_table_index_manager() {
840 let manager = TableIndexManager::new("users".to_string());
841
842 manager.create_index(
844 "idx_id".to_string(),
845 vec!["id".to_string()],
846 true,
847 IndexType::BTree,
848 ).unwrap();
849
850 manager.create_index(
851 "idx_status".to_string(),
852 vec!["status".to_string()],
853 false,
854 IndexType::Hash,
855 ).unwrap();
856
857 let mut values = HashMap::new();
859 values.insert("id".to_string(), Value::Integer(1));
860 values.insert("status".to_string(), Value::String("active".to_string()));
861
862 manager.insert_row(0, &values).unwrap();
863
864 let key_id = IndexKey::single(IndexValue::Int(1));
866 let key_status = IndexKey::single(IndexValue::String("active".to_string()));
867
868 assert_eq!(manager.lookup_eq("idx_id", &key_id), Some(vec![0]));
869 assert_eq!(manager.lookup_eq("idx_status", &key_status), Some(vec![0]));
870 }
871
872 #[test]
873 fn test_find_index_for_columns() {
874 let manager = TableIndexManager::new("users".to_string());
875
876 manager.create_index(
877 "idx_name".to_string(),
878 vec!["name".to_string()],
879 false,
880 IndexType::Hash,
881 ).unwrap();
882
883 manager.create_index(
884 "idx_age_city".to_string(),
885 vec!["age".to_string(), "city".to_string()],
886 false,
887 IndexType::BTree,
888 ).unwrap();
889
890 let result = manager.find_index_for_columns(&["name".to_string()]);
892 assert_eq!(result, Some(("idx_name".to_string(), IndexType::Hash)));
893
894 let result = manager.find_index_for_columns(&["age".to_string()]);
896 assert_eq!(result, Some(("idx_age_city".to_string(), IndexType::BTree)));
897
898 let result = manager.find_index_for_columns(&["email".to_string()]);
900 assert_eq!(result, None);
901 }
902
903 #[test]
904 fn test_index_remove() {
905 let index = BTreeIndex::new(
906 "idx_test".to_string(),
907 "users".to_string(),
908 vec!["id".to_string()],
909 false,
910 );
911
912 let key = IndexKey::single(IndexValue::Int(1));
913 index.insert(key.clone(), 0).unwrap();
914 index.insert(key.clone(), 1).unwrap();
915
916 assert_eq!(index.get(&key).len(), 2);
917
918 index.remove(&key, 0);
919 assert_eq!(index.get(&key).len(), 1);
920
921 index.remove(&key, 1);
922 assert_eq!(index.get(&key).len(), 0);
923 }
924}