Skip to main content

uqa_storage/key_value/
storage_backend.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Persistent-storage facade that assembles the key/value adapters.
8
9use super::{
10    btree_index, Analyzer, Arc, BTreeMap, DocId, DocumentStore, InvertedIndex, KeyValueCatalog,
11    KeyValueDocumentStore, KeyValueHNSWIndex, KeyValueIVFIndex, KeyValueInvertedIndex,
12    KeyValueStore, KeyValueVectorIndex, PersistentStorageBackend, PersistentStorageIdentity,
13    StorageBackendResult, Value, VectorIndex, VectorIndexOpenMode, VectorIndexSpec,
14};
15use crate::{CatalogFacade, PersistentStorageSession};
16
17/// Persistent storage factory implemented over [`KeyValueStore`].
18#[derive(Clone)]
19pub struct KeyValueStorageBackend {
20    store: Arc<dyn KeyValueStore>,
21}
22
23impl KeyValueStorageBackend {
24    pub fn new(store: Arc<dyn KeyValueStore>) -> Self {
25        Self { store }
26    }
27
28    pub fn store(&self) -> Arc<dyn KeyValueStore> {
29        Arc::clone(&self.store)
30    }
31}
32
33impl PersistentStorageBackend for KeyValueStorageBackend {
34    fn storage_identity(&self) -> StorageBackendResult<Option<PersistentStorageIdentity>> {
35        self.store.storage_identity()
36    }
37
38    fn open_session(&self) -> StorageBackendResult<PersistentStorageSession> {
39        let store = self.store.open_session()?;
40        let catalog: Arc<dyn CatalogFacade> = Arc::new(KeyValueCatalog::new(Arc::clone(&store)));
41        let backend: Arc<dyn PersistentStorageBackend> = Arc::new(Self::new(store));
42        Ok(PersistentStorageSession::new(catalog, backend))
43    }
44
45    fn document_store(&self, table: &str) -> Box<dyn DocumentStore> {
46        Box::new(KeyValueDocumentStore::new(Arc::clone(&self.store), table))
47    }
48
49    fn inverted_index(&self, table: &str, analyzer: Analyzer) -> Box<dyn InvertedIndex> {
50        Box::new(KeyValueInvertedIndex::new(
51            Arc::clone(&self.store),
52            table,
53            analyzer,
54        ))
55    }
56
57    fn migrate_inverted_index_storage(&self) -> StorageBackendResult<()> {
58        KeyValueInvertedIndex::migrate_legacy_storage(self.store.as_ref())
59    }
60
61    fn vector_index(
62        &self,
63        table: &str,
64        field: &str,
65        dimensions: u32,
66        spec: VectorIndexSpec,
67        mode: VectorIndexOpenMode,
68    ) -> StorageBackendResult<Box<dyn VectorIndex>> {
69        match spec {
70            VectorIndexSpec::BruteForce => Ok(Box::new(KeyValueVectorIndex::new(
71                Arc::clone(&self.store),
72                table,
73                field,
74                dimensions,
75            ))),
76            VectorIndexSpec::IVF(params) => match mode {
77                VectorIndexOpenMode::Create => Ok(Box::new(KeyValueIVFIndex::create(
78                    Arc::clone(&self.store),
79                    table,
80                    field,
81                    dimensions,
82                    params,
83                )?)),
84                VectorIndexOpenMode::Restore => Ok(Box::new(KeyValueIVFIndex::restore(
85                    Arc::clone(&self.store),
86                    table,
87                    field,
88                    dimensions,
89                    params,
90                )?)),
91            },
92            VectorIndexSpec::HNSW(params) => match mode {
93                VectorIndexOpenMode::Create => Ok(Box::new(KeyValueHNSWIndex::create(
94                    Arc::clone(&self.store),
95                    table,
96                    field,
97                    dimensions,
98                    params,
99                )?)),
100                VectorIndexOpenMode::Restore => Ok(Box::new(KeyValueHNSWIndex::restore(
101                    Arc::clone(&self.store),
102                    table,
103                    field,
104                    dimensions,
105                    params,
106                )?)),
107            },
108        }
109    }
110
111    fn drop_vector_index_metadata(&self, table: &str, field: &str) -> StorageBackendResult<()> {
112        KeyValueIVFIndex::drop_metadata(self.store.as_ref(), table, field)
113    }
114
115    fn persists_btree_indexes(&self) -> bool {
116        true
117    }
118
119    fn load_btree_index(
120        &self,
121        table: &str,
122        field: &str,
123    ) -> StorageBackendResult<Option<Vec<(DocId, Value)>>> {
124        btree_index::load(self.store.as_ref(), table, field)
125    }
126
127    fn btree_index_fields(&self, table: &str) -> StorageBackendResult<Vec<String>> {
128        btree_index::fields(self.store.as_ref(), table)
129    }
130
131    fn replace_btree_index(
132        &self,
133        table: &str,
134        field: &str,
135        values: &[(DocId, Value)],
136    ) -> StorageBackendResult<()> {
137        btree_index::replace(self.store.as_ref(), table, field, values)
138    }
139
140    fn replace_btree_indexes(
141        &self,
142        table: &str,
143        indexes: &[(&str, &[(DocId, Value)])],
144    ) -> StorageBackendResult<()> {
145        btree_index::replace_many(self.store.as_ref(), table, indexes)
146    }
147
148    fn apply_btree_index_write(
149        &self,
150        table: &str,
151        doc_id: DocId,
152        values: Option<&BTreeMap<String, Value>>,
153    ) -> StorageBackendResult<()> {
154        btree_index::apply_write(self.store.as_ref(), table, doc_id, values)
155    }
156
157    fn drop_btree_index(&self, table: &str, field: &str) -> StorageBackendResult<()> {
158        btree_index::drop_index(self.store.as_ref(), table, field)
159    }
160
161    fn clear_btree_indexes(&self, table: &str) -> StorageBackendResult<()> {
162        btree_index::clear_entries(self.store.as_ref(), table)
163    }
164
165    fn begin_transaction(&self) -> StorageBackendResult<()> {
166        self.store.begin_transaction()
167    }
168
169    fn begin_read_transaction(&self) -> StorageBackendResult<()> {
170        self.store.begin_read_transaction()
171    }
172
173    fn in_transaction(&self) -> bool {
174        self.store.in_transaction()
175    }
176
177    fn transaction_has_written(&self) -> StorageBackendResult<bool> {
178        self.store.transaction_has_written()
179    }
180
181    fn change_version(&self) -> StorageBackendResult<Option<u64>> {
182        self.store.change_version()
183    }
184
185    fn change_version_monitor_is_nonblocking(&self) -> StorageBackendResult<bool> {
186        self.store.change_version_monitor_is_nonblocking()
187    }
188
189    fn pin_transaction_snapshot(&self) -> StorageBackendResult<()> {
190        self.store.pin_transaction_snapshot()
191    }
192
193    fn commit_transaction(&self) -> StorageBackendResult<()> {
194        self.store.commit_transaction()
195    }
196
197    fn rollback_transaction(&self) -> StorageBackendResult<()> {
198        self.store.rollback_transaction()
199    }
200
201    fn savepoint(&self, id: crate::StorageSavepointId) -> StorageBackendResult<()> {
202        self.store.savepoint(&id.backend_name())
203    }
204
205    fn release_savepoint(&self, id: crate::StorageSavepointId) -> StorageBackendResult<()> {
206        self.store.release_savepoint(&id.backend_name())
207    }
208
209    fn rollback_to_savepoint(&self, id: crate::StorageSavepointId) -> StorageBackendResult<()> {
210        self.store.rollback_to_savepoint(&id.backend_name())
211    }
212}