Skip to main content

uqa_storage/key_value/
catalog.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Catalog facade implementation for key/value-backed persistence.
8
9use std::sync::Arc;
10
11use parking_lot::Mutex;
12use serde::{Deserialize, Serialize};
13
14use crate::catalog::{
15    CatalogFacade, CatalogIndexRow, ColumnStatsInput, ColumnStatsRow, EdgeRow, ForeignServerRow,
16    ForeignTableRow, GraphSnapshot, RelationIdentity, RelationKind, SchemaRow, SequenceOptions,
17    SequenceReservationResult, SequenceRow, SequenceSetValueResult, TableSchema, ViewRow,
18};
19use crate::{StorageBackendError, StorageBackendResult};
20
21use super::codec::{
22    decode_stored_document_value, decode_string, decode_value, doc_length_key,
23    doc_length_key_prefix, document_key_prefix, encode_stored_document_value, encode_value,
24    field_stats_key, field_stats_key_prefix, key_with_tag, posting_cluster_positions_field_prefix,
25    posting_cluster_positions_key_prefix, posting_cluster_score_field_prefix,
26    posting_cluster_score_key_prefix, posting_document_key, posting_document_key_prefix,
27    posting_field_prefix, posting_key_prefix, push_str, push_u64, read_str, read_u64,
28    reverse_posting_key, reverse_posting_key_prefix, single_str_key, string_value,
29    vector_field_prefix, vector_key_prefix,
30};
31use super::{
32    KeyValueBatch, KeyValueStore, TAG_ANALYZER, TAG_ANALYZER_DESCRIPTOR, TAG_CATALOG_INDEX,
33    TAG_COLUMN_STATS, TAG_EDGE, TAG_FIELD_ANALYZER_BINDING, TAG_FOREIGN_SERVER, TAG_FOREIGN_TABLE,
34    TAG_GRAPH_MEMBERSHIP, TAG_METADATA, TAG_MODEL, TAG_NAMED_GRAPH, TAG_PATH_INDEX, TAG_RELATION,
35    TAG_SCHEMA, TAG_SCORING_PARAMS, TAG_SEQUENCE, TAG_SEQUENCE_VALUE, TAG_TABLE,
36    TAG_TABLE_FIELD_ANALYZER, TAG_VERTEX, TAG_VIEW,
37};
38
39mod analyzers;
40pub(super) mod diskann;
41mod foreign;
42mod graph_access;
43mod graph_guards;
44mod graph_observations;
45mod graph_view;
46mod graphs;
47mod indexes;
48pub(super) mod keys;
49mod migration;
50mod models;
51mod occurrence_lifecycle;
52mod path_index_data;
53mod physical_indexes;
54mod record_revisions;
55mod records;
56mod relation_acl;
57mod relations;
58mod schema_table;
59mod sequences;
60mod table_data;
61mod tables;
62mod views;
63
64use keys::{
65    batch_put_or_keep_existing, batch_rekey_prefix, batch_rekey_prefix_or_keep_existing,
66    catalog_index_references_column, catalog_index_rename_column, column_stats_key,
67    column_stats_prefix, decode_catalog_relation_key, decode_relation_key, edge_key,
68    ensure_prefix_absent, graph_membership_graph_prefix, graph_membership_key,
69    graph_membership_prefix, load_single_string_rows, register_migration_relation, relation_key,
70    table_field_analyzer_field_prefix, table_field_analyzer_key, table_field_analyzer_prefix,
71    vertex_key,
72};
73use migration::{
74    apply_relation_migrations, collect_relation_migrations, validate_relation_parents,
75};
76use records::{
77    StoredCatalogIndex, StoredColumnStats, StoredEdge, StoredForeignServer, StoredForeignTable,
78    StoredRelation, StoredSequence, StoredSequenceValue, StoredVertex, StoredView,
79    STORED_FOREIGN_TABLE_SECURITY_VERSION,
80};
81
82#[derive(Clone)]
83pub struct KeyValueCatalog {
84    store: Arc<dyn KeyValueStore>,
85    graph_indexes_lock: Arc<Mutex<()>>,
86}
87
88impl KeyValueCatalog {
89    pub fn new(store: Arc<dyn KeyValueStore>) -> Self {
90        Self {
91            store,
92            graph_indexes_lock: Arc::new(Mutex::new(())),
93        }
94    }
95
96    pub fn store(&self) -> Arc<dyn KeyValueStore> {
97        Arc::clone(&self.store)
98    }
99}
100
101impl CatalogFacade for KeyValueCatalog {
102    fn record_revisions(
103        &self,
104        records: &[crate::catalog::CatalogRecordRef<'_>],
105    ) -> StorageBackendResult<Option<Vec<Option<crate::catalog::CatalogRecordRevision>>>> {
106        if !self.store.transaction_model().is_versioned() {
107            return Ok(None);
108        }
109        self.record_revisions_impl(records).map(Some)
110    }
111
112    fn transaction_model(&self) -> crate::StorageTransactionModel {
113        self.store.transaction_model()
114    }
115
116    fn transaction_affinity(&self) -> Option<crate::StorageSessionAffinity> {
117        self.store.transaction_affinity()
118    }
119
120    fn clear_path_index_data(&self, index: &str) -> StorageBackendResult<()> {
121        self.clear_path_index_data_impl(index)
122    }
123
124    fn save_path_index_pairs(
125        &self,
126        index: &str,
127        sequence: &str,
128        pairs: &[(u64, u64)],
129    ) -> StorageBackendResult<()> {
130        self.save_path_index_pairs_impl(index, sequence, pairs)
131    }
132
133    fn finish_path_index_data(
134        &self,
135        index: &str,
136        graph: &str,
137        definition: &str,
138    ) -> StorageBackendResult<()> {
139        self.finish_path_index_data_impl(index, graph, definition)
140    }
141
142    fn path_index_data_is_current(
143        &self,
144        index: &str,
145        definition: &str,
146    ) -> StorageBackendResult<bool> {
147        self.path_index_data_is_current_impl(index, definition)
148    }
149
150    fn path_index_pairs(
151        &self,
152        index: &str,
153        sequence: &str,
154        after: Option<(u64, u64)>,
155        limit: usize,
156    ) -> StorageBackendResult<Vec<(u64, u64)>> {
157        self.path_index_pairs_impl(index, sequence, after, limit)
158    }
159
160    fn graph_vertex(&self, id: u64) -> StorageBackendResult<Option<crate::GraphVertexRow>> {
161        self.graph_vertex_impl(id)
162    }
163
164    fn graph_edge(&self, id: u64) -> StorageBackendResult<Option<EdgeRow>> {
165        self.graph_edge_impl(id)
166    }
167
168    fn graph_entity_ids(
169        &self,
170        filter: crate::GraphEntityFilter<'_>,
171        after: Option<u64>,
172        limit: usize,
173    ) -> StorageBackendResult<Vec<u64>> {
174        self.graph_entity_ids_impl(filter, after, limit)
175    }
176
177    fn graph_entity_count(
178        &self,
179        filter: crate::GraphEntityFilter<'_>,
180    ) -> StorageBackendResult<u64> {
181        self.with_graph_read(|read| {
182            let mut after = None;
183            let mut count = 0_u64;
184            loop {
185                let ids = read.ids(filter, after, 256)?;
186                if ids.is_empty() {
187                    return Ok(count);
188                }
189                after = ids.last().copied();
190                count = count
191                    .checked_add(
192                        u64::try_from(ids.len())
193                            .map_err(|error| StorageBackendError::Other(error.to_string()))?,
194                    )
195                    .ok_or_else(|| {
196                        StorageBackendError::Other("graph entity count overflow".into())
197                    })?;
198            }
199        })
200    }
201
202    fn graph_entity_max_id(
203        &self,
204        kind: crate::GraphEntityKind,
205    ) -> StorageBackendResult<Option<u64>> {
206        self.with_graph_read(|read| {
207            let filter = crate::GraphEntityFilter::new(kind, None);
208            let mut after = None;
209            loop {
210                let ids = read.ids(filter, after, 256)?;
211                if ids.is_empty() {
212                    return Ok(after);
213                }
214                after = ids.last().copied();
215            }
216        })
217    }
218
219    fn graph_entity_memberships(
220        &self,
221        kind: crate::GraphEntityKind,
222        id: u64,
223    ) -> StorageBackendResult<Vec<String>> {
224        self.graph_entity_memberships_impl(kind, id)
225    }
226
227    fn graph_has_membership(
228        &self,
229        kind: crate::GraphEntityKind,
230        id: u64,
231        graph: &str,
232    ) -> StorageBackendResult<bool> {
233        self.store
234            .contains_key(&graph_membership_key(kind.as_str(), id, graph)?)
235    }
236
237    fn set_metadata(&self, key: &str, value: &str) -> StorageBackendResult<()> {
238        self.set_metadata_impl(key, value)
239    }
240
241    fn delete_metadata(&self, key: &str) -> StorageBackendResult<()> {
242        self.delete_metadata_impl(key)
243    }
244
245    fn get_metadata(&self, key: &str) -> StorageBackendResult<Option<String>> {
246        self.get_metadata_impl(key)
247    }
248
249    fn metadata_has_private_changes(&self, key: &str) -> StorageBackendResult<bool> {
250        self.metadata_has_private_changes_impl(key)
251    }
252    fn metadata_with_prefix(&self, prefix: &str) -> StorageBackendResult<Vec<(String, String)>> {
253        self.metadata_with_prefix_impl(prefix)
254    }
255
256    fn save_statistics_maintenance(
257        &self,
258        table: &str,
259        state: &crate::statistics_maintenance::StatisticsMaintenance,
260    ) -> StorageBackendResult<()> {
261        let key = single_str_key(
262            TAG_METADATA,
263            &crate::statistics_maintenance::StatisticsMaintenance::key(table),
264        )?;
265        self.store.with_mutation(&mut |read, batch| {
266            let value = state
267                .encode(read.control())
268                .map_err(crate::mvcc::VersionError::into_storage_error)?;
269            batch.replace_statistics_maintenance(&key, &value)
270        })
271    }
272
273    fn migrate_relation_namespace(&self) -> StorageBackendResult<()> {
274        self.migrate_relation_namespace_impl()?;
275        self.ensure_graph_lookup_indexes()
276    }
277
278    fn save_schema_row(&self, schema: &SchemaRow) -> StorageBackendResult<()> {
279        self.save_schema_row_impl(schema)
280    }
281
282    fn schema_has_private_changes(&self, name: &str) -> StorageBackendResult<bool> {
283        self.named_record_has_private_changes(TAG_SCHEMA, name)
284    }
285
286    fn drop_schema(&self, name: &str) -> StorageBackendResult<()> {
287        self.drop_schema_impl(name)
288    }
289
290    fn load_schema_rows(&self) -> StorageBackendResult<Vec<SchemaRow>> {
291        self.load_schema_rows_impl()
292    }
293
294    fn save_table(&self, schema: &TableSchema) -> StorageBackendResult<()> {
295        self.save_table_impl(schema)
296    }
297
298    fn load_tables(&self) -> StorageBackendResult<Vec<TableSchema>> {
299        self.load_tables_impl()
300    }
301
302    fn drop_table(&self, name: &str) -> StorageBackendResult<()> {
303        self.drop_table_impl(name)
304    }
305
306    fn drop_table_and_data(&self, name: &str) -> StorageBackendResult<()> {
307        self.drop_table_and_data_impl(name)
308    }
309
310    fn purge_table_data(&self, name: &str) -> StorageBackendResult<()> {
311        self.purge_table_data_impl(name)
312    }
313
314    fn rename_table_data(&self, from: &str, to: &str) -> StorageBackendResult<()> {
315        self.rename_table_data_impl(from, to)
316    }
317
318    fn drop_column_data(&self, table_name: &str, column_name: &str) -> StorageBackendResult<()> {
319        self.drop_column_data_impl(table_name, column_name)
320    }
321
322    fn rename_column_data(
323        &self,
324        table_name: &str,
325        from: &str,
326        to: &str,
327    ) -> StorageBackendResult<()> {
328        self.rename_column_data_impl(table_name, from, to)
329    }
330
331    fn save_model(&self, name: &str, json: &str) -> StorageBackendResult<()> {
332        self.save_model_impl(name, json)
333    }
334
335    fn load_models(&self) -> StorageBackendResult<Vec<(String, String)>> {
336        self.load_models_impl()
337    }
338
339    fn load_model(&self, name: &str) -> StorageBackendResult<Option<String>> {
340        self.load_model_impl(name)
341    }
342
343    fn drop_model(&self, name: &str) -> StorageBackendResult<()> {
344        self.drop_model_impl(name)
345    }
346
347    fn save_scoring_params(&self, name: &str, params_json: &str) -> StorageBackendResult<()> {
348        self.save_scoring_params_impl(name, params_json)
349    }
350
351    fn load_scoring_params(&self, name: &str) -> StorageBackendResult<Option<String>> {
352        self.load_scoring_params_impl(name)
353    }
354
355    fn load_all_scoring_params(&self) -> StorageBackendResult<Vec<(String, String)>> {
356        self.load_all_scoring_params_impl()
357    }
358
359    fn drop_scoring_params(&self, name: &str) -> StorageBackendResult<()> {
360        self.drop_scoring_params_impl(name)
361    }
362
363    fn create_sequence_row(&self, sequence: &SequenceRow) -> StorageBackendResult<bool> {
364        self.create_sequence_row_impl(sequence)
365    }
366
367    fn replace_sequence_row(&self, sequence: &SequenceRow) -> StorageBackendResult<bool> {
368        self.replace_sequence_row_impl(sequence)
369    }
370
371    fn rename_sequence_row(&self, from: &str, to: &str) -> StorageBackendResult<bool> {
372        self.rename_sequence_row_impl(from, to)
373    }
374
375    fn drop_sequence_row(&self, name: &str) -> StorageBackendResult<bool> {
376        self.drop_sequence_row_impl(name)
377    }
378
379    fn load_sequence_rows(&self) -> StorageBackendResult<Vec<SequenceRow>> {
380        self.load_sequence_rows_impl()
381    }
382
383    fn sequence_has_private_changes(
384        &self,
385        relation: &RelationIdentity,
386        _object_id: [u8; 16],
387    ) -> StorageBackendResult<bool> {
388        self.sequence_has_private_changes_impl(relation)
389    }
390
391    fn sequence_value_has_private_changes(
392        &self,
393        object_id: [u8; 16],
394        definition_generation: [u8; 16],
395    ) -> StorageBackendResult<bool> {
396        self.sequence_value_has_private_changes_impl(object_id, definition_generation)
397    }
398
399    fn migrate_sequence_values(&self) -> StorageBackendResult<()> {
400        self.migrate_sequence_values_impl()
401    }
402
403    fn reserve_sequence_values(
404        &self,
405        name: &str,
406        object_id: [u8; 16],
407        definition_generation: [u8; 16],
408    ) -> StorageBackendResult<SequenceReservationResult> {
409        self.reserve_sequence_values_impl(name, object_id, definition_generation)
410    }
411
412    fn set_sequence_value(
413        &self,
414        name: &str,
415        object_id: [u8; 16],
416        definition_generation: [u8; 16],
417        value: i64,
418        called: bool,
419        log_count: i64,
420    ) -> StorageBackendResult<SequenceSetValueResult> {
421        self.set_sequence_value_impl(
422            name,
423            object_id,
424            definition_generation,
425            value,
426            called,
427            log_count,
428        )
429    }
430
431    fn log_sequence_values(
432        &self,
433        name: &str,
434        object_id: [u8; 16],
435        definition_generation: [u8; 16],
436        expected: (i64, bool),
437        logged: crate::catalog::SequenceValuePosition,
438    ) -> StorageBackendResult<crate::catalog::SequenceLogResult> {
439        self.log_sequence_values_impl(name, object_id, definition_generation, expected, logged)
440    }
441
442    fn save_view(&self, view: &ViewRow) -> StorageBackendResult<()> {
443        self.save_view_impl(view)
444    }
445
446    fn rename_view(
447        &self,
448        from: &RelationIdentity,
449        to: &RelationIdentity,
450    ) -> StorageBackendResult<bool> {
451        self.rename_view_impl(from, to)
452    }
453
454    fn drop_view(&self, relation: &RelationIdentity) -> StorageBackendResult<bool> {
455        self.drop_view_impl(relation)
456    }
457
458    fn load_views(&self) -> StorageBackendResult<Vec<ViewRow>> {
459        self.load_views_impl()
460    }
461
462    fn save_named_graph(&self, name: &str) -> StorageBackendResult<()> {
463        self.save_named_graph_impl(name)
464    }
465    fn guard_graph_definition(&self, graph: Option<&str>) -> StorageBackendResult<()> {
466        self.guard_graph_definition_impl(graph)
467    }
468    fn load_named_graph_snapshot(&self, name: &str) -> StorageBackendResult<Option<GraphSnapshot>> {
469        let (mut result, namespace) =
470            self.with_graph_read(|read| Ok((read.snapshot(name)?, read.identifier_namespace()?)))?;
471        if let (Some(snapshot), Some(allocator)) =
472            (result.as_mut(), self.store.identifier_allocator())
473        {
474            snapshot.label_registry_json = crate::catalog::graph_identifiers::export_registry(
475                &snapshot.label_registry_json,
476                name,
477                namespace,
478                |key| allocator.identifier_watermark(key),
479            )?;
480        }
481        Ok(result)
482    }
483
484    fn drop_named_graph(&self, name: &str) -> StorageBackendResult<()> {
485        self.drop_named_graph_impl(name)
486    }
487
488    fn load_named_graphs(&self) -> StorageBackendResult<Vec<String>> {
489        self.load_named_graphs_impl()
490    }
491    fn named_graph_exists(&self, name: &str) -> StorageBackendResult<bool> {
492        self.store
493            .contains_key(&single_str_key(TAG_NAMED_GRAPH, name)?)
494    }
495
496    fn save_vertex(
497        &self,
498        vertex_id: u64,
499        label: &str,
500        properties_json: &str,
501    ) -> StorageBackendResult<()> {
502        self.save_vertex_impl(vertex_id, label, properties_json)
503    }
504
505    fn delete_vertex(&self, vertex_id: u64) -> StorageBackendResult<()> {
506        self.delete_vertex_impl(vertex_id)
507    }
508
509    fn load_vertices(&self) -> StorageBackendResult<Vec<(u64, String, String)>> {
510        self.load_vertices_impl()
511    }
512
513    fn save_edge(
514        &self,
515        edge_id: u64,
516        source_id: u64,
517        target_id: u64,
518        label: &str,
519        properties_json: &str,
520    ) -> StorageBackendResult<()> {
521        self.save_edge_impl(edge_id, source_id, target_id, label, properties_json)
522    }
523
524    fn delete_edge(&self, edge_id: u64) -> StorageBackendResult<()> {
525        self.delete_edge_impl(edge_id)
526    }
527
528    fn load_edges(&self) -> StorageBackendResult<Vec<EdgeRow>> {
529        self.load_edges_impl()
530    }
531
532    fn save_graph_membership(
533        &self,
534        entity_type: &str,
535        entity_id: u64,
536        graph_name: &str,
537    ) -> StorageBackendResult<()> {
538        self.save_graph_membership_impl(entity_type, entity_id, graph_name)
539    }
540
541    fn delete_graph_membership(
542        &self,
543        entity_type: &str,
544        entity_id: u64,
545        graph_name: &str,
546    ) -> StorageBackendResult<()> {
547        self.delete_graph_membership_impl(entity_type, entity_id, graph_name)
548    }
549
550    fn delete_graph_membership_for_graph(&self, graph_name: &str) -> StorageBackendResult<()> {
551        self.delete_graph_membership_for_graph_impl(graph_name)
552    }
553
554    fn load_graph_memberships(&self) -> StorageBackendResult<Vec<(String, u64, String)>> {
555        self.load_graph_memberships_impl()
556    }
557
558    fn purge_orphan_graph_entities(&self) -> StorageBackendResult<()> {
559        self.purge_orphan_graph_entities_impl()
560    }
561
562    fn replace_named_graph(
563        &self,
564        graph_name: &str,
565        snapshot: &GraphSnapshot,
566    ) -> StorageBackendResult<()> {
567        self.replace_named_graph_impl(graph_name, snapshot)
568    }
569
570    fn drop_named_graph_data(&self, graph_name: &str) -> StorageBackendResult<()> {
571        self.drop_named_graph_data_impl(graph_name)
572    }
573
574    fn save_analyzer(&self, name: &str, config_json: &str) -> StorageBackendResult<()> {
575        self.save_analyzer_impl(name, config_json)
576    }
577
578    fn drop_analyzer(&self, name: &str) -> StorageBackendResult<()> {
579        self.drop_analyzer_impl(name)
580    }
581
582    fn load_analyzers(&self) -> StorageBackendResult<Vec<(String, String)>> {
583        self.load_analyzers_impl()
584    }
585
586    fn save_analyzer_revision(
587        &self,
588        name: &str,
589        config_json: &str,
590        descriptor_json: &str,
591    ) -> StorageBackendResult<()> {
592        self.save_analyzer_revision_impl(name, config_json, descriptor_json)
593    }
594
595    fn load_analyzer_descriptors(&self) -> StorageBackendResult<Vec<(String, String)>> {
596        load_single_string_rows(self.store.as_ref(), TAG_ANALYZER_DESCRIPTOR)
597    }
598
599    fn replace_table_field_analyzer_binding(
600        &self,
601        table: &str,
602        field: &str,
603        phase: &str,
604        name: &str,
605        binding_json: &str,
606    ) -> StorageBackendResult<()> {
607        self.replace_table_field_analyzer_binding_impl(table, field, phase, name, binding_json)
608    }
609
610    fn load_table_field_analyzer_bindings(
611        &self,
612    ) -> StorageBackendResult<Vec<(String, String, String)>> {
613        self.load_table_field_analyzer_bindings_impl()
614    }
615
616    fn save_table_field_analyzer(
617        &self,
618        table_name: &str,
619        field: &str,
620        phase: &str,
621        analyzer_name: &str,
622    ) -> StorageBackendResult<()> {
623        self.save_table_field_analyzer_impl(table_name, field, phase, analyzer_name)
624    }
625
626    fn replace_table_field_analyzer(
627        &self,
628        table_name: &str,
629        field: &str,
630        phase: &str,
631        analyzer_name: &str,
632    ) -> StorageBackendResult<()> {
633        self.replace_table_field_analyzer_impl(table_name, field, phase, analyzer_name)
634    }
635
636    fn drop_table_field_analyzer_field(
637        &self,
638        table_name: &str,
639        field: &str,
640    ) -> StorageBackendResult<()> {
641        self.drop_table_field_analyzer_field_impl(table_name, field)
642    }
643
644    fn drop_table_field_analyzers(&self, table_name: &str) -> StorageBackendResult<()> {
645        self.drop_table_field_analyzers_impl(table_name)
646    }
647
648    fn load_table_field_analyzers(
649        &self,
650    ) -> StorageBackendResult<Vec<(String, String, String, String)>> {
651        self.load_table_field_analyzers_impl()
652    }
653
654    fn save_foreign_server(
655        &self,
656        name: &str,
657        fdw_type: &str,
658        options_json: &str,
659    ) -> StorageBackendResult<()> {
660        self.save_foreign_server_impl(name, fdw_type, options_json)
661    }
662
663    fn drop_foreign_server(&self, name: &str) -> StorageBackendResult<()> {
664        self.drop_foreign_server_impl(name)
665    }
666
667    fn load_foreign_servers(&self) -> StorageBackendResult<Vec<(String, String, String)>> {
668        self.load_foreign_servers_impl()
669    }
670
671    fn save_foreign_server_row(&self, row: &ForeignServerRow) -> StorageBackendResult<()> {
672        self.save_foreign_server_row_impl(row)
673    }
674
675    fn load_foreign_server_rows(&self) -> StorageBackendResult<Vec<ForeignServerRow>> {
676        self.load_foreign_server_rows_impl()
677    }
678
679    fn save_foreign_table(&self, row: &ForeignTableRow) -> StorageBackendResult<()> {
680        self.save_foreign_table_impl(row)
681    }
682
683    fn rename_foreign_table(
684        &self,
685        from: &RelationIdentity,
686        to: &RelationIdentity,
687    ) -> StorageBackendResult<bool> {
688        self.rename_foreign_table_impl(from, to)
689    }
690
691    fn update_foreign_table_security(
692        &self,
693        relation: &RelationIdentity,
694        security: &crate::RelationSecurityRow,
695    ) -> StorageBackendResult<bool> {
696        self.update_foreign_table_security_impl(relation, security)
697    }
698
699    fn drop_foreign_table(&self, relation: &RelationIdentity) -> StorageBackendResult<()> {
700        self.drop_foreign_table_impl(relation)
701    }
702
703    fn load_foreign_tables(&self) -> StorageBackendResult<Vec<ForeignTableRow>> {
704        self.load_foreign_tables_impl()
705    }
706
707    fn save_catalog_index_row(&self, index: &CatalogIndexRow) -> StorageBackendResult<()> {
708        self.save_catalog_index_impl(index)
709    }
710
711    fn drop_catalog_index(&self, relation: &RelationIdentity) -> StorageBackendResult<()> {
712        self.drop_catalog_index_impl(relation)
713    }
714
715    fn drop_catalog_indexes_for_table(&self, table_name: &str) -> StorageBackendResult<()> {
716        self.drop_catalog_indexes_for_table_impl(table_name)
717    }
718
719    fn load_catalog_indexes(&self) -> StorageBackendResult<Vec<CatalogIndexRow>> {
720        self.load_catalog_indexes_impl()
721    }
722
723    fn save_path_index(
724        &self,
725        graph_name: &str,
726        label_sequences_json: &str,
727    ) -> StorageBackendResult<()> {
728        self.save_path_index_impl(graph_name, label_sequences_json)
729    }
730
731    fn drop_path_index(&self, graph_name: &str) -> StorageBackendResult<()> {
732        self.drop_path_index_impl(graph_name)
733    }
734
735    fn load_path_indexes(&self) -> StorageBackendResult<Vec<(String, String)>> {
736        self.load_path_indexes_impl()
737    }
738
739    fn save_column_stats(&self, stats: ColumnStatsInput<'_>) -> StorageBackendResult<()> {
740        self.save_column_stats_impl(stats)
741    }
742
743    fn replace_column_stats(
744        &self,
745        table_name: &str,
746        stats: &[ColumnStatsInput<'_>],
747    ) -> StorageBackendResult<()> {
748        self.replace_column_stats_impl(table_name, stats)
749    }
750
751    fn load_column_stats(&self, table_name: &str) -> StorageBackendResult<Vec<ColumnStatsRow>> {
752        self.load_column_stats_impl(table_name)
753    }
754
755    fn delete_column_stats(&self, table_name: &str) -> StorageBackendResult<()> {
756        self.delete_column_stats_impl(table_name)
757    }
758}
759
760#[cfg(test)]
761mod tests;