Skip to main content

akar_processor/processor/
graph_source.rs

1//! Builds a `GraphDataSource` snapshot from the storage `TableCatalog`.
2//!
3//! The query processor and the connection layer own the storage catalog, so
4//! they construct this adapter and hand it to GDS table functions through the
5//! `TableFunction::CustomTableWithGraph` variant.
6
7use akar_function::graph::{GraphDataSource, GraphEdge};
8use akar_storage::table::TableCatalog;
9use std::sync::Arc;
10
11/// A `GraphDataSource` snapshot over the live node/rel tables of a catalog.
12#[derive(Debug, Default)]
13pub struct CatalogGraphSource {
14    num_nodes: usize,
15    edges: Vec<GraphEdge>,
16}
17
18impl CatalogGraphSource {
19    /// Snapshot the graph topology. `None` (no catalog) yields an empty graph.
20    pub fn new(catalog: Option<&Arc<TableCatalog>>) -> Self {
21        let Some(catalog) = catalog else {
22            return Self::default();
23        };
24
25        let mut num_nodes = 0usize;
26        let mut edges = Vec::new();
27
28        for node_table in catalog.all_node_tables() {
29            num_nodes = num_nodes.max(node_table.num_rows as usize);
30        }
31        for rel_table in catalog.all_rel_tables() {
32            for (edge_idx, &(src, dst)) in rel_table.edges.iter().enumerate() {
33                if src == u64::MAX || dst == u64::MAX {
34                    continue;
35                }
36                edges.push(GraphEdge {
37                    src_offset: src,
38                    dst_offset: dst,
39                    rel_id: edge_idx as u64,
40                    rel_table_id: rel_table.table_id,
41                });
42                num_nodes = num_nodes.max(src as usize + 1).max(dst as usize + 1);
43            }
44        }
45
46        Self { num_nodes, edges }
47    }
48}
49
50impl GraphDataSource for CatalogGraphSource {
51    fn num_nodes(&self) -> usize {
52        self.num_nodes
53    }
54
55    fn edges(&self) -> Vec<GraphEdge> {
56        self.edges.clone()
57    }
58}