1use std::collections::BTreeMap;
14use std::sync::Arc;
15
16use uqa_core::{memory::BudgetedVec, DocId, FieldName, PathSegment, Value};
17
18use crate::backend::{StorageBackendError, StorageBackendResult};
19use crate::read_control::StorageReadControl;
20
21mod controlled_ids;
22pub use controlled_ids::read_document_ids;
23mod controlled_field;
24pub use controlled_field::read_selected_field;
25mod controlled_rows;
26pub use controlled_rows::{read_stored_documents, RetainedDocumentPage};
27mod controlled_presence;
28pub use controlled_presence::read_field_presence;
29pub mod decoding;
30pub mod identifiers;
31mod retained;
32pub use retained::{RetainedDocumentFields, RetainedStoredDocument};
33mod retained_store;
34pub use retained_store::{RetainedDocumentStore, RetainedDocumentStoreBuilder};
35
36pub type Document = BTreeMap<FieldName, Value>;
38
39#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
41pub struct DocumentMetadata {
42 tuple_xmin: Option<u32>,
43}
44
45impl DocumentMetadata {
46 #[must_use]
47 pub const fn with_tuple_xmin(tuple_xmin: u32) -> Self {
48 Self {
49 tuple_xmin: Some(tuple_xmin),
50 }
51 }
52
53 #[must_use]
54 pub const fn tuple_xmin(self) -> Option<u32> {
55 self.tuple_xmin
56 }
57}
58
59#[derive(Debug, Clone, Default, PartialEq)]
61pub struct StoredDocument {
62 fields: Document,
63 metadata: DocumentMetadata,
64}
65
66impl StoredDocument {
67 #[must_use]
68 pub fn new(fields: Document) -> Self {
69 Self {
70 fields,
71 metadata: DocumentMetadata::default(),
72 }
73 }
74
75 #[must_use]
76 pub fn with_metadata(fields: Document, metadata: DocumentMetadata) -> Self {
77 Self { fields, metadata }
78 }
79
80 #[must_use]
81 pub fn fields(&self) -> &Document {
82 &self.fields
83 }
84
85 #[must_use]
86 pub fn fields_mut(&mut self) -> &mut Document {
87 &mut self.fields
88 }
89
90 #[must_use]
91 pub fn metadata(&self) -> DocumentMetadata {
92 self.metadata
93 }
94
95 #[must_use]
96 pub fn into_fields(self) -> Document {
97 self.fields
98 }
99
100 #[must_use]
101 pub fn into_parts(self) -> (Document, DocumentMetadata) {
102 (self.fields, self.metadata)
103 }
104}
105
106const MISSING_SHARED_SLOT: usize = usize::MAX;
107static SHARED_NULL_VALUE: Value = Value::Null;
108
109#[derive(Debug, Clone, PartialEq)]
116pub struct SharedDocumentRow {
117 values: Arc<Vec<Value>>,
118 projection: Arc<[usize]>,
119}
120
121impl SharedDocumentRow {
122 pub(crate) fn new(values: Arc<Vec<Value>>, projection: Arc<[usize]>) -> Self {
123 debug_assert!(projection
124 .iter()
125 .all(|slot| *slot == MISSING_SHARED_SLOT || *slot < values.len()));
126 Self { values, projection }
127 }
128
129 pub fn project<'a>(&'a self, output: &mut Vec<&'a Value>) {
131 output.clear();
132 output.extend(self.projection.iter().map(|slot| {
133 if *slot == MISSING_SHARED_SLOT {
134 &SHARED_NULL_VALUE
135 } else {
136 &self.values[*slot]
137 }
138 }));
139 }
140
141 pub fn with_projected<R>(&self, visitor: impl FnOnce(&[&Value]) -> R) -> R {
145 const INLINE_FIELDS: usize = 32;
146 if self.projection.len() <= INLINE_FIELDS {
147 let mut projected = [&SHARED_NULL_VALUE; INLINE_FIELDS];
148 for (output, slot) in projected.iter_mut().zip(self.projection.iter()) {
149 if *slot != MISSING_SHARED_SLOT {
150 *output = &self.values[*slot];
151 }
152 }
153 visitor(&projected[..self.projection.len()])
154 } else {
155 let projected = self
156 .projection
157 .iter()
158 .map(|slot| {
159 if *slot == MISSING_SHARED_SLOT {
160 &SHARED_NULL_VALUE
161 } else {
162 &self.values[*slot]
163 }
164 })
165 .collect::<Vec<_>>();
166 visitor(&projected)
167 }
168 }
169
170 pub fn indexed_values(&self) -> (&[Value], &[usize]) {
172 (&self.values, &self.projection)
173 }
174
175 pub fn into_parts(self) -> (Arc<Vec<Value>>, Arc<[usize]>) {
178 (self.values, self.projection)
179 }
180}
181
182pub trait DocumentStore: Send + Sync {
184 fn put_stored(&mut self, doc_id: DocId, document: StoredDocument) -> StorageBackendResult<()>;
186
187 fn put_stored_unused(
189 &mut self,
190 doc_id: DocId,
191 document: StoredDocument,
192 namespace: identifiers::DocumentIdNamespace,
193 ) -> StorageBackendResult<()> {
194 let _ = namespace;
195 self.put_stored(doc_id, document)
196 }
197
198 fn get_stored(&self, doc_id: DocId) -> StorageBackendResult<Option<StoredDocument>>;
200
201 fn get_stored_many_controlled(
203 &self,
204 doc_ids: &[DocId],
205 control: &StorageReadControl,
206 ) -> StorageBackendResult<RetainedDocumentPage> {
207 control.check()?;
208 if doc_ids.is_empty() {
209 return Ok(BudgetedVec::new(control.memory()));
210 }
211 Err(StorageBackendError::Other(
212 "controlled whole-document reads are not supported by this store".into(),
213 ))
214 }
215
216 fn field_presence_controlled(
218 &self,
219 doc_ids: &[DocId],
220 fields: &[&str],
221 control: &StorageReadControl,
222 ) -> StorageBackendResult<BudgetedVec<bool>> {
223 controlled_presence::from_controlled_rows(self, doc_ids, fields, control)
224 }
225
226 fn with_field_ref_controlled(
228 &self,
229 doc_id: DocId,
230 field: &str,
231 control: &StorageReadControl,
232 visitor: &mut dyn FnMut(Option<&Value>) -> StorageBackendResult<()>,
233 ) -> StorageBackendResult<()> {
234 controlled_field::visit_selected_field(self, doc_id, field, control, visitor)
235 }
236
237 fn put(&mut self, doc_id: DocId, document: Document) -> StorageBackendResult<()> {
239 let metadata = self.get_metadata(doc_id)?.unwrap_or_default();
240 self.put_stored(doc_id, StoredDocument::with_metadata(document, metadata))
241 }
242
243 fn get(&self, doc_id: DocId) -> StorageBackendResult<Option<Document>> {
244 self.get_stored(doc_id)
245 .map(|document| document.map(StoredDocument::into_fields))
246 }
247
248 fn get_stored_many(
250 &self,
251 doc_ids: &[DocId],
252 ) -> StorageBackendResult<BTreeMap<DocId, StoredDocument>> {
253 let mut out = BTreeMap::new();
254 for doc_id in doc_ids {
255 if let Some(document) = self.get_stored(*doc_id)? {
256 out.insert(*doc_id, document);
257 }
258 }
259 Ok(out)
260 }
261
262 fn get_metadata(&self, doc_id: DocId) -> StorageBackendResult<Option<DocumentMetadata>> {
264 self.get_stored(doc_id)
265 .map(|document| document.map(|document| document.metadata()))
266 }
267 fn contains_doc_id(&self, doc_id: DocId) -> StorageBackendResult<bool> {
268 Ok(self.get(doc_id)?.is_some())
269 }
270 fn delete(&mut self, doc_id: DocId) -> StorageBackendResult<()>;
271 fn clear(&mut self) -> StorageBackendResult<()>;
272
273 fn get_field(&self, doc_id: DocId, field: &str) -> StorageBackendResult<Option<Value>> {
277 Ok(self
278 .get(doc_id)?
279 .and_then(|document| document.get(field).cloned()))
280 }
281
282 fn find_doc_id_by_field(
286 &self,
287 field: &str,
288 value: &Value,
289 ) -> StorageBackendResult<Option<DocId>> {
290 for doc_id in self.doc_ids()? {
291 if self.get_field(doc_id, field)?.as_ref() == Some(value) {
292 return Ok(Some(doc_id));
293 }
294 }
295 Ok(None)
296 }
297
298 fn patch_fields(
303 &mut self,
304 doc_id: DocId,
305 updates: &BTreeMap<String, Value>,
306 ) -> StorageBackendResult<bool> {
307 let Some(mut document) = self.get_stored(doc_id)? else {
308 return Ok(false);
309 };
310 for (field, value) in updates {
311 if matches!(value, Value::Null) {
312 document.fields_mut().remove(field);
313 } else {
314 document.fields_mut().insert(field.clone(), value.clone());
315 }
316 }
317 self.put_stored(doc_id, document)?;
318 Ok(true)
319 }
320
321 fn get_many(&self, doc_ids: &[DocId]) -> StorageBackendResult<BTreeMap<DocId, Document>> {
326 let mut out = BTreeMap::new();
327 for doc_id in doc_ids {
328 if let Some(document) = self.get(*doc_id)? {
329 out.insert(*doc_id, document);
330 }
331 }
332 Ok(out)
333 }
334
335 fn get_fields_multi(
341 &self,
342 doc_ids: &[DocId],
343 fields: &[&str],
344 ) -> StorageBackendResult<BTreeMap<DocId, Vec<Value>>> {
345 let mut out = BTreeMap::new();
346 for doc_id in doc_ids {
347 let Some(document) = self.get(*doc_id)? else {
348 continue;
349 };
350 let values = fields
351 .iter()
352 .map(|field| document.get(*field).cloned().unwrap_or(Value::Null))
353 .collect();
354 out.insert(*doc_id, values);
355 }
356 Ok(out)
357 }
358
359 fn for_each_fields_multi(
365 &self,
366 doc_ids: &[DocId],
367 fields: &[&str],
368 visitor: &mut dyn FnMut(DocId, Vec<Value>) -> bool,
369 ) -> StorageBackendResult<()> {
370 let mut projected = self.get_fields_multi(doc_ids, fields)?;
371 for doc_id in doc_ids {
372 let values = projected
373 .remove(doc_id)
374 .unwrap_or_else(|| vec![Value::Null; fields.len()]);
375 if !visitor(*doc_id, values) {
376 break;
377 }
378 }
379 Ok(())
380 }
381
382 fn for_each_fields_multi_ref(
387 &self,
388 doc_ids: &[DocId],
389 fields: &[&str],
390 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
391 ) -> StorageBackendResult<()> {
392 self.for_each_fields_multi(doc_ids, fields, &mut |doc_id, values| {
393 let references: Vec<&Value> = values.iter().collect();
394 visitor(doc_id, &references)
395 })
396 }
397
398 fn for_each_fields_multi_ref_with_presence(
403 &self,
404 doc_ids: &[DocId],
405 fields: &[&str],
406 visitor: &mut dyn FnMut(DocId, bool, &[&Value]) -> bool,
407 ) -> StorageBackendResult<()> {
408 if fields.is_empty() {
409 for doc_id in doc_ids {
410 if !visitor(*doc_id, self.contains_doc_id(*doc_id)?, &[]) {
411 break;
412 }
413 }
414 return Ok(());
415 }
416
417 let projected = self.get_fields_multi(doc_ids, fields)?;
418 let null = Value::Null;
419 let missing = vec![&null; fields.len()];
420 for doc_id in doc_ids {
421 let Some(values) = projected.get(doc_id) else {
422 if !visitor(*doc_id, false, &missing) {
423 break;
424 }
425 continue;
426 };
427 let references = values.iter().collect::<Vec<_>>();
428 if !visitor(*doc_id, true, &references) {
429 break;
430 }
431 }
432 Ok(())
433 }
434
435 fn get_shared_fields(
440 &self,
441 _doc_ids: &[DocId],
442 _fields: &[&str],
443 ) -> StorageBackendResult<Option<Vec<Option<SharedDocumentRow>>>> {
444 Ok(None)
445 }
446
447 fn get_fields_bulk(
451 &self,
452 doc_ids: &[DocId],
453 field: &str,
454 ) -> StorageBackendResult<BTreeMap<DocId, Value>> {
455 let mut out = BTreeMap::new();
456 for doc_id in doc_ids {
457 out.insert(
458 *doc_id,
459 self.get_field(*doc_id, field)?.unwrap_or(Value::Null),
460 );
461 }
462 Ok(out)
463 }
464
465 fn has_value(&self, field: &str, value: &Value) -> StorageBackendResult<bool> {
467 for doc_id in self.doc_ids()? {
468 if self.get_field(doc_id, field)?.as_ref() == Some(value) {
469 return Ok(true);
470 }
471 }
472 Ok(false)
473 }
474
475 fn find_doc_id_by_fields(
478 &self,
479 fields: &[String],
480 values: &[Value],
481 ) -> StorageBackendResult<Option<DocId>> {
482 if fields.is_empty() || fields.len() != values.len() {
483 return Ok(None);
484 }
485 for doc_id in self.doc_ids()? {
486 let mut matches = true;
487 for (field, value) in fields.iter().zip(values) {
488 if self.get_field(doc_id, field)?.unwrap_or(Value::Null) != *value {
489 matches = false;
490 break;
491 }
492 }
493 if matches {
494 return Ok(Some(doc_id));
495 }
496 }
497 Ok(None)
498 }
499
500 fn eval_path(
502 &self,
503 doc_id: DocId,
504 path: &[PathSegment],
505 ) -> StorageBackendResult<Option<Value>> {
506 let Some(document) = self.get(doc_id)? else {
507 return Ok(None);
508 };
509 Ok(eval_path_in_document(&document, path))
510 }
511
512 fn doc_ids(&self) -> StorageBackendResult<Vec<DocId>>;
513
514 fn next_doc_id(&self, after: Option<DocId>) -> StorageBackendResult<Option<DocId>> {
519 Ok(self
520 .doc_ids()?
521 .into_iter()
522 .filter(|doc_id| after.is_none_or(|after| *doc_id > after))
523 .min())
524 }
525
526 fn next_doc_ids(&self, after: Option<DocId>, limit: usize) -> StorageBackendResult<Vec<DocId>> {
530 if limit == 0 {
531 return Ok(Vec::new());
532 }
533 let mut doc_ids = self.doc_ids()?;
534 doc_ids.sort_unstable();
535 Ok(doc_ids
536 .into_iter()
537 .filter(|doc_id| after.is_none_or(|after| *doc_id > after))
538 .take(limit)
539 .collect())
540 }
541
542 fn next_doc_ids_controlled(
544 &self,
545 _after: Option<DocId>,
546 limit: usize,
547 control: &StorageReadControl,
548 ) -> StorageBackendResult<BudgetedVec<DocId>> {
549 control.check()?;
550 if limit == 0 {
551 return Ok(BudgetedVec::new(control.memory()));
552 }
553 Err(StorageBackendError::Other(
554 "controlled document identity reads are not supported".into(),
555 ))
556 }
557
558 fn next_shared_fields(
562 &self,
563 _after: Option<DocId>,
564 _limit: usize,
565 _fields: &[&str],
566 ) -> StorageBackendResult<Option<Vec<(DocId, SharedDocumentRow)>>> {
567 Ok(None)
568 }
569
570 fn for_each_next_fields(
572 &self,
573 _after: Option<DocId>,
574 _limit: usize,
575 _fields: &[&str],
576 _visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
577 ) -> StorageBackendResult<Option<usize>> {
578 Ok(None)
579 }
580
581 fn for_each_next_fields_borrowed(
583 &self,
584 after: Option<DocId>,
585 limit: usize,
586 fields: &[&str],
587 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
588 ) -> StorageBackendResult<Option<usize>> {
589 self.for_each_next_fields(after, limit, fields, visitor)
590 }
591
592 fn for_each_fields_multi_borrowed(
594 &self,
595 _ids: &[DocId],
596 _fields: &[&str],
597 _visitor: &mut dyn FnMut(DocId, bool, &[&Value]) -> bool,
598 ) -> StorageBackendResult<Option<usize>> {
599 Ok(None)
600 }
601
602 fn max_doc_id(&self) -> StorageBackendResult<DocId> {
603 Ok(self.doc_ids()?.into_iter().max().unwrap_or(0))
604 }
605
606 fn len(&self) -> StorageBackendResult<usize>;
607
608 fn is_empty(&self) -> StorageBackendResult<bool> {
609 Ok(self.len()? == 0)
610 }
611
612 fn iter_all(&self) -> StorageBackendResult<Box<dyn Iterator<Item = (DocId, Document)> + '_>> {
616 let mut ids = self.doc_ids()?;
617 ids.sort_unstable();
618 let snapshot = self.snapshot()?;
619 let mut rows = Vec::with_capacity(ids.len());
620 for doc_id in ids {
621 if let Some(document) = snapshot.get(doc_id)? {
622 rows.push((doc_id, document));
623 }
624 }
625 Ok(Box::new(rows.into_iter()))
626 }
627
628 fn snapshot(&self) -> StorageBackendResult<Arc<dyn DocumentStore>>;
632
633 fn retained_snapshot(&self) -> StorageBackendResult<Option<Arc<dyn DocumentStore>>> {
635 Ok(None)
636 }
637
638 fn writable_snapshot(&self) -> StorageBackendResult<Box<dyn DocumentStore>> {
642 Err(StorageBackendError::Other(
643 "writable document-store snapshots are not supported by this backend".into(),
644 ))
645 }
646}
647
648pub fn eval_path_in_document(doc: &Document, path: &[PathSegment]) -> Option<Value> {
652 let mut current: Value = match path.first()? {
653 PathSegment::Key(k) => doc.get(k)?.clone(),
654 PathSegment::Index(_) => return None,
655 };
656 for seg in path.iter().skip(1) {
657 current = match (current, seg) {
658 (Value::Map(m), PathSegment::Key(k)) => m.get(k)?.clone(),
659 (Value::List(items), PathSegment::Index(i)) => items.get(*i)?.clone(),
660 (Value::List(items), PathSegment::Key(k)) => {
661 let collected: Vec<Value> = items
662 .into_iter()
663 .filter_map(|v| match v {
664 Value::Map(m) => m.get(k).cloned(),
665 _ => None,
666 })
667 .collect();
668 Value::List(collected)
669 }
670 _ => return None,
671 };
672 }
673 Some(current)
674}
675
676mod memory;
677
678pub use memory::MemoryDocumentStore;