pub struct GraphStore { /* private fields */ }Implementations§
Source§impl GraphStore
impl GraphStore
pub fn new(pool: SqlitePool) -> Self
pub fn pool(&self) -> &SqlitePool
Sourcepub async fn upsert_entity(
&self,
surface_name: &str,
canonical_name: &str,
entity_type: EntityType,
summary: Option<&str>,
) -> Result<i64, MemoryError>
pub async fn upsert_entity( &self, surface_name: &str, canonical_name: &str, entity_type: EntityType, summary: Option<&str>, ) -> Result<i64, MemoryError>
Insert or update an entity by (canonical_name, entity_type).
surface_name: the original display form (e.g."Rust") — stored in thenamecolumn so user-facing output preserves casing. Updated on every upsert to the latest seen form.canonical_name: the stable normalized key (e.g."rust") — used for deduplication.summary: passNoneto preserve the existing summary; passSome("")to blank it.
§Errors
Returns an error if the database query fails.
Sourcepub async fn find_entity(
&self,
canonical_name: &str,
entity_type: EntityType,
) -> Result<Option<Entity>, MemoryError>
pub async fn find_entity( &self, canonical_name: &str, entity_type: EntityType, ) -> Result<Option<Entity>, MemoryError>
Find an entity by exact canonical name and type.
§Errors
Returns an error if the database query fails.
Sourcepub async fn find_entity_by_id(
&self,
entity_id: i64,
) -> Result<Option<Entity>, MemoryError>
pub async fn find_entity_by_id( &self, entity_id: i64, ) -> Result<Option<Entity>, MemoryError>
Sourcepub async fn set_entity_qdrant_point_id(
&self,
entity_id: i64,
point_id: &str,
) -> Result<(), MemoryError>
pub async fn set_entity_qdrant_point_id( &self, entity_id: i64, point_id: &str, ) -> Result<(), MemoryError>
Sourcepub async fn find_entities_fuzzy(
&self,
query: &str,
limit: usize,
) -> Result<Vec<Entity>, MemoryError>
pub async fn find_entities_fuzzy( &self, query: &str, limit: usize, ) -> Result<Vec<Entity>, MemoryError>
Find entities matching query in name, summary, or aliases, up to limit results, ranked by relevance.
Uses FTS5 MATCH with prefix wildcards (token*) and bm25 ranking. Name matches are
weighted 10x higher than summary matches. Also searches graph_entity_aliases for
alias matches via a UNION query.
§Behavioral note
This replaces the previous LIKE '%query%' implementation. FTS5 prefix matching differs
from substring matching: searching “SQL” will match “SQLite” (prefix) but NOT “GraphQL”
(substring). Entity names are indexed as single tokens by the unicode61 tokenizer, so
mid-word substrings are not matched. This is a known trade-off for index performance.
Single-character queries (e.g., “a”) are allowed and produce a broad prefix match (“a*”).
The limit parameter caps the result set. No minimum query length is enforced; if this
causes noise in practice, add a minimum length guard at the call site.
§Errors
Returns an error if the database query fails.
Sourcepub fn all_entities_stream(
&self,
) -> impl Stream<Item = Result<Entity, MemoryError>> + '_
pub fn all_entities_stream( &self, ) -> impl Stream<Item = Result<Entity, MemoryError>> + '_
Stream all entities from the database incrementally (true cursor, no full-table load).
Sourcepub async fn add_alias(
&self,
entity_id: i64,
alias_name: &str,
) -> Result<(), MemoryError>
pub async fn add_alias( &self, entity_id: i64, alias_name: &str, ) -> Result<(), MemoryError>
Insert an alias for an entity (idempotent: duplicate alias is silently ignored via UNIQUE constraint).
§Errors
Returns an error if the database query fails.
Sourcepub async fn find_entity_by_alias(
&self,
alias_name: &str,
entity_type: EntityType,
) -> Result<Option<Entity>, MemoryError>
pub async fn find_entity_by_alias( &self, alias_name: &str, entity_type: EntityType, ) -> Result<Option<Entity>, MemoryError>
Find an entity by alias name and entity type (case-insensitive).
Filters by entity_type to avoid cross-type alias collisions (S2 fix).
§Errors
Returns an error if the database query fails.
Sourcepub async fn aliases_for_entity(
&self,
entity_id: i64,
) -> Result<Vec<EntityAlias>, MemoryError>
pub async fn aliases_for_entity( &self, entity_id: i64, ) -> Result<Vec<EntityAlias>, MemoryError>
Sourcepub async fn all_entities(&self) -> Result<Vec<Entity>, MemoryError>
pub async fn all_entities(&self) -> Result<Vec<Entity>, MemoryError>
Collect all entities into a Vec.
§Errors
Returns an error if the database query fails or entity_type parsing fails.
Sourcepub async fn entity_count(&self) -> Result<i64, MemoryError>
pub async fn entity_count(&self) -> Result<i64, MemoryError>
Sourcepub async fn insert_edge(
&self,
source_entity_id: i64,
target_entity_id: i64,
relation: &str,
fact: &str,
confidence: f32,
episode_id: Option<MessageId>,
) -> Result<i64, MemoryError>
pub async fn insert_edge( &self, source_entity_id: i64, target_entity_id: i64, relation: &str, fact: &str, confidence: f32, episode_id: Option<MessageId>, ) -> Result<i64, MemoryError>
Sourcepub async fn invalidate_edge(&self, edge_id: i64) -> Result<(), MemoryError>
pub async fn invalidate_edge(&self, edge_id: i64) -> Result<(), MemoryError>
Mark an edge as invalid (set valid_to and expired_at to now).
§Errors
Returns an error if the database update fails.
Sourcepub async fn edges_for_entity(
&self,
entity_id: i64,
) -> Result<Vec<Edge>, MemoryError>
pub async fn edges_for_entity( &self, entity_id: i64, ) -> Result<Vec<Edge>, MemoryError>
Get all active edges where entity is source or target.
§Errors
Returns an error if the database query fails.
Sourcepub async fn edges_between(
&self,
entity_a: i64,
entity_b: i64,
) -> Result<Vec<Edge>, MemoryError>
pub async fn edges_between( &self, entity_a: i64, entity_b: i64, ) -> Result<Vec<Edge>, MemoryError>
Get all active edges between two entities (both directions).
§Errors
Returns an error if the database query fails.
Sourcepub async fn edges_exact(
&self,
source_entity_id: i64,
target_entity_id: i64,
) -> Result<Vec<Edge>, MemoryError>
pub async fn edges_exact( &self, source_entity_id: i64, target_entity_id: i64, ) -> Result<Vec<Edge>, MemoryError>
Get active edges from source to target in the exact direction (no reverse).
§Errors
Returns an error if the database query fails.
Sourcepub async fn active_edge_count(&self) -> Result<i64, MemoryError>
pub async fn active_edge_count(&self) -> Result<i64, MemoryError>
Sourcepub async fn upsert_community(
&self,
name: &str,
summary: &str,
entity_ids: &[i64],
fingerprint: Option<&str>,
) -> Result<i64, MemoryError>
pub async fn upsert_community( &self, name: &str, summary: &str, entity_ids: &[i64], fingerprint: Option<&str>, ) -> Result<i64, MemoryError>
Insert or update a community by name.
fingerprint is a BLAKE3 hex string computed from sorted entity IDs and
intra-community edge IDs. Pass None to leave the fingerprint unchanged (e.g. when
assign_to_community adds an entity without a full re-detection pass).
§Errors
Returns an error if the database query fails or JSON serialization fails.
Sourcepub async fn community_fingerprints(
&self,
) -> Result<HashMap<String, i64>, MemoryError>
pub async fn community_fingerprints( &self, ) -> Result<HashMap<String, i64>, MemoryError>
Return a map of fingerprint -> community_id for all communities with a non-NULL
fingerprint. Used by detect_communities to skip unchanged partitions.
§Errors
Returns an error if the database query fails.
Sourcepub async fn delete_community_by_id(&self, id: i64) -> Result<(), MemoryError>
pub async fn delete_community_by_id(&self, id: i64) -> Result<(), MemoryError>
Sourcepub async fn clear_community_fingerprint(
&self,
id: i64,
) -> Result<(), MemoryError>
pub async fn clear_community_fingerprint( &self, id: i64, ) -> Result<(), MemoryError>
Set the fingerprint of a community to NULL, invalidating the incremental cache.
Used by assign_to_community when an entity is added without a full re-detection pass,
ensuring the next detect_communities run re-summarizes the affected community.
§Errors
Returns an error if the database query fails.
Sourcepub async fn community_for_entity(
&self,
entity_id: i64,
) -> Result<Option<Community>, MemoryError>
pub async fn community_for_entity( &self, entity_id: i64, ) -> Result<Option<Community>, MemoryError>
Find the first community that contains the given entity_id.
Uses json_each() to push the membership search into SQLite, avoiding a full
table scan with per-row JSON parsing.
§Errors
Returns an error if the database query fails or JSON parsing fails.
Sourcepub async fn all_communities(&self) -> Result<Vec<Community>, MemoryError>
pub async fn all_communities(&self) -> Result<Vec<Community>, MemoryError>
Sourcepub async fn community_count(&self) -> Result<i64, MemoryError>
pub async fn community_count(&self) -> Result<i64, MemoryError>
Sourcepub async fn get_metadata(
&self,
key: &str,
) -> Result<Option<String>, MemoryError>
pub async fn get_metadata( &self, key: &str, ) -> Result<Option<String>, MemoryError>
Sourcepub async fn set_metadata(
&self,
key: &str,
value: &str,
) -> Result<(), MemoryError>
pub async fn set_metadata( &self, key: &str, value: &str, ) -> Result<(), MemoryError>
Sourcepub async fn extraction_count(&self) -> Result<i64, MemoryError>
pub async fn extraction_count(&self) -> Result<i64, MemoryError>
Get the current extraction count from metadata.
Returns 0 if the counter has not been initialized.
§Errors
Returns an error if the database query fails.
Sourcepub fn all_active_edges_stream(
&self,
) -> impl Stream<Item = Result<Edge, MemoryError>> + '_
pub fn all_active_edges_stream( &self, ) -> impl Stream<Item = Result<Edge, MemoryError>> + '_
Stream all active (non-invalidated) edges.
Sourcepub async fn find_community_by_id(
&self,
id: i64,
) -> Result<Option<Community>, MemoryError>
pub async fn find_community_by_id( &self, id: i64, ) -> Result<Option<Community>, MemoryError>
Find a community by its primary key.
§Errors
Returns an error if the database query fails or JSON parsing fails.
Sourcepub async fn delete_all_communities(&self) -> Result<(), MemoryError>
pub async fn delete_all_communities(&self) -> Result<(), MemoryError>
Delete all communities (full rebuild before upsert).
§Errors
Returns an error if the database query fails.
Sourcepub async fn delete_expired_edges(
&self,
retention_days: u32,
) -> Result<usize, MemoryError>
pub async fn delete_expired_edges( &self, retention_days: u32, ) -> Result<usize, MemoryError>
Delete expired edges older than retention_days and return count deleted.
§Errors
Returns an error if the database query fails.
Sourcepub async fn delete_orphan_entities(
&self,
retention_days: u32,
) -> Result<usize, MemoryError>
pub async fn delete_orphan_entities( &self, retention_days: u32, ) -> Result<usize, MemoryError>
Delete orphan entities (no active edges, last seen more than retention_days ago).
§Errors
Returns an error if the database query fails.
Sourcepub async fn cap_entities(
&self,
max_entities: usize,
) -> Result<usize, MemoryError>
pub async fn cap_entities( &self, max_entities: usize, ) -> Result<usize, MemoryError>
Delete the oldest excess entities when count exceeds max_entities.
Entities are ranked by ascending edge count, then ascending last_seen_at (LRU).
Only deletes when entity_count() > max_entities.
§Errors
Returns an error if the database query fails.
Sourcepub async fn bfs(
&self,
start_entity_id: i64,
max_hops: u32,
) -> Result<(Vec<Entity>, Vec<Edge>), MemoryError>
pub async fn bfs( &self, start_entity_id: i64, max_hops: u32, ) -> Result<(Vec<Entity>, Vec<Edge>), MemoryError>
Breadth-first traversal from start_entity_id up to max_hops hops.
Returns all reachable entities and the active edges connecting them.
Implements BFS iteratively in Rust to guarantee cycle safety regardless
of SQLite CTE limitations.
SQLite bind parameter limit: each BFS hop binds the frontier IDs three times in the
neighbour query. At ~300+ frontier entities per hop, the IN clause may approach SQLite’s
default SQLITE_MAX_VARIABLE_NUMBER limit of 999. Acceptable for Phase 1 (small graphs,
max_hops typically 2–3). For large graphs, consider batching or a temp-table approach.
§Errors
Returns an error if any database query fails.
Sourcepub async fn bfs_with_depth(
&self,
start_entity_id: i64,
max_hops: u32,
) -> Result<(Vec<Entity>, Vec<Edge>, HashMap<i64, u32>), MemoryError>
pub async fn bfs_with_depth( &self, start_entity_id: i64, max_hops: u32, ) -> Result<(Vec<Entity>, Vec<Edge>, HashMap<i64, u32>), MemoryError>
BFS traversal returning entities, edges, and a depth map (entity_id → hop distance).
The depth map records the minimum hop distance from start_entity_id to each visited
entity. The start entity itself has depth 0.
SQLite bind parameter limit: see [bfs] for notes on frontier size limits.
§Errors
Returns an error if any database query fails.
Sourcepub async fn find_entity_by_name(
&self,
name: &str,
) -> Result<Vec<Entity>, MemoryError>
pub async fn find_entity_by_name( &self, name: &str, ) -> Result<Vec<Entity>, MemoryError>
Find an entity by name only (no type filter). Uses FTS5 prefix search with alias fallback.
This is a convenience wrapper around find_entities_fuzzy returning the best match.
§Errors
Returns an error if the database query fails.
Sourcepub async fn unprocessed_messages_for_backfill(
&self,
limit: usize,
) -> Result<Vec<(MessageId, String)>, MemoryError>
pub async fn unprocessed_messages_for_backfill( &self, limit: usize, ) -> Result<Vec<(MessageId, String)>, MemoryError>
Return up to limit messages that have not yet been processed by graph extraction.
Reads the graph_processed column added by migration 021.
§Errors
Returns an error if the database query fails.
Sourcepub async fn unprocessed_message_count(&self) -> Result<i64, MemoryError>
pub async fn unprocessed_message_count(&self) -> Result<i64, MemoryError>
Return the count of messages not yet processed by graph extraction.
§Errors
Returns an error if the database query fails.
Sourcepub async fn mark_messages_graph_processed(
&self,
ids: &[MessageId],
) -> Result<(), MemoryError>
pub async fn mark_messages_graph_processed( &self, ids: &[MessageId], ) -> Result<(), MemoryError>
Auto Trait Implementations§
impl Freeze for GraphStore
impl !RefUnwindSafe for GraphStore
impl Send for GraphStore
impl Sync for GraphStore
impl Unpin for GraphStore
impl UnsafeUnpin for GraphStore
impl !UnwindSafe for GraphStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request