pub trait GraphStore:
Send
+ Sync
+ 'static {
Show 17 methods
// Required methods
fn upsert_edge<'life0, 'async_trait>(
&'life0 self,
edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn upsert_edges<'life0, 'async_trait>(
&'life0 self,
edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<BatchWriteSummary>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_edge_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn delete_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = StorageResult<bool>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn query_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Page<Edge>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn count_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn count_edges_by_relation<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(EdgeRelation, u64)>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn query_edges_after<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
after: Option<Uuid>,
limit: u32,
) -> Pin<Box<dyn Future<Output = StorageResult<EdgeSeekPage>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn neighbors<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<NeighborHit>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn traverse<'life0, 'async_trait>(
&'life0 self,
request: TraversalRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<GraphPath>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn purge_incident_edges<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided methods
fn upsert_edge_guarded<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedWriteOutcome>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn upsert_edges_guarded<'life0, 'async_trait>(
&'life0 self,
_edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedBatchOutcome>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn neighbors_both_directions<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<DirectedNeighborHit>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn get_edges<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<Edge>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn batch_neighbors<'life0, 'life1, 'async_trait>(
&'life0 self,
sources: &'life1 [Uuid],
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(Uuid, NeighborHit)>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}Expand description
Directed edge CRUD and graph traversal over the knowledge graph.
Required Methods§
Sourcefn upsert_edge<'life0, 'async_trait>(
&'life0 self,
edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn upsert_edge<'life0, 'async_trait>(
&'life0 self,
edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Insert or update a single edge.
Sourcefn upsert_edges<'life0, 'async_trait>(
&'life0 self,
edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<BatchWriteSummary>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn upsert_edges<'life0, 'async_trait>(
&'life0 self,
edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<BatchWriteSummary>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Insert or update a batch of edges.
Sourcefn get_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Fetch an edge by link ID, returning None if absent. Filters soft-deleted rows.
Sourcefn get_edge_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_edge_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = StorageResult<Option<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Fetch an edge by link ID including soft-deleted rows. Used by the runtime hard-delete path to locate and namespace-check an already-soft-deleted edge before purging it.
Sourcefn delete_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = StorageResult<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn delete_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = StorageResult<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Delete an edge by link ID using the specified delete mode.
Sourcefn query_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Page<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn query_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Page<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Query edges with filter, sort, and pagination.
Sourcefn count_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn count_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Count edges matching the given filter.
Sourcefn count_edges_by_relation<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(EdgeRelation, u64)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn count_edges_by_relation<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(EdgeRelation, u64)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Count edges grouped by relation, ignoring soft-deleted rows. Cheap
aggregate (GROUP BY relation) used to report the true per-relation
population for full-graph audits (#702.3).
Sourcefn query_edges_after<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
after: Option<Uuid>,
limit: u32,
) -> Pin<Box<dyn Future<Output = StorageResult<EdgeSeekPage>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn query_edges_after<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
after: Option<Uuid>,
limit: u32,
) -> Pin<Box<dyn Future<Output = StorageResult<EdgeSeekPage>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Seek-pagination page of edges ordered by id ascending, using an
indexed range scan (id > after) against the (namespace, id)
primary key instead of OFFSET. after is exclusive; None starts
from the beginning of the set. Stable under concurrent writes and
O(log n + limit) at any depth, unlike offset paging (#702.2).
Sourcefn neighbors<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<NeighborHit>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn neighbors<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<NeighborHit>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Return immediate neighbors of a graph node.
Sourcefn traverse<'life0, 'async_trait>(
&'life0 self,
request: TraversalRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<GraphPath>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn traverse<'life0, 'async_trait>(
&'life0 self,
request: TraversalRequest,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<GraphPath>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Multi-hop BFS traversal from the given roots.
Sourcefn purge_incident_edges<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn purge_incident_edges<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
) -> Pin<Box<dyn Future<Output = StorageResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Hard-delete every incident edge (source or target) for node_id, regardless of soft-delete
state. Used during endpoint hard-delete to prevent dangling graph_edges rows (ADR-002
no-dangling-references contract).
Provided Methods§
Sourcefn upsert_edge_guarded<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedWriteOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn upsert_edge_guarded<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedWriteOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Insert or update a single edge, re-checking that both endpoints still exist (and are not soft-deleted) as part of the same write, not a separate prior read. Closes the TOCTOU window between an async prepare-time existence check and a later, unconditional write: a concurrent hard-delete of an endpoint that lands between the two can otherwise leave a durably dangling edge (#769).
Returns GuardedWriteOutcome::Refused naming exactly which
endpoint(s) were missing, determined by the guard’s own in-transaction
probe — never reconstructed by a caller re-reading the endpoints after
the write already failed, since a concurrent write landing between the
refusal and any such later read could misreport which endpoint was
actually missing at write time (round-2 codex Medium 1).
Default returns StorageError::Unsupported: a backend that does not
override this method cannot honor the endpoint-existence guarantee,
and silently falling back to GraphStore::upsert_edge would
reintroduce the TOCTOU window this method exists to close.
Sourcefn upsert_edges_guarded<'life0, 'async_trait>(
&'life0 self,
_edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedBatchOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn upsert_edges_guarded<'life0, 'async_trait>(
&'life0 self,
_edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = StorageResult<GuardedBatchOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Batch form of GraphStore::upsert_edge_guarded. All-or-nothing:
if any edge’s endpoints are missing at write time, no edge from the
batch is persisted, BatchWriteSummary::affected is 0, and
GuardedBatchOutcome::refused names the first failing batch entry and
its missing endpoint(s) — determined by the same in-transaction
pre-check that aborted the batch, not a post-hoc re-read.
Default returns StorageError::Unsupported, for the same reason as
GraphStore::upsert_edge_guarded’s default.
Sourcefn neighbors_both_directions<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<DirectedNeighborHit>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn neighbors_both_directions<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<DirectedNeighborHit>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Return neighbors in BOTH directions in a single call, each tagged with
the direction (Out/In) it was found in. query.direction is
ignored — this always fetches both directions.
Exists so a caller that needs both-direction neighbors labeled by
direction (e.g. the context verb) can do so with one storage query
instead of two separate direction-scoped neighbors calls. The
default implementation preserves the original two-call behavior for
backends that don’t override it; SqlGraphStore overrides this with a
single UNION ALL query that projects a direction literal per arm.
Sourcefn get_edges<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_edges<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<Edge>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Fetch multiple edges by their link IDs in a single round-trip.
IDs that are not found (absent or soft-deleted) are silently skipped;
the returned Vec may be shorter than ids. Backends that support
batched IN (...) queries should override this; the default loops
get_edge so non-SQLite backends keep compiling unchanged.
Callers must chunk large ID lists before calling if they need a strict size bound; this method does not enforce a maximum.
Sourcefn batch_neighbors<'life0, 'life1, 'async_trait>(
&'life0 self,
sources: &'life1 [Uuid],
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(Uuid, NeighborHit)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn batch_neighbors<'life0, 'life1, 'async_trait>(
&'life0 self,
sources: &'life1 [Uuid],
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = StorageResult<Vec<(Uuid, NeighborHit)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Return neighbors for multiple source nodes in a single round-trip,
yielding (source_id, hit) pairs.
The query parameters (direction, relations, min_weight) are applied
uniformly to every source node. query.limit is applied per source:
each source returns at most limit hits. Backends that support batched
source_id IN (...) queries should override this; the default loops
neighbors so non-SQLite backends keep compiling unchanged.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".