1mod migration;
10mod projection;
11mod read;
12
13use std::collections::BTreeMap;
14use std::sync::Arc;
15
16use super::codec::{document_key, document_key_prefix, encode_stored_document_value, other_error};
17use super::{table_owners, KeyValueBatch, KeyValueRead, KeyValueStore};
18use crate::document_store::Document;
19use crate::read_control::StorageReadControl;
20use crate::{DocumentStore, StorageBackendResult, StoredDocument};
21use read::Documents;
22use uqa_core::memory::BudgetedVec;
23use uqa_core::{DocId, Value};
24
25#[derive(Clone)]
26enum Source {
27 Live(Arc<dyn KeyValueStore>),
28 Retained(Arc<dyn KeyValueRead + Send + Sync>),
29}
30
31#[derive(Clone)]
33pub struct KeyValueDocumentStore {
34 source: Source,
35 table: String,
36}
37
38impl KeyValueDocumentStore {
39 pub fn new(store: Arc<dyn KeyValueStore>, table: impl Into<String>) -> Self {
40 Self {
41 source: Source::Live(store),
42 table: table.into(),
43 }
44 }
45
46 fn read<T>(
47 &self,
48 query: impl FnOnce(Documents<'_>) -> StorageBackendResult<T>,
49 ) -> StorageBackendResult<T> {
50 let mut query = Some(query);
51 let mut result = None;
52 let mut visit = |read: &dyn KeyValueRead| {
53 let query = query
54 .take()
55 .ok_or_else(|| other_error("document read was evaluated twice"))?;
56 result = Some(query(Documents {
57 read,
58 table: &self.table,
59 })?);
60 Ok(())
61 };
62 match &self.source {
63 Source::Live(store) => store.with_read_view(&mut visit)?,
64 Source::Retained(read) => visit(&**read)?,
65 }
66 result.ok_or_else(|| other_error("document read was not evaluated"))
67 }
68
69 fn mutate<T>(
70 &self,
71 change: impl FnOnce(
72 Documents<'_>,
73 &mut dyn KeyValueBatch,
74 Option<table_owners::Owner>,
75 ) -> StorageBackendResult<T>,
76 ) -> StorageBackendResult<T> {
77 let Source::Live(store) = &self.source else {
78 return Err(other_error("document snapshot is read-only"));
79 };
80 let durable = store.identifier_allocator().is_some();
81 let mut change = Some(change);
82 let mut result = None;
83 store.with_mutation(&mut |read, batch| {
84 let change = change
85 .take()
86 .ok_or_else(|| other_error("document mutation was evaluated twice"))?;
87 let owner = if durable {
88 Some(table_owners::document_owner(read, batch, &self.table)?)
89 } else {
90 None
91 };
92 result = Some(change(
93 Documents {
94 read,
95 table: &self.table,
96 },
97 batch,
98 owner,
99 )?);
100 Ok(())
101 })?;
102 result.ok_or_else(|| other_error("document mutation was not evaluated"))
103 }
104}
105
106fn put_document(
107 batch: &mut dyn KeyValueBatch,
108 table: &str,
109 owner: Option<table_owners::Owner>,
110 id: DocId,
111 document: StoredDocument,
112) -> StorageBackendResult<()> {
113 let (mut fields, metadata) = document.into_parts();
114 fields.retain(|_, value| !matches!(value, Value::Null));
115 let bytes = encode_stored_document_value(&StoredDocument::with_metadata(fields, metadata))?;
116 if let Some(owner) = owner {
117 owner.observe(batch, id)?;
118 }
119 batch.put(&document_key(table, id)?, &bytes)
120}
121
122impl DocumentStore for KeyValueDocumentStore {
123 fn put(&mut self, id: DocId, document: Document) -> StorageBackendResult<()> {
124 self.mutate(|view, batch, owner| {
125 let metadata = view
126 .get(id)?
127 .map(|document| document.metadata())
128 .unwrap_or_default();
129 put_document(
130 batch,
131 view.table,
132 owner,
133 id,
134 StoredDocument::with_metadata(document, metadata),
135 )
136 })
137 }
138
139 fn put_stored(&mut self, id: DocId, document: StoredDocument) -> StorageBackendResult<()> {
140 self.mutate(|view, batch, owner| put_document(batch, view.table, owner, id, document))
141 }
142
143 fn get_stored(&self, id: DocId) -> StorageBackendResult<Option<StoredDocument>> {
144 self.read(|view| view.get(id))
145 }
146
147 fn get_stored_many_controlled(
148 &self,
149 ids: &[DocId],
150 control: &StorageReadControl,
151 ) -> StorageBackendResult<crate::RetainedDocumentPage> {
152 control.check()?;
153 if ids.is_empty() {
154 return Ok(BudgetedVec::new(control.memory()));
155 }
156 self.read(|view| view.retained_many_controlled(ids, control))
157 }
158
159 fn get_stored_many(
160 &self,
161 ids: &[DocId],
162 ) -> StorageBackendResult<BTreeMap<DocId, StoredDocument>> {
163 self.read(|view| view.many(ids))
164 }
165
166 fn get_many(&self, ids: &[DocId]) -> StorageBackendResult<BTreeMap<DocId, Document>> {
167 Ok(self
168 .get_stored_many(ids)?
169 .into_iter()
170 .map(|(id, document)| (id, document.into_fields()))
171 .collect())
172 }
173
174 fn get_fields_multi(
175 &self,
176 ids: &[DocId],
177 fields: &[&str],
178 ) -> StorageBackendResult<BTreeMap<DocId, Vec<Value>>> {
179 self.read(|view| view.project(ids, fields))
180 }
181
182 fn for_each_fields_multi_ref_with_presence(
183 &self,
184 ids: &[DocId],
185 fields: &[&str],
186 visitor: &mut dyn FnMut(DocId, bool, &[&Value]) -> bool,
187 ) -> StorageBackendResult<()> {
188 self.visit_projection(ids, fields, visitor)
189 }
190
191 fn for_each_fields_multi_ref(
192 &self,
193 ids: &[DocId],
194 fields: &[&str],
195 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
196 ) -> StorageBackendResult<()> {
197 self.visit_projection(ids, fields, &mut |id, _, values| visitor(id, values))
198 }
199
200 fn for_each_fields_multi(
201 &self,
202 ids: &[DocId],
203 fields: &[&str],
204 visitor: &mut dyn FnMut(DocId, Vec<Value>) -> bool,
205 ) -> StorageBackendResult<()> {
206 self.visit_projection(ids, fields, &mut |id, _, values| {
207 visitor(id, values.iter().map(|value| (*value).clone()).collect())
208 })
209 }
210
211 fn get_fields_bulk(
212 &self,
213 ids: &[DocId],
214 field: &str,
215 ) -> StorageBackendResult<BTreeMap<DocId, Value>> {
216 let projected = self.get_fields_multi(ids, &[field])?;
217 Ok(ids
218 .iter()
219 .map(|id| {
220 (
221 *id,
222 projected
223 .get(id)
224 .and_then(|row| row.first().cloned())
225 .unwrap_or(Value::Null),
226 )
227 })
228 .collect())
229 }
230
231 fn contains_doc_id(&self, id: DocId) -> StorageBackendResult<bool> {
232 self.read(|view| view.contains(id))
233 }
234
235 fn patch_fields(
236 &mut self,
237 id: DocId,
238 updates: &BTreeMap<String, Value>,
239 ) -> StorageBackendResult<bool> {
240 self.mutate(|view, batch, owner| {
241 let Some(mut document) = view.get(id)? else {
242 return Ok(false);
243 };
244 for (field, value) in updates {
245 if matches!(value, Value::Null) {
246 document.fields_mut().remove(field);
247 } else {
248 document.fields_mut().insert(field.clone(), value.clone());
249 }
250 }
251 put_document(batch, view.table, owner, id, document)?;
252 Ok(true)
253 })
254 }
255
256 fn delete(&mut self, id: DocId) -> StorageBackendResult<()> {
257 self.mutate(|view, batch, _| batch.delete(&document_key(view.table, id)?))
258 }
259
260 fn clear(&mut self) -> StorageBackendResult<()> {
261 self.mutate(|view, batch, owner| {
262 if let Some(owner) = owner {
263 owner.fence(batch)?;
264 }
265 batch.delete_prefix(&document_key_prefix(view.table)?)
266 })
267 }
268
269 fn doc_ids(&self) -> StorageBackendResult<Vec<DocId>> {
270 self.next_doc_ids(None, usize::MAX)
271 }
272
273 fn next_doc_id(&self, after: Option<DocId>) -> StorageBackendResult<Option<DocId>> {
274 Ok(self.next_doc_ids(after, 1)?.into_iter().next())
275 }
276
277 fn next_doc_ids(&self, after: Option<DocId>, limit: usize) -> StorageBackendResult<Vec<DocId>> {
278 self.read(|view| view.ids(after, limit))
279 }
280
281 fn next_doc_ids_controlled(
282 &self,
283 after: Option<DocId>,
284 limit: usize,
285 control: &StorageReadControl,
286 ) -> StorageBackendResult<BudgetedVec<DocId>> {
287 control.check()?;
288 if limit == 0 {
289 return Ok(BudgetedVec::new(control.memory()));
290 }
291 self.read(|view| view.id_page_controlled(after, limit, control))
292 }
293
294 fn for_each_next_fields(
295 &self,
296 after: Option<DocId>,
297 limit: usize,
298 fields: &[&str],
299 visitor: &mut dyn FnMut(DocId, &[&Value]) -> bool,
300 ) -> StorageBackendResult<Option<usize>> {
301 if !fields.is_empty() {
302 return Ok(None);
303 }
304 let (ids, control) =
305 self.read(|view| Ok((view.id_page(after, limit)?, view.read.control().clone())))?;
306 let mut visited = 0;
307 for id in ids.iter().copied() {
308 control.check()?;
309 visited += 1;
310 let keep_going = visitor(id, &[]);
311 control.check()?;
312 if !keep_going {
313 break;
314 }
315 }
316 control.check()?;
317 Ok(Some(visited))
318 }
319
320 fn len(&self) -> StorageBackendResult<usize> {
321 self.read(|view| view.count())
322 }
323
324 fn find_doc_id_by_field(
325 &self,
326 field: &str,
327 value: &Value,
328 ) -> StorageBackendResult<Option<DocId>> {
329 self.read(|view| view.find(|document| document.get(field) == Some(value)))
330 }
331
332 fn has_value(&self, field: &str, value: &Value) -> StorageBackendResult<bool> {
333 Ok(self.find_doc_id_by_field(field, value)?.is_some())
334 }
335
336 fn find_doc_id_by_fields(
337 &self,
338 fields: &[String],
339 values: &[Value],
340 ) -> StorageBackendResult<Option<DocId>> {
341 if fields.is_empty() || fields.len() != values.len() {
342 return Ok(None);
343 }
344 self.read(|view| {
345 view.find(|document| {
346 fields
347 .iter()
348 .zip(values)
349 .all(|(field, value)| document.get(field).unwrap_or(&Value::Null) == value)
350 })
351 })
352 }
353
354 fn iter_all(&self) -> StorageBackendResult<Box<dyn Iterator<Item = (DocId, Document)> + '_>> {
355 let rows = self.read(|view| view.all())?;
356 Ok(Box::new(rows.into_iter()))
357 }
358
359 fn snapshot(&self) -> StorageBackendResult<Arc<dyn DocumentStore>> {
360 let source = match &self.source {
361 Source::Live(_) => self.read(|view| {
362 Ok(Source::Retained(
363 view.read.retain(&[&document_key_prefix(view.table)?])?,
364 ))
365 })?,
366 Source::Retained(_) => self.source.clone(),
367 };
368 Ok(Arc::new(Self {
369 source,
370 table: self.table.clone(),
371 }))
372 }
373}