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