kmp-domain 0.11.0

Domain model of the Kernel Memory Protocol: aggregates, value objects, repositories and projections, with no IO
Documentation
use std::future::Future;
use std::sync::Arc;

use crate::{ContextPathNeighborhood, NeighborhoodRequest, NodeNeighborhood, PortError};

pub trait GraphNeighborhoodReader {
    fn load_neighborhood(
        &self,
        root_node_id: &str,
        depth: u32,
    ) -> impl Future<Output = Result<Option<NodeNeighborhood>, PortError>> + Send;

    /// Loads a neighbourhood already narrowed by the axes the caller resolved.
    ///
    /// The application resolves the dimension axis into fully namespaced scope
    /// ids before it asks for anything, and until this existed it carried them
    /// as far as the query and then filtered the bundle after materialising it
    /// whole. Handing them down lets a store that can narrow do so.
    ///
    /// The narrowing is a hint and never a contract: the default ignores it,
    /// which leaves an adapter correct and only slow, and the application
    /// filters what comes back either way. That is what makes adopting this
    /// one adapter at a time a pure performance change.
    fn load_scoped_neighborhood(
        &self,
        request: &NeighborhoodRequest,
    ) -> impl Future<Output = Result<Option<NodeNeighborhood>, PortError>> + Send {
        self.load_neighborhood(request.root_node_id(), request.depth())
    }

    fn load_context_path(
        &self,
        root_node_id: &str,
        target_node_id: &str,
        subtree_depth: u32,
    ) -> impl Future<Output = Result<Option<ContextPathNeighborhood>, PortError>> + Send;
}

impl<T> GraphNeighborhoodReader for Arc<T>
where
    T: GraphNeighborhoodReader + Send + Sync + ?Sized,
{
    async fn load_neighborhood(
        &self,
        root_node_id: &str,
        depth: u32,
    ) -> Result<Option<NodeNeighborhood>, PortError> {
        self.as_ref().load_neighborhood(root_node_id, depth).await
    }

    async fn load_scoped_neighborhood(
        &self,
        request: &NeighborhoodRequest,
    ) -> Result<Option<NodeNeighborhood>, PortError> {
        self.as_ref().load_scoped_neighborhood(request).await
    }

    async fn load_context_path(
        &self,
        root_node_id: &str,
        target_node_id: &str,
        subtree_depth: u32,
    ) -> Result<Option<ContextPathNeighborhood>, PortError> {
        self.as_ref()
            .load_context_path(root_node_id, target_node_id, subtree_depth)
            .await
    }
}

impl<T> GraphNeighborhoodReader for &T
where
    T: GraphNeighborhoodReader + Send + Sync + ?Sized,
{
    async fn load_neighborhood(
        &self,
        root_node_id: &str,
        depth: u32,
    ) -> Result<Option<NodeNeighborhood>, PortError> {
        (*self).load_neighborhood(root_node_id, depth).await
    }

    async fn load_context_path(
        &self,
        root_node_id: &str,
        target_node_id: &str,
        subtree_depth: u32,
    ) -> Result<Option<ContextPathNeighborhood>, PortError> {
        (*self)
            .load_context_path(root_node_id, target_node_id, subtree_depth)
            .await
    }
}