1use std::collections::BTreeMap;
10use std::sync::Arc;
11
12use uqa_core::{memory::BudgetedVec, DocId, Value};
13
14use crate::backend::StorageBackendResult;
15use crate::read_control::StorageReadControl;
16
17use super::{Document, DocumentMetadata, DocumentStore, SharedDocumentRow, StoredDocument};
18
19mod projection;
20
21#[derive(Debug, Default)]
22pub struct MemoryDocumentStore {
23 state: Arc<MemoryDocumentState>,
25}
26
27impl Clone for MemoryDocumentStore {
29 fn clone(&self) -> Self {
30 Self {
31 state: Arc::new((*self.state).clone()),
32 }
33 }
34}
35
36#[derive(Debug, Default, Clone)]
37struct MemoryDocumentState {
38 documents: BTreeMap<DocId, MemoryDocumentRow>,
39 layouts: Vec<Vec<String>>,
40}
41
42#[derive(Debug, Clone)]
43pub(super) struct MemoryDocumentRow {
44 layout_id: usize,
45 values: Arc<Vec<Value>>,
46 metadata: DocumentMetadata,
47}
48
49impl MemoryDocumentStore {
50 pub fn new() -> Self {
51 Self::default()
52 }
53
54 fn shared_snapshot(&self) -> Self {
55 Self {
56 state: Arc::clone(&self.state),
57 }
58 }
59
60 pub fn iter(&self) -> impl Iterator<Item = (DocId, Document)> + '_ {
61 self.state
62 .documents
63 .iter()
64 .map(|(doc_id, stored)| (*doc_id, self.materialize_document(stored)))
65 }
66
67 fn materialize_document(&self, stored: &MemoryDocumentRow) -> Document {
68 self.state.layouts[stored.layout_id]
69 .iter()
70 .cloned()
71 .zip(stored.values.iter().cloned())
72 .collect()
73 }
74
75 fn materialize_stored_document(&self, stored: &MemoryDocumentRow) -> StoredDocument {
76 StoredDocument::with_metadata(self.materialize_document(stored), stored.metadata)
77 }
78
79 fn field<'a>(&'a self, stored: &'a MemoryDocumentRow, field: &str) -> Option<&'a Value> {
80 let slot = self.state.layouts[stored.layout_id]
81 .binary_search_by(|stored| stored.as_str().cmp(field))
82 .ok()?;
83 stored.values.get(slot)
84 }
85
86 fn put_stored_inner(&mut self, doc_id: DocId, document: StoredDocument) {
87 let state = Arc::make_mut(&mut self.state);
88 let (document, metadata) = document.into_parts();
89 let (layout_id, values) =
90 if let Some(layout_id) = document_layout_id(&state.layouts, &document) {
91 (layout_id, document.into_values().collect())
92 } else {
93 let (layout, values): (Vec<_>, Vec<_>) = document.into_iter().unzip();
94 let layout_id = state.layouts.len();
95 state.layouts.push(layout);
96 (layout_id, values)
97 };
98 state.documents.insert(
99 doc_id,
100 MemoryDocumentRow {
101 layout_id,
102 values: Arc::new(values),
103 metadata,
104 },
105 );
106 }
107}
108
109fn document_layout_id(layouts: &[Vec<String>], document: &Document) -> Option<usize> {
110 layouts.iter().position(|layout| {
111 layout.len() == document.len()
112 && layout
113 .iter()
114 .map(String::as_str)
115 .eq(document.keys().map(String::as_str))
116 })
117}
118
119impl DocumentStore for MemoryDocumentStore {
120 fn put(&mut self, doc_id: DocId, document: Document) -> StorageBackendResult<()> {
121 let metadata = self
122 .state
123 .documents
124 .get(&doc_id)
125 .map_or_else(DocumentMetadata::default, |stored| stored.metadata);
126 self.put_stored_inner(doc_id, StoredDocument::with_metadata(document, metadata));
127 Ok(())
128 }
129
130 fn get(&self, doc_id: DocId) -> StorageBackendResult<Option<Document>> {
131 Ok(self
132 .state
133 .documents
134 .get(&doc_id)
135 .map(|stored| self.materialize_document(stored)))
136 }
137
138 fn put_stored(&mut self, doc_id: DocId, document: StoredDocument) -> StorageBackendResult<()> {
139 self.put_stored_inner(doc_id, document);
140 Ok(())
141 }
142
143 fn get_stored(&self, doc_id: DocId) -> StorageBackendResult<Option<StoredDocument>> {
144 Ok(self
145 .state
146 .documents
147 .get(&doc_id)
148 .map(|stored| self.materialize_stored_document(stored)))
149 }
150
151 fn get_stored_many_controlled(
152 &self,
153 ids: &[DocId],
154 control: &StorageReadControl,
155 ) -> StorageBackendResult<super::RetainedDocumentPage> {
156 control.check()?;
157 let mut page = BudgetedVec::new(control.memory());
158 page.reserve(ids.len())?;
159 for id in ids {
160 control.check()?;
161 let row = self
162 .state
163 .documents
164 .get(id)
165 .map(|row| -> StorageBackendResult<_> {
166 let fields = super::controlled_rows::copy_fields(
167 self.state.layouts[row.layout_id]
168 .iter()
169 .map(String::as_str)
170 .zip(row.values.iter()),
171 control,
172 )?;
173 Ok(super::RetainedStoredDocument::with_metadata(
174 fields,
175 row.metadata,
176 ))
177 })
178 .transpose()?;
179 page.push(row)?;
180 }
181 control.check()?;
182 Ok(page)
183 }
184
185 fn get_stored_many(
186 &self,
187 doc_ids: &[DocId],
188 ) -> StorageBackendResult<BTreeMap<DocId, StoredDocument>> {
189 Ok(doc_ids
190 .iter()
191 .filter_map(|doc_id| {
192 self.state
193 .documents
194 .get(doc_id)
195 .map(|stored| (*doc_id, self.materialize_stored_document(stored)))
196 })
197 .collect())
198 }
199
200 fn get_metadata(&self, doc_id: DocId) -> StorageBackendResult<Option<DocumentMetadata>> {
201 Ok(self
202 .state
203 .documents
204 .get(&doc_id)
205 .map(|stored| stored.metadata))
206 }
207
208 fn contains_doc_id(&self, doc_id: DocId) -> StorageBackendResult<bool> {
209 Ok(self.state.documents.contains_key(&doc_id))
210 }
211
212 fn get_field(&self, doc_id: DocId, field: &str) -> StorageBackendResult<Option<Value>> {
213 Ok(self
214 .state
215 .documents
216 .get(&doc_id)
217 .and_then(|stored| self.field(stored, field).cloned()))
218 }
219
220 fn get_fields_multi(
221 &self,
222 doc_ids: &[DocId],
223 fields: &[&str],
224 ) -> StorageBackendResult<BTreeMap<DocId, Vec<Value>>> {
225 Ok(doc_ids
226 .iter()
227 .filter_map(|doc_id| {
228 let stored = self.state.documents.get(doc_id)?;
229 let values = fields
230 .iter()
231 .map(|field| self.field(stored, field).cloned().unwrap_or(Value::Null))
232 .collect();
233 Some((*doc_id, values))
234 })
235 .collect())
236 }
237
238 fn for_each_fields_multi(
239 &self,
240 doc_ids: &[DocId],
241 fields: &[&str],
242 visitor: &mut dyn FnMut(DocId, Vec<Value>) -> bool,
243 ) -> StorageBackendResult<()> {
244 for doc_id in doc_ids {
245 let values = self.state.documents.get(doc_id).map_or_else(
246 || vec![Value::Null; fields.len()],
247 |stored| {
248 fields
249 .iter()
250 .map(|field| self.field(stored, field).cloned().unwrap_or(Value::Null))
251 .collect()
252 },
253 );
254 if !visitor(*doc_id, values) {
255 break;
256 }
257 }
258 Ok(())
259 }
260
261 fn for_each_fields_multi_ref(
262 &self,
263 doc_ids: &[DocId],
264 fields: &[&str],
265 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
266 ) -> StorageBackendResult<()> {
267 self.visit_fields_multi_ref_with_presence(doc_ids, fields, &mut |doc_id, _, values| {
268 visitor(doc_id, values)
269 });
270 Ok(())
271 }
272
273 fn for_each_fields_multi_ref_with_presence(
274 &self,
275 doc_ids: &[DocId],
276 fields: &[&str],
277 visitor: &mut dyn FnMut(DocId, bool, &[&Value]) -> bool,
278 ) -> StorageBackendResult<()> {
279 self.visit_fields_multi_ref_with_presence(doc_ids, fields, visitor);
280 Ok(())
281 }
282
283 fn for_each_fields_multi_borrowed(
284 &self,
285 ids: &[DocId],
286 fields: &[&str],
287 visitor: &mut dyn FnMut(DocId, bool, &[&Value]) -> bool,
288 ) -> StorageBackendResult<Option<usize>> {
289 let mut visited = 0;
290 self.visit_fields_multi_ref_with_presence(ids, fields, &mut |id, present, values| {
291 visited += 1;
292 visitor(id, present, values)
293 });
294 Ok(Some(visited))
295 }
296
297 fn with_field_ref_controlled(
298 &self,
299 id: DocId,
300 field: &str,
301 control: &StorageReadControl,
302 visitor: &mut dyn FnMut(Option<&Value>) -> StorageBackendResult<()>,
303 ) -> StorageBackendResult<()> {
304 control.check()?;
305 let value = self
306 .state
307 .documents
308 .get(&id)
309 .and_then(|row| self.field(row, field));
310 visitor(value)?;
311 control.check()
312 }
313
314 fn field_presence_controlled(
315 &self,
316 ids: &[DocId],
317 fields: &[&str],
318 control: &StorageReadControl,
319 ) -> StorageBackendResult<BudgetedVec<bool>> {
320 control.check()?;
321 let mut present = BudgetedVec::new(control.memory());
322 for id in ids {
323 let row = self.state.documents.get(id);
324 for field in fields {
325 control.check()?;
326 present.push(row.is_some_and(|row| self.field(row, field).is_some()))?;
327 }
328 }
329 control.check()?;
330 Ok(present)
331 }
332
333 fn get_shared_fields(
334 &self,
335 doc_ids: &[DocId],
336 fields: &[&str],
337 ) -> StorageBackendResult<Option<Vec<Option<SharedDocumentRow>>>> {
338 Ok(Some(self.shared_fields(doc_ids, fields)))
339 }
340
341 fn find_doc_id_by_field(
342 &self,
343 field: &str,
344 value: &Value,
345 ) -> StorageBackendResult<Option<DocId>> {
346 Ok(self.state.documents.iter().find_map(|(doc_id, stored)| {
347 (self.field(stored, field) == Some(value)).then_some(*doc_id)
348 }))
349 }
350
351 fn find_doc_id_by_fields(
352 &self,
353 fields: &[String],
354 values: &[Value],
355 ) -> StorageBackendResult<Option<DocId>> {
356 if fields.is_empty() || fields.len() != values.len() {
357 return Ok(None);
358 }
359 Ok(self.state.documents.iter().find_map(|(doc_id, stored)| {
360 fields
361 .iter()
362 .zip(values.iter())
363 .all(|(field, value)| self.field(stored, field).unwrap_or(&Value::Null) == value)
364 .then_some(*doc_id)
365 }))
366 }
367
368 fn patch_fields(
369 &mut self,
370 doc_id: DocId,
371 updates: &BTreeMap<String, Value>,
372 ) -> StorageBackendResult<bool> {
373 let Some(mut document) = self
374 .state
375 .documents
376 .get(&doc_id)
377 .map(|stored| self.materialize_stored_document(stored))
378 else {
379 return Ok(false);
380 };
381 for (field, value) in updates {
382 if matches!(value, Value::Null) {
383 document.fields_mut().remove(field);
384 } else {
385 document.fields_mut().insert(field.clone(), value.clone());
386 }
387 }
388 self.put_stored(doc_id, document)?;
389 Ok(true)
390 }
391
392 fn delete(&mut self, doc_id: DocId) -> StorageBackendResult<()> {
393 if self.state.documents.contains_key(&doc_id) {
394 Arc::make_mut(&mut self.state).documents.remove(&doc_id);
395 }
396 Ok(())
397 }
398
399 fn clear(&mut self) -> StorageBackendResult<()> {
400 if let Some(state) = Arc::get_mut(&mut self.state) {
401 *state = MemoryDocumentState::default();
402 } else {
403 self.state = Arc::default();
404 }
405 Ok(())
406 }
407
408 fn doc_ids(&self) -> StorageBackendResult<Vec<DocId>> {
409 Ok(self.state.documents.keys().copied().collect())
410 }
411
412 fn next_doc_id(&self, after: Option<DocId>) -> StorageBackendResult<Option<DocId>> {
413 use std::ops::Bound::{Excluded, Unbounded};
414
415 Ok(match after {
416 Some(after) => self
417 .state
418 .documents
419 .range((Excluded(after), Unbounded))
420 .next()
421 .map(|(doc_id, _)| *doc_id),
422 None => self.state.documents.keys().next().copied(),
423 })
424 }
425
426 fn next_doc_ids(&self, after: Option<DocId>, limit: usize) -> StorageBackendResult<Vec<DocId>> {
427 use std::ops::Bound::{Excluded, Unbounded};
428
429 if limit == 0 {
430 return Ok(Vec::new());
431 }
432 Ok(match after {
433 Some(after) => self
434 .state
435 .documents
436 .range((Excluded(after), Unbounded))
437 .take(limit)
438 .map(|(doc_id, _)| *doc_id)
439 .collect(),
440 None => self.state.documents.keys().take(limit).copied().collect(),
441 })
442 }
443
444 fn next_doc_ids_controlled(
445 &self,
446 after: Option<DocId>,
447 limit: usize,
448 control: &StorageReadControl,
449 ) -> StorageBackendResult<BudgetedVec<DocId>> {
450 use std::ops::Bound::{Excluded, Unbounded};
451
452 control.check()?;
453 let mut ids = BudgetedVec::new(control.memory());
454 let after = after.map_or(Unbounded, Excluded);
455 for (&id, _) in self.state.documents.range((after, Unbounded)).take(limit) {
456 control.check()?;
457 ids.push(id)?;
458 }
459 control.check()?;
460 Ok(ids)
461 }
462
463 fn next_shared_fields(
464 &self,
465 after: Option<DocId>,
466 limit: usize,
467 fields: &[&str],
468 ) -> StorageBackendResult<Option<Vec<(DocId, SharedDocumentRow)>>> {
469 Ok(Some(self.next_shared_rows(after, limit, fields)))
470 }
471
472 fn for_each_next_fields(
473 &self,
474 after: Option<DocId>,
475 limit: usize,
476 fields: &[&str],
477 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
478 ) -> StorageBackendResult<Option<usize>> {
479 Ok(Some(self.visit_next_rows(after, limit, fields, visitor)))
480 }
481
482 fn len(&self) -> StorageBackendResult<usize> {
483 Ok(self.state.documents.len())
484 }
485
486 fn snapshot(&self) -> StorageBackendResult<Arc<dyn DocumentStore>> {
487 Ok(Arc::new(self.shared_snapshot()))
488 }
489
490 fn writable_snapshot(&self) -> StorageBackendResult<Box<dyn DocumentStore>> {
491 Ok(Box::new(self.shared_snapshot()))
492 }
493}
494
495#[cfg(test)]
496mod tests;