Skip to main content

GraphStore

Trait GraphStore 

Source
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§

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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).

Source

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.

Source

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.

Source

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§

Source

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.

Source

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.

Source

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.

Source

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.

Source

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".

Implementors§