raphtory 0.17.0

raphtory, a temporal graph library
Documentation
use crate::{
    core::storage::timeindex::EventTime,
    db::{
        api::view::internal::*,
        graph::{graph::Graph, views::deletion_graph::PersistentGraph},
    },
    prelude::*,
};
use raphtory_api::{iter::BoxedLDIter, GraphType};
use raphtory_storage::{graph::graph::GraphStorage, mutation::InheritMutationOps};
use serde::{Deserialize, Serialize};
use std::ops::Range;

#[derive(Serialize, Deserialize, Clone)]
pub enum MaterializedGraph {
    EventGraph(Graph),
    PersistentGraph(PersistentGraph),
}

macro_rules! for_all {
    ($value:expr, $pattern:pat => $result:expr) => {
        match $value {
            MaterializedGraph::EventGraph($pattern) => $result,
            MaterializedGraph::PersistentGraph($pattern) => $result,
        }
    };
}

impl From<Graph> for MaterializedGraph {
    fn from(value: Graph) -> Self {
        MaterializedGraph::EventGraph(value)
    }
}

impl From<PersistentGraph> for MaterializedGraph {
    fn from(value: PersistentGraph) -> Self {
        MaterializedGraph::PersistentGraph(value)
    }
}

impl Base for MaterializedGraph {
    type Base = Arc<Storage>;

    fn base(&self) -> &Self::Base {
        match self {
            MaterializedGraph::EventGraph(g) => &g.inner,
            MaterializedGraph::PersistentGraph(g) => &g.0,
        }
    }
}

impl InheritCoreGraphOps for MaterializedGraph {}
impl InheritLayerOps for MaterializedGraph {}
impl InheritListOps for MaterializedGraph {}

impl InheritPropertiesOps for MaterializedGraph {}

impl InheritNodeFilterOps for MaterializedGraph {}
impl InheritAllEdgeFilterOps for MaterializedGraph {}

impl InternalMaterialize for MaterializedGraph {
    fn graph_type(&self) -> GraphType {
        match self {
            MaterializedGraph::EventGraph(_) => GraphType::EventGraph,
            MaterializedGraph::PersistentGraph(_) => GraphType::PersistentGraph,
        }
    }
}

impl InheritMutationOps for MaterializedGraph {}

impl Debug for MaterializedGraph {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let mut builder = f.debug_tuple("MaterializedGraph");
        for_all!(self, g => builder.field(g)).finish()
    }
}

impl Static for MaterializedGraph {}

impl MaterializedGraph {
    pub fn into_events(self) -> Option<Graph> {
        match self {
            MaterializedGraph::EventGraph(g) => Some(g),
            MaterializedGraph::PersistentGraph(_) => None,
        }
    }
    pub fn into_persistent(self) -> Option<PersistentGraph> {
        match self {
            MaterializedGraph::EventGraph(_) => None,
            MaterializedGraph::PersistentGraph(g) => Some(g),
        }
    }
}

impl InternalStorageOps for MaterializedGraph {
    fn get_storage(&self) -> Option<&Storage> {
        for_all!(self, g => g.get_storage())
    }
}

impl GraphTimeSemanticsOps for MaterializedGraph {
    fn node_time_semantics(&self) -> TimeSemantics {
        for_all!(self, g => g.node_time_semantics())
    }

    fn edge_time_semantics(&self) -> TimeSemantics {
        for_all!(self, g => g.edge_time_semantics())
    }

    fn view_start(&self) -> Option<EventTime> {
        for_all!(self, g => g.view_start())
    }

    fn view_end(&self) -> Option<EventTime> {
        for_all!(self, g => g.view_end())
    }

    fn earliest_time_global(&self) -> Option<i64> {
        for_all!(self, g => g.earliest_time_global())
    }

    fn latest_time_global(&self) -> Option<i64> {
        for_all!(self, g => g.latest_time_global())
    }

    fn earliest_time_window(&self, start: EventTime, end: EventTime) -> Option<i64> {
        for_all!(self, g => g.earliest_time_window(start, end))
    }

    fn latest_time_window(&self, start: EventTime, end: EventTime) -> Option<i64> {
        for_all!(self, g => g.latest_time_window(start, end))
    }

    fn has_temporal_prop(&self, prop_id: usize) -> bool {
        for_all!(self, g => g.has_temporal_prop(prop_id))
    }

    fn temporal_prop_iter(&self, prop_id: usize) -> BoxedLDIter<'_, (EventTime, Prop)> {
        for_all!(self, g => g.temporal_prop_iter(prop_id))
    }

    fn has_temporal_prop_window(&self, prop_id: usize, w: Range<EventTime>) -> bool {
        for_all!(self, g => g.has_temporal_prop_window(prop_id, w))
    }

    fn temporal_prop_iter_window(
        &self,
        prop_id: usize,
        start: EventTime,
        end: EventTime,
    ) -> BoxedLDIter<'_, (EventTime, Prop)> {
        for_all!(self, g => g.temporal_prop_iter_window(prop_id, start, end))
    }

    fn temporal_prop_last_at(&self, prop_id: usize, t: EventTime) -> Option<(EventTime, Prop)> {
        for_all!(self, g => g.temporal_prop_last_at(prop_id, t))
    }

    fn temporal_prop_last_at_window(
        &self,
        prop_id: usize,
        t: EventTime,
        w: Range<EventTime>,
    ) -> Option<(EventTime, Prop)> {
        for_all!(self, g => g.temporal_prop_last_at_window(prop_id, t, w))
    }
}

pub trait InternalMaterialize {
    fn new_base_graph(&self, graph: GraphStorage) -> MaterializedGraph {
        match self.graph_type() {
            GraphType::EventGraph => {
                MaterializedGraph::EventGraph(Graph::from_internal_graph(graph))
            }
            GraphType::PersistentGraph => {
                MaterializedGraph::PersistentGraph(PersistentGraph::from_internal_graph(graph))
            }
        }
    }

    fn graph_type(&self) -> GraphType;
}

pub trait InheritMaterialize: Base {}

impl<G: InheritMaterialize> InternalMaterialize for G
where
    G::Base: InternalMaterialize,
{
    #[inline]
    fn new_base_graph(&self, graph: GraphStorage) -> MaterializedGraph {
        self.base().new_base_graph(graph)
    }

    #[inline]
    fn graph_type(&self) -> GraphType {
        self.base().graph_type()
    }
}

#[cfg(test)]
mod test_materialised_graph_dispatch {
    use crate::{
        core::entities::LayerIds,
        db::api::view::internal::{
            GraphTimeSemanticsOps, InternalEdgeFilterOps, InternalLayerOps, MaterializedGraph,
        },
        prelude::*,
    };
    use raphtory_api::core::entities::GID;
    use raphtory_storage::core_ops::CoreGraphOps;

    #[test]
    fn materialised_graph_has_core_ops() {
        let mg = MaterializedGraph::from(Graph::new());
        assert_eq!(mg.unfiltered_num_nodes(), 0);
    }

    #[test]
    fn materialised_graph_has_graph_ops() {
        let mg = MaterializedGraph::from(Graph::new());
        assert_eq!(mg.count_nodes(), 0);
    }

    #[test]
    fn materialised_graph_has_edge_filter_ops() {
        let mg = MaterializedGraph::from(Graph::new());
        assert!(!mg.internal_edge_filtered());
    }

    #[test]
    fn materialised_graph_has_layer_ops() {
        let mg = MaterializedGraph::from(Graph::new());
        assert!(matches!(mg.layer_ids(), LayerIds::All));
    }

    #[test]
    fn materialised_graph_has_time_semantics() {
        let mg = MaterializedGraph::from(Graph::new());
        assert!(mg.view_start().is_none());
    }

    #[test]
    fn materialised_graph_can_be_used_directly() {
        let g = Graph::new();

        let mg = g.materialize().unwrap();

        let v = mg.add_node(0, 1, NO_PROPS, None).unwrap();
        assert_eq!(v.id(), GID::U64(1))
    }
}