khive-db 0.12.0

SQLite storage backend: entities, edges, notes, events, FTS5, sqlite-vec vectors.
Documentation
use super::super::StorageBackend;
use super::map_open_error;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use khive_storage::graph::{
    CommitAnnotationGuard, CommitAnnotationInsertOutcome, GraphStore, SymmetricEdgeUpdateOutcome,
    SymmetricEdgeUpdateRequest,
};
use khive_storage::types::EdgeEndpointBaseCounts;
use khive_storage::{
    BatchWriteSummary, DeleteMode, DirectedNeighborHit, Edge, EdgeFilter, EdgeSeekPage,
    EdgeSortField, EdgeUpsertRequest, EdgeUpsertResult, GraphPath, GuardedBatchOutcome,
    GuardedEdgeBatchUpsertOutcome, GuardedEdgeUpsertOutcome, GuardedWriteOutcome, LinkId,
    NeighborCursor, NeighborHit, NeighborQuery, Page, PageRequest, SeekCursor, SeekPage, SortOrder,
    StorageCapability, StorageResult, TraversalRequest,
};
use khive_types::EdgeRelation;
use uuid::Uuid;

#[async_trait]
impl GraphStore for StorageBackend {
    async fn latest_annotating_note(
        &self,
        _node_id: Uuid,
        _kind: &str,
        _tag: &str,
    ) -> StorageResult<Option<(Uuid, i64)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .latest_annotating_note(_node_id, _kind, _tag)
            .await
    }

    async fn latest_annotating_note_with_property(
        &self,
        _node_id: Uuid,
        _kind: &str,
        _tag: &str,
        _property_key: &str,
        _property_value: &str,
    ) -> StorageResult<Option<(Uuid, i64)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .latest_annotating_note_with_property(
                _node_id,
                _kind,
                _tag,
                _property_key,
                _property_value,
            )
            .await
    }

    async fn upsert_edge(&self, edge: Edge) -> StorageResult<()> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edge(edge)
            .await
    }

    async fn insert_edge_if_absent(&self, _edge: Edge) -> StorageResult<bool> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .insert_edge_if_absent(_edge)
            .await
    }

    async fn insert_commit_annotation_if_absent(
        &self,
        _edge: Edge,
        _guard: CommitAnnotationGuard,
    ) -> StorageResult<CommitAnnotationInsertOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .insert_commit_annotation_if_absent(_edge, _guard)
            .await
    }

    async fn upsert_edges(&self, edges: Vec<Edge>) -> StorageResult<BatchWriteSummary> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edges(edges)
            .await
    }

    async fn upsert_edge_observed(
        &self,
        _request: EdgeUpsertRequest,
    ) -> StorageResult<EdgeUpsertResult> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edge_observed(_request)
            .await
    }

    async fn replace_edge_if_unchanged(
        &self,
        _edge: Edge,
        _expected_updated_at: DateTime<Utc>,
        _expected_deleted_at: Option<DateTime<Utc>>,
    ) -> StorageResult<bool> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .replace_edge_if_unchanged(_edge, _expected_updated_at, _expected_deleted_at)
            .await
    }

    async fn update_symmetric_edge_if_unchanged(
        &self,
        _request: SymmetricEdgeUpdateRequest,
    ) -> StorageResult<SymmetricEdgeUpdateOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .update_symmetric_edge_if_unchanged(_request)
            .await
    }

    async fn upsert_edge_guarded(&self, _edge: Edge) -> StorageResult<GuardedWriteOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edge_guarded(_edge)
            .await
    }

    async fn upsert_edge_guarded_observed(
        &self,
        _request: EdgeUpsertRequest,
    ) -> StorageResult<GuardedEdgeUpsertOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edge_guarded_observed(_request)
            .await
    }

    async fn upsert_edges_guarded(&self, _edges: Vec<Edge>) -> StorageResult<GuardedBatchOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edges_guarded(_edges)
            .await
    }

    async fn upsert_edges_guarded_observed(
        &self,
        _requests: Vec<EdgeUpsertRequest>,
    ) -> StorageResult<GuardedEdgeBatchUpsertOutcome> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .upsert_edges_guarded_observed(_requests)
            .await
    }

    async fn get_edge(&self, id: LinkId) -> StorageResult<Option<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .get_edge(id)
            .await
    }

    async fn get_edge_including_deleted(&self, id: LinkId) -> StorageResult<Option<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .get_edge_including_deleted(id)
            .await
    }

    async fn get_edge_by_natural_key_including_deleted(
        &self,
        namespace: &str,
        source_id: Uuid,
        target_id: Uuid,
        relation: EdgeRelation,
    ) -> StorageResult<Option<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .get_edge_by_natural_key_including_deleted(namespace, source_id, target_id, relation)
            .await
    }

    async fn delete_edge(&self, id: LinkId, mode: DeleteMode) -> StorageResult<bool> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .delete_edge(id, mode)
            .await
    }

    async fn query_edges(
        &self,
        filter: EdgeFilter,
        sort: Vec<SortOrder<EdgeSortField>>,
        page: PageRequest,
    ) -> StorageResult<Page<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .query_edges(filter, sort, page)
            .await
    }

    async fn query_edges_in_namespaces(
        &self,
        namespaces: &[String],
        filter: EdgeFilter,
        sort: Vec<SortOrder<EdgeSortField>>,
        page: PageRequest,
    ) -> StorageResult<Page<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .query_edges_in_namespaces(namespaces, filter, sort, page)
            .await
    }

    async fn count_edges(&self, filter: EdgeFilter) -> StorageResult<u64> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges(filter)
            .await
    }

    async fn count_edges_in_namespaces(
        &self,
        namespaces: &[String],
        filter: EdgeFilter,
    ) -> StorageResult<u64> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_in_namespaces(namespaces, filter)
            .await
    }

    async fn count_edges_by_relation(&self) -> StorageResult<Vec<(EdgeRelation, u64)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_by_relation()
            .await
    }

    async fn count_edges_by_relation_in_namespaces(
        &self,
        namespaces: &[String],
    ) -> StorageResult<Vec<(EdgeRelation, u64)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_by_relation_in_namespaces(namespaces)
            .await
    }

    async fn count_edges_by_endpoint_base(&self) -> StorageResult<EdgeEndpointBaseCounts> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_by_endpoint_base()
            .await
    }

    async fn count_edges_by_endpoint_base_in_namespaces(
        &self,
        namespaces: &[String],
    ) -> StorageResult<EdgeEndpointBaseCounts> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_by_endpoint_base_in_namespaces(namespaces)
            .await
    }

    async fn count_edges_by_relation_and_endpoint_base_in_namespaces(
        &self,
        namespaces: &[String],
    ) -> StorageResult<Vec<(EdgeRelation, EdgeEndpointBaseCounts)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .count_edges_by_relation_and_endpoint_base_in_namespaces(namespaces)
            .await
    }

    async fn query_edges_after(
        &self,
        filter: EdgeFilter,
        after: Option<Uuid>,
        limit: u32,
    ) -> StorageResult<EdgeSeekPage> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .query_edges_after(filter, after, limit)
            .await
    }

    async fn edge_sequence(&self, _id: Uuid) -> StorageResult<Option<i64>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .edge_sequence(_id)
            .await
    }

    async fn edge_sequences(&self, ids: &[Uuid]) -> StorageResult<Vec<(Uuid, i64)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .edge_sequences(ids)
            .await
    }

    async fn query_edges_sequence_after(
        &self,
        _filter: EdgeFilter,
        _after: Option<SeekCursor>,
        _limit: u32,
    ) -> StorageResult<SeekPage<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .query_edges_sequence_after(_filter, _after, _limit)
            .await
    }

    async fn neighbors(
        &self,
        node_id: Uuid,
        query: NeighborQuery,
    ) -> StorageResult<Vec<NeighborHit>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .neighbors(node_id, query)
            .await
    }

    async fn neighbors_page(
        &self,
        node_id: Uuid,
        query: NeighborQuery,
        after: Option<NeighborCursor>,
        neighbor_kinds: Option<Vec<String>>,
    ) -> StorageResult<Vec<NeighborHit>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .neighbors_page(node_id, query, after, neighbor_kinds)
            .await
    }

    async fn neighbors_both_directions(
        &self,
        node_id: Uuid,
        query: NeighborQuery,
    ) -> StorageResult<Vec<DirectedNeighborHit>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .neighbors_both_directions(node_id, query)
            .await
    }

    async fn get_edges(&self, ids: &[LinkId]) -> StorageResult<Vec<Edge>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .get_edges(ids)
            .await
    }

    async fn get_edge_read_outcomes(
        &self,
        ids: &[LinkId],
    ) -> StorageResult<Vec<StorageResult<Option<Edge>>>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .get_edge_read_outcomes(ids)
            .await
    }

    async fn batch_neighbors(
        &self,
        sources: &[Uuid],
        query: NeighborQuery,
    ) -> StorageResult<Vec<(Uuid, NeighborHit)>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .batch_neighbors(sources, query)
            .await
    }

    async fn traverse(&self, request: TraversalRequest) -> StorageResult<Vec<GraphPath>> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .traverse(request)
            .await
    }

    async fn purge_incident_edges(&self, node_id: Uuid) -> StorageResult<u64> {
        self.graph()
            .map_err(|error| map_open_error(error, StorageCapability::Graph, "graph"))?
            .purge_incident_edges(node_id)
            .await
    }
}