icydb_core/db/index/
store.rs1use crate::{
2 db::{
3 index::{
4 entry::{IndexEntry, IndexEntryCorruption, MAX_INDEX_ENTRY_KEYS, RawIndexEntry},
5 fingerprint,
6 key::{IndexId, IndexKey, RawIndexKey},
7 },
8 store::{DataKey, StoreRegistry},
9 },
10 prelude::{EntityKind, IndexModel, Value},
11};
12use canic_cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory};
13use derive_more::{Deref, DerefMut};
14use thiserror::Error as ThisError;
15
16#[derive(Deref, DerefMut)]
24pub struct IndexStoreRegistry(StoreRegistry<IndexStore>);
25
26impl IndexStoreRegistry {
27 #[must_use]
28 pub fn new() -> Self {
29 Self(StoreRegistry::new())
30 }
31}
32
33impl Default for IndexStoreRegistry {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub enum IndexInsertOutcome {
48 Inserted,
49 Skipped,
50}
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
59pub enum IndexRemoveOutcome {
60 Removed,
61 Skipped,
62}
63
64#[derive(Debug, ThisError)]
72pub enum IndexInsertError {
73 #[error("unique index violation")]
74 UniqueViolation,
75 #[error("index entry corrupted: {0}")]
76 CorruptedEntry(#[from] IndexEntryCorruption),
77 #[error("index entry exceeds max keys: {keys} (limit {MAX_INDEX_ENTRY_KEYS})")]
78 EntryTooLarge { keys: usize },
79}
80
81#[derive(Deref, DerefMut)]
89pub struct IndexStore(BTreeMap<RawIndexKey, RawIndexEntry, VirtualMemory<DefaultMemoryImpl>>);
90
91impl IndexStore {
92 #[must_use]
93 pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
94 Self(BTreeMap::init(memory))
95 }
96
97 pub fn insert_index_entry<E: EntityKind>(
98 &mut self,
99 entity: &E,
100 index: &IndexModel,
101 ) -> Result<IndexInsertOutcome, IndexInsertError> {
102 let Some(index_key) = IndexKey::new(entity, index) else {
103 return Ok(IndexInsertOutcome::Skipped);
104 };
105 let raw_key = index_key.to_raw();
106 let key = entity.key();
107
108 if let Some(raw_entry) = self.get(&raw_key) {
109 let mut entry = raw_entry.try_decode()?;
110 if index.unique {
111 if entry.len() > 1 {
112 return Err(IndexEntryCorruption::NonUniqueEntry { keys: entry.len() }.into());
113 }
114 if entry.contains(&key) {
115 return Ok(IndexInsertOutcome::Skipped);
116 }
117 if !entry.is_empty() {
118 return Err(IndexInsertError::UniqueViolation);
119 }
120 let entry = IndexEntry::new(key);
121 let raw_entry = RawIndexEntry::try_from_entry(&entry)
122 .map_err(|err| IndexInsertError::EntryTooLarge { keys: err.keys() })?;
123 self.insert(raw_key, raw_entry);
124 } else {
125 entry.insert_key(key);
126 let raw_entry = RawIndexEntry::try_from_entry(&entry)
127 .map_err(|err| IndexInsertError::EntryTooLarge { keys: err.keys() })?;
128 self.insert(raw_key, raw_entry);
129 }
130 } else {
131 let entry = IndexEntry::new(key);
132 let raw_entry = RawIndexEntry::try_from_entry(&entry)
133 .map_err(|err| IndexInsertError::EntryTooLarge { keys: err.keys() })?;
134 self.insert(raw_key, raw_entry);
135 }
136
137 Ok(IndexInsertOutcome::Inserted)
138 }
139
140 pub fn remove_index_entry<E: EntityKind>(
141 &mut self,
142 entity: &E,
143 index: &IndexModel,
144 ) -> Result<IndexRemoveOutcome, IndexEntryCorruption> {
145 let Some(index_key) = IndexKey::new(entity, index) else {
146 return Ok(IndexRemoveOutcome::Skipped);
147 };
148 let raw_key = index_key.to_raw();
149
150 if let Some(raw_entry) = self.get(&raw_key) {
151 let mut entry = raw_entry.try_decode()?;
152 entry.remove_key(&entity.key());
153 if entry.is_empty() {
154 self.remove(&raw_key);
155 } else {
156 let raw_entry = RawIndexEntry::try_from_entry(&entry)
157 .map_err(|err| IndexEntryCorruption::TooManyKeys { count: err.keys() })?;
158 self.insert(raw_key, raw_entry);
159 }
160 return Ok(IndexRemoveOutcome::Removed);
161 }
162
163 Ok(IndexRemoveOutcome::Skipped)
164 }
165
166 pub fn resolve_data_values<E: EntityKind>(
167 &self,
168 index: &IndexModel,
169 prefix: &[Value],
170 ) -> Result<Vec<DataKey>, &'static str> {
171 let mut out = Vec::new();
172 let index_id = IndexId::new::<E>(index);
173
174 let Some(fps) = prefix
175 .iter()
176 .map(fingerprint::to_index_fingerprint)
177 .collect::<Option<Vec<_>>>()
178 else {
179 return Ok(out);
180 };
181
182 let (start, end) = IndexKey::bounds_for_prefix(index_id, index.fields.len(), &fps);
183 let start_raw = start.to_raw();
184 let end_raw = end.to_raw();
185
186 for entry in self.range(start_raw..=end_raw) {
187 let _ = IndexKey::try_from_raw(entry.key())?;
188 let decoded = entry.value().try_decode().map_err(|err| err.message())?;
189 out.extend(decoded.iter_keys().map(|k| DataKey::new::<E>(k)));
190 }
191
192 Ok(out)
193 }
194
195 pub fn memory_bytes(&self) -> u64 {
197 self.iter()
198 .map(|entry| u64::from(IndexKey::STORED_SIZE) + entry.value().len() as u64)
199 .sum()
200 }
201}