pub trait GraphBackend {
Show 30 methods
// Required methods
fn insert_node(&self, node: NodeSpec) -> Result<i64, SqliteGraphError>;
fn insert_edge(&self, edge: EdgeSpec) -> Result<i64, SqliteGraphError>;
fn update_node(
&self,
node_id: i64,
node: NodeSpec,
) -> Result<i64, SqliteGraphError>;
fn delete_entity(&self, id: i64) -> Result<(), SqliteGraphError>;
fn entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>;
fn get_node(
&self,
snapshot_id: SnapshotId,
id: i64,
) -> Result<GraphEntity, SqliteGraphError>;
fn neighbors(
&self,
snapshot_id: SnapshotId,
node: i64,
query: NeighborQuery,
) -> Result<Vec<i64>, SqliteGraphError>;
fn bfs(
&self,
snapshot_id: SnapshotId,
start: i64,
depth: u32,
) -> Result<Vec<i64>, SqliteGraphError>;
fn shortest_path(
&self,
snapshot_id: SnapshotId,
start: i64,
end: i64,
) -> Result<Option<Vec<i64>>, SqliteGraphError>;
fn node_degree(
&self,
snapshot_id: SnapshotId,
node: i64,
) -> Result<(usize, usize), SqliteGraphError>;
fn k_hop(
&self,
snapshot_id: SnapshotId,
start: i64,
depth: u32,
direction: BackendDirection,
) -> Result<Vec<i64>, SqliteGraphError>;
fn k_hop_filtered(
&self,
snapshot_id: SnapshotId,
start: i64,
depth: u32,
direction: BackendDirection,
allowed_edge_types: &[&str],
) -> Result<Vec<i64>, SqliteGraphError>;
fn chain_query(
&self,
snapshot_id: SnapshotId,
start: i64,
chain: &[ChainStep],
) -> Result<Vec<i64>, SqliteGraphError>;
fn pattern_search(
&self,
snapshot_id: SnapshotId,
start: i64,
pattern: &PatternQuery,
) -> Result<Vec<PatternMatch>, SqliteGraphError>;
fn checkpoint(&self) -> Result<(), SqliteGraphError>;
fn flush(&self) -> Result<(), SqliteGraphError>;
fn backup(
&self,
backup_dir: &Path,
) -> Result<BackupResult, SqliteGraphError>;
fn snapshot_export(
&self,
export_dir: &Path,
) -> Result<SnapshotMetadata, SqliteGraphError>;
fn snapshot_import(
&self,
import_dir: &Path,
) -> Result<ImportMetadata, SqliteGraphError>;
fn kv_get(
&self,
snapshot_id: SnapshotId,
key: &[u8],
) -> Result<Option<KvValue>, SqliteGraphError>;
fn kv_set(
&self,
key: Vec<u8>,
value: KvValue,
ttl_seconds: Option<u64>,
) -> Result<(), SqliteGraphError>;
fn kv_delete(&self, key: &[u8]) -> Result<(), SqliteGraphError>;
fn subscribe(
&self,
filter: SubscriptionFilter,
) -> Result<(u64, Receiver<PubSubEvent>), SqliteGraphError>;
fn unsubscribe(&self, subscriber_id: u64) -> Result<bool, SqliteGraphError>;
fn kv_prefix_scan(
&self,
snapshot_id: SnapshotId,
prefix: &[u8],
) -> Result<Vec<(Vec<u8>, KvValue)>, SqliteGraphError>;
fn query_nodes_by_kind(
&self,
snapshot_id: SnapshotId,
kind: &str,
) -> Result<Vec<i64>, SqliteGraphError>;
fn query_nodes_by_name_pattern(
&self,
snapshot_id: SnapshotId,
pattern: &str,
) -> Result<Vec<i64>, SqliteGraphError>;
// Provided methods
fn all_entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError> { ... }
fn fetch_outgoing(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError> { ... }
fn fetch_incoming(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError> { ... }
}Expand description
Each trait method delegates to backend-specific primitives while ensuring deterministic behavior and a single integration surface for consumers.
§Snapshot Isolation
All read operations require a snapshot_id: SnapshotId parameter to enforce
ACID compliance. Reads only observe data committed at or before the snapshot.
Required Methods§
fn insert_node(&self, node: NodeSpec) -> Result<i64, SqliteGraphError>
fn insert_edge(&self, edge: EdgeSpec) -> Result<i64, SqliteGraphError>
Sourcefn update_node(
&self,
node_id: i64,
node: NodeSpec,
) -> Result<i64, SqliteGraphError>
fn update_node( &self, node_id: i64, node: NodeSpec, ) -> Result<i64, SqliteGraphError>
Update an existing node in place without allocating a new node ID
This modifies the data associated with an existing node while preserving its node_id.
§Arguments
node_id- The ID of the node to update (must exist)node- New node specification (kind, name, file_path, data)
§Returns
The same node_id that was passed in, if update succeeded
§Errors
Returns SqliteGraphError if:
- The node_id doesn’t exist
- The update operation fails
- The backend doesn’t support in-place updates
§Behavior by Backend
- Native: Uses WAL to update node data in place, preserving node_id
- SQLite: Uses UPDATE SQL query on entities table
§Example
// Create a node
let node_id = backend.insert_node(NodeSpec {
kind: "File".to_string(),
name: "main.rs".to_string(),
file_path: Some("main.rs".to_string()),
data: serde_json::json!({"hash": "abc123"}),
})?;
// Update it - this does NOT allocate a new node_id
let updated_id = backend.update_node(node_id, NodeSpec {
kind: "File".to_string(),
name: "main.rs".to_string(),
file_path: Some("main.rs".to_string()),
data: serde_json::json!({"hash": "def456", "modified": true}),
})?;
assert_eq!(updated_id, node_id); // Same ID!Sourcefn delete_entity(&self, id: i64) -> Result<(), SqliteGraphError>
fn delete_entity(&self, id: i64) -> Result<(), SqliteGraphError>
Delete an entity (node) from the graph by ID
This removes the entity and all associated edges from the graph. For SQLite backend: deletes from entities table and cascades to edges For Native backend: marks node as deleted and updates adjacency indexes
Sourcefn entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>
fn entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>
Get all entity IDs from the graph
Returns a vector of all node IDs currently stored in the graph. For SQLite backend: queries all IDs from entities table For Native backend: iterates over node store
fn get_node( &self, snapshot_id: SnapshotId, id: i64, ) -> Result<GraphEntity, SqliteGraphError>
fn neighbors( &self, snapshot_id: SnapshotId, node: i64, query: NeighborQuery, ) -> Result<Vec<i64>, SqliteGraphError>
fn bfs( &self, snapshot_id: SnapshotId, start: i64, depth: u32, ) -> Result<Vec<i64>, SqliteGraphError>
fn shortest_path( &self, snapshot_id: SnapshotId, start: i64, end: i64, ) -> Result<Option<Vec<i64>>, SqliteGraphError>
fn node_degree( &self, snapshot_id: SnapshotId, node: i64, ) -> Result<(usize, usize), SqliteGraphError>
fn k_hop( &self, snapshot_id: SnapshotId, start: i64, depth: u32, direction: BackendDirection, ) -> Result<Vec<i64>, SqliteGraphError>
fn k_hop_filtered( &self, snapshot_id: SnapshotId, start: i64, depth: u32, direction: BackendDirection, allowed_edge_types: &[&str], ) -> Result<Vec<i64>, SqliteGraphError>
fn chain_query( &self, snapshot_id: SnapshotId, start: i64, chain: &[ChainStep], ) -> Result<Vec<i64>, SqliteGraphError>
fn pattern_search( &self, snapshot_id: SnapshotId, start: i64, pattern: &PatternQuery, ) -> Result<Vec<PatternMatch>, SqliteGraphError>
Sourcefn checkpoint(&self) -> Result<(), SqliteGraphError>
fn checkpoint(&self) -> Result<(), SqliteGraphError>
Trigger WAL checkpoint for backends that support write-ahead logging
For Native backend with WAL: flushes WAL to graph file For SQLite backend: executes PRAGMA wal_checkpoint(TRUNCATE) For backends without WAL: returns Ok(()) as no-op
Sourcefn flush(&self) -> Result<(), SqliteGraphError>
fn flush(&self) -> Result<(), SqliteGraphError>
Force immediate flush of WAL buffer to disk
Ensures all buffered WAL records (including KV writes) are persisted immediately, making them visible to other processes.
For Native backend with WAL: flushes WAL buffer to disk For SQLite backend: returns Ok(()) as no-op (SQLite handles sync) For backends without WAL: returns Ok(()) as no-op
Sourcefn backup(&self, backup_dir: &Path) -> Result<BackupResult, SqliteGraphError>
fn backup(&self, backup_dir: &Path) -> Result<BackupResult, SqliteGraphError>
Sourcefn snapshot_export(
&self,
export_dir: &Path,
) -> Result<SnapshotMetadata, SqliteGraphError>
fn snapshot_export( &self, export_dir: &Path, ) -> Result<SnapshotMetadata, SqliteGraphError>
Export database snapshot to the specified directory
Creates a consistent snapshot of the current database state. For Native backend: uses snapshot format For SQLite backend: uses JSON dump format
§Arguments
export_dir- Directory path where snapshot will be written
§Returns
Snapshot metadata including file paths and size information
Sourcefn snapshot_import(
&self,
import_dir: &Path,
) -> Result<ImportMetadata, SqliteGraphError>
fn snapshot_import( &self, import_dir: &Path, ) -> Result<ImportMetadata, SqliteGraphError>
Import database snapshot from the specified directory
Restores database state from a previously created snapshot. For Native backend: loads snapshot format For SQLite backend: loads JSON dump format
§Arguments
import_dir- Directory path containing snapshot files
§Returns
Import metadata including number of records imported
Sourcefn kv_get(
&self,
snapshot_id: SnapshotId,
key: &[u8],
) -> Result<Option<KvValue>, SqliteGraphError>
fn kv_get( &self, snapshot_id: SnapshotId, key: &[u8], ) -> Result<Option<KvValue>, SqliteGraphError>
Sourcefn kv_set(
&self,
key: Vec<u8>,
value: KvValue,
ttl_seconds: Option<u64>,
) -> Result<(), SqliteGraphError>
fn kv_set( &self, key: Vec<u8>, value: KvValue, ttl_seconds: Option<u64>, ) -> Result<(), SqliteGraphError>
Set a value in the KV store
This operation participates in the current transaction and will be committed atomically with other graph operations.
§Arguments
key- Key to set (arbitrary bytes)value- Value to storettl_seconds- Optional TTL in seconds (None = no expiration)
Sourcefn kv_delete(&self, key: &[u8]) -> Result<(), SqliteGraphError>
fn kv_delete(&self, key: &[u8]) -> Result<(), SqliteGraphError>
Delete a value from the KV store
This operation participates in the current transaction and will be committed atomically with other graph operations.
§Arguments
key- Key to delete
Sourcefn subscribe(
&self,
filter: SubscriptionFilter,
) -> Result<(u64, Receiver<PubSubEvent>), SqliteGraphError>
fn subscribe( &self, filter: SubscriptionFilter, ) -> Result<(u64, Receiver<PubSubEvent>), SqliteGraphError>
Subscribe to graph change events
Returns a subscriber ID and a receiver channel for events. The receiver will receive events that match the given filter.
§Events
Events are emitted ONLY on transaction commit:
NodeChanged- node created or modifiedEdgeChanged- edge created or modifiedKvChanged- KV entry created, modified, or deletedSnapshotCommitted- transaction committed
§Best-Effort Delivery
- No persistence of events
- If receiver is dropped, events are silently dropped
- If channel is full, events are silently dropped
- No delivery guarantees
§Example
let (sub_id, rx) = graph.subscribe(SubscriptionFilter::all());
// In another thread/task:
for event in rx {
match event {
PubSubEvent::NodeChanged { node_id, snapshot_id } => {
// Read node state at snapshot_id
}
_ => {}
}
}
}Sourcefn unsubscribe(&self, subscriber_id: u64) -> Result<bool, SqliteGraphError>
fn unsubscribe(&self, subscriber_id: u64) -> Result<bool, SqliteGraphError>
Unsubscribe from events
Cancels the subscription and stops receiving events. Returns true if subscription existed and was removed.
§Arguments
subscriber_id- The subscriber ID returned by subscribe()
Sourcefn kv_prefix_scan(
&self,
snapshot_id: SnapshotId,
prefix: &[u8],
) -> Result<Vec<(Vec<u8>, KvValue)>, SqliteGraphError>
fn kv_prefix_scan( &self, snapshot_id: SnapshotId, prefix: &[u8], ) -> Result<Vec<(Vec<u8>, KvValue)>, SqliteGraphError>
Scan all KV entries with a given prefix
Returns all keys that start with the given prefix, along with their values. Results are in lexicographic order by key.
§Arguments
snapshot_id- Only return data committed at or before this snapshotprefix- Prefix to match (empty prefix returns all keys)
§Returns
Vector of (key, value) pairs for all matching keys
Sourcefn query_nodes_by_kind(
&self,
snapshot_id: SnapshotId,
kind: &str,
) -> Result<Vec<i64>, SqliteGraphError>
fn query_nodes_by_kind( &self, snapshot_id: SnapshotId, kind: &str, ) -> Result<Vec<i64>, SqliteGraphError>
Query all nodes with a given kind
Returns all node IDs where the node’s kind equals the given string. Results are sorted by node ID for deterministic output.
§Arguments
snapshot_id- Only return data committed at or before this snapshotkind- Kind string to match (case-sensitive)
§Returns
Vector of node IDs with matching kind
Sourcefn query_nodes_by_name_pattern(
&self,
snapshot_id: SnapshotId,
pattern: &str,
) -> Result<Vec<i64>, SqliteGraphError>
fn query_nodes_by_name_pattern( &self, snapshot_id: SnapshotId, pattern: &str, ) -> Result<Vec<i64>, SqliteGraphError>
Query nodes by name pattern using glob matching
Returns all node IDs where the node’s label matches the glob pattern. Pattern syntax:
*matches any sequence of characters?matches exactly one character
§Arguments
snapshot_id- Only return data committed at or before this snapshotpattern- Glob pattern to match against node labels
§Returns
Vector of node IDs with matching labels
Provided Methods§
Sourcefn all_entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>
fn all_entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>
Alias for entity_ids() for backward compatibility with algorithms
Default implementation delegates to entity_ids().
Sourcefn fetch_outgoing(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError>
fn fetch_outgoing(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError>
Get outgoing neighbors for a node (convenience method)
Default implementation uses neighbors with Outgoing direction.
Sourcefn fetch_incoming(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError>
fn fetch_incoming(&self, node: i64) -> Result<Vec<i64>, SqliteGraphError>
Get incoming neighbors for a node (convenience method)
Default implementation uses neighbors with Incoming direction.
Implementations on Foreign Types§
Source§impl<B> GraphBackend for &Bwhere
B: GraphBackend + ?Sized,
Reference implementation for GraphBackend trait that works with references.
impl<B> GraphBackend for &Bwhere
B: GraphBackend + ?Sized,
Reference implementation for GraphBackend trait that works with references.