Skip to main content

gitcortex_core/
store.rs

1use std::path::Path;
2
3use crate::{
4    error::Result,
5    graph::{Edge, GraphDiff, Node},
6    schema::NodeKind,
7};
8
9/// A subgraph centred on a seed node, returned by `get_subgraph`.
10pub struct SubGraph {
11    pub nodes: Vec<Node>,
12    pub edges: Vec<Edge>,
13}
14
15/// Callers of a symbol grouped by hop distance.
16pub struct CallersDeep {
17    /// Groups indexed 0..depth-1. `hops[0]` = direct callers (hop 1).
18    pub hops: Vec<Vec<Node>>,
19    /// Risk score derived from total affected count and depth reached.
20    pub risk_level: &'static str,
21}
22
23/// 360-degree view of a single symbol.
24pub struct SymbolContext {
25    /// The node matching `name` (first match if multiple).
26    pub definition: Node,
27    /// Functions/methods that call this symbol (direct callers).
28    pub callers: Vec<Node>,
29    /// Functions/methods that this symbol calls (direct callees).
30    pub callees: Vec<Node>,
31    /// Functions/types that reference this symbol via `Uses` edges.
32    pub used_by: Vec<Node>,
33}
34
35/// Backend-agnostic interface for the knowledge graph store.
36///
37/// The v0.1 implementation is `KuzuGraphStore` (local embedded DB).
38/// A remote backend can be plugged in by implementing this trait without
39/// touching the indexer or MCP layers.
40pub trait GraphStore: Send + Sync {
41    // ── Write operations ─────────────────────────────────────────────────────
42
43    /// Apply an incremental diff to the named branch's graph.
44    fn apply_diff(&mut self, branch: &str, diff: &GraphDiff) -> Result<()>;
45
46    // ── Read operations ──────────────────────────────────────────────────────
47
48    /// Find all nodes matching `name` on `branch`.
49    /// When `fuzzy` is true, matches any node whose name *contains* `name`
50    /// (case-sensitive substring). When false, exact match only.
51    fn lookup_symbol(&self, branch: &str, name: &str, fuzzy: bool) -> Result<Vec<Node>>;
52
53    /// Find all call-site nodes whose outgoing `Calls` edge points to a node
54    /// named `function_name` on `branch` (single hop).
55    fn find_callers(&self, branch: &str, function_name: &str) -> Result<Vec<Node>>;
56
57    /// Multi-hop BFS: find callers up to `depth` hops away.
58    /// Returns callers grouped by hop distance (1..=depth).
59    /// `depth` is capped at 5 to prevent runaway queries.
60    fn find_callers_deep(
61        &self,
62        branch: &str,
63        function_name: &str,
64        depth: u8,
65    ) -> Result<CallersDeep>;
66
67    /// Return a 360° view of a symbol: its definition, direct callers,
68    /// direct callees, and nodes that reference it via `Uses` edges.
69    fn symbol_context(&self, branch: &str, name: &str) -> Result<SymbolContext>;
70
71    /// List all top-level definitions in `file` on `branch`.
72    fn list_definitions(&self, branch: &str, file: &Path) -> Result<Vec<Node>>;
73
74    /// Return all nodes in `branch`'s graph.
75    fn list_all_nodes(&self, branch: &str) -> Result<Vec<Node>>;
76
77    /// Return all edges in `branch`'s graph.
78    fn list_all_edges(&self, branch: &str) -> Result<Vec<Edge>>;
79
80    /// Return the graph delta between two branches as a `GraphDiff`.
81    /// Nodes/edges present in `to` but not `from` are in `added_*`.
82    /// Nodes/edges present in `from` but not `to` are in `removed_*`.
83    fn branch_diff(&self, from: &str, to: &str) -> Result<GraphDiff>;
84
85    // ── Wave 2 tools ─────────────────────────────────────────────────────────
86
87    /// Find all functions/methods called by `function_name` up to `depth` hops.
88    /// Returns callees grouped by hop distance (1..=depth). Capped at 5.
89    fn find_callees(&self, branch: &str, function_name: &str, depth: u8) -> Result<CallersDeep>;
90
91    /// Find all structs/classes that implement/inherit `trait_or_interface_name`.
92    fn find_implementors(&self, branch: &str, trait_or_interface_name: &str) -> Result<Vec<Node>>;
93
94    /// Find all call paths between `from` and `to` using BFS.
95    /// Returns at most one path (the shortest), as a sequence of nodes.
96    fn trace_path(&self, branch: &str, from: &str, to: &str) -> Result<Vec<Node>>;
97
98    /// Find all nodes in `file` whose span overlaps `[start_line, end_line]`.
99    fn list_symbols_in_range(
100        &self,
101        branch: &str,
102        file: &Path,
103        start_line: u32,
104        end_line: u32,
105    ) -> Result<Vec<Node>>;
106
107    /// Find symbols with no incoming Calls or Uses edges (potential dead code).
108    /// If `kind` is provided, filters to only that NodeKind.
109    fn find_unused_symbols(&self, branch: &str, kind: Option<NodeKind>) -> Result<Vec<Node>>;
110
111    /// Return a subgraph centred on `seed_name` up to `depth` hops.
112    /// `direction`: "in" (callers), "out" (callees), or "both".
113    fn get_subgraph(
114        &self,
115        branch: &str,
116        seed_name: &str,
117        depth: u8,
118        direction: &str,
119    ) -> Result<SubGraph>;
120
121    // ── Indexing state ───────────────────────────────────────────────────────
122
123    /// Last commit SHA successfully indexed for `branch`. `None` if the branch
124    /// has never been indexed.
125    fn last_indexed_sha(&self, branch: &str) -> Result<Option<String>>;
126
127    /// Persist the commit SHA after a successful index run.
128    fn set_last_indexed_sha(&mut self, branch: &str, sha: &str) -> Result<()>;
129}