Skip to main content

mnemo_graph/store/
mod.rs

1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use thiserror::Error;
4use uuid::Uuid;
5
6use crate::model::TemporalEdge;
7
8pub mod duckdb;
9
10#[derive(Debug, Error)]
11pub enum Error {
12    #[error("graph store: {0}")]
13    Store(String),
14    #[error("graph store: serde error: {0}")]
15    Serde(#[from] serde_json::Error),
16}
17
18impl From<::duckdb::Error> for Error {
19    fn from(e: ::duckdb::Error) -> Self {
20        Error::Store(e.to_string())
21    }
22}
23
24pub type Result<T> = std::result::Result<T, Error>;
25
26/// Persistent home for [`TemporalEdge`] rows.
27///
28/// Today the only impl is [`duckdb::DuckGraphStore`]. The trait stays
29/// minimal on purpose — we add methods only when retrieval needs them
30/// rather than guessing.
31#[async_trait]
32pub trait GraphStore: Send + Sync {
33    /// Persist `edge` (or upsert if `edge.id` already exists).
34    async fn insert_edge(&self, edge: &TemporalEdge) -> Result<()>;
35
36    /// Close the validity window of `edge_id` at `closed_at` — i.e.
37    /// "as of this moment we no longer believe the relation is true".
38    /// Idempotent: closing an already-closed edge no-ops.
39    async fn close_edge(&self, edge_id: Uuid, closed_at: DateTime<Utc>) -> Result<()>;
40
41    /// Edges leaving `node` that are valid at `as_of`. Used by the
42    /// BFS in [`crate::graph_expand`].
43    async fn outgoing_at(&self, node: Uuid, as_of: DateTime<Utc>) -> Result<Vec<TemporalEdge>>;
44
45    /// Every edge in the store — for tests and admin tooling. Not
46    /// suitable for hot-path retrieval; production walkers should
47    /// stick to [`outgoing_at`].
48    async fn all_edges(&self) -> Result<Vec<TemporalEdge>>;
49}