simple-triplestore 0.1.1

A simple graph database for storing triples with support for custom node and edge properties.
Documentation
use std::collections::BTreeMap;

use crate::{
    prelude::*,
    traits::{IdType, Property},
    EdgeOrder, PropsTriple, Triple,
};

use super::MemTripleStore;

impl<Id: IdType, NodeProps: Property, EdgeProps: Property>
    MemTripleStore<Id, NodeProps, EdgeProps>
{
    fn iter_impl(
        node_props: &BTreeMap<Id, NodeProps>,
        edge_props: &BTreeMap<Id, EdgeProps>,
        triple: Triple<Id>,
        v: &Id,
    ) -> Option<Result<PropsTriple<Id, NodeProps, EdgeProps>, ()>> {
        let sub_data = node_props.get(&triple.sub).cloned();
        let pred_data = edge_props.get(v).cloned();
        let obj_data = node_props.get(&triple.obj).cloned();

        match (sub_data, pred_data, obj_data) {
            (Some(sub_props), Some(prod_props), Some(obj_props)) => Some(Ok(PropsTriple {
                sub: (triple.sub, sub_props),
                pred: (triple.pred, prod_props),
                obj: (triple.obj, obj_props),
            })),
            _ => None,
        }
    }
}

impl<Id: IdType, NodeProps: Property, EdgeProps: Property> TripleStoreIter<Id, NodeProps, EdgeProps>
    for MemTripleStore<Id, NodeProps, EdgeProps>
{
    fn vertices(&self) -> Result<impl Iterator<Item = Id>, Self::Error> {
        Ok(self.node_props.iter().map(|e| e.0.clone()))
    }

    fn iter_nodes(
        &self,
        order: EdgeOrder,
    ) -> (
        impl Iterator<Item = Result<(Id, NodeProps), Self::Error>>,
        impl Iterator<Item = Result<(Triple<Id>, EdgeProps), Self::Error>>,
    ) {
        (self.iter_vertices(), self.iter_edges(order))
    }

    fn iter_vertices<'a>(&'a self) -> impl Iterator<Item = Result<(Id, NodeProps), ()>> + 'a {
        self.node_props
            .iter()
            .map(|(id, props)| Ok((id.clone(), props.clone())))
    }

    fn iter_edges_with_props<'a>(
        &'a self,
        order: EdgeOrder,
    ) -> impl Iterator<Item = Result<PropsTriple<Id, NodeProps, EdgeProps>, ()>> + 'a {
        let edges: Box<dyn Iterator<Item = _>> = match order {
            EdgeOrder::SPO => Box::new(
                self.spo_data
                    .iter()
                    .map(|(k, v)| (Id::decode_spo_triple(k), v)),
            ),
            EdgeOrder::POS => Box::new(
                self.pos_data
                    .iter()
                    .map(|(k, v)| (Id::decode_pos_triple(k), v)),
            ),
            EdgeOrder::OSP => Box::new(
                self.osp_data
                    .iter()
                    .map(|(k, v)| (Id::decode_osp_triple(k), v)),
            ),
        };

        edges.filter_map(|(k, v)| {
            MemTripleStore::iter_impl(&self.node_props, &self.edge_props, k, &v)
        })
    }

    fn iter_edges<'a>(
        &'a self,
        order: EdgeOrder,
    ) -> impl Iterator<Item = Result<(Triple<Id>, EdgeProps), ()>> + 'a {
        let edges: Box<dyn Iterator<Item = _>> = match order {
            EdgeOrder::SPO => Box::new(
                self.spo_data
                    .iter()
                    .map(|(k, v)| (Id::decode_spo_triple(k), v)),
            ),
            EdgeOrder::POS => Box::new(
                self.pos_data
                    .iter()
                    .map(|(k, v)| (Id::decode_pos_triple(k), v)),
            ),
            EdgeOrder::OSP => Box::new(
                self.osp_data
                    .iter()
                    .map(|(k, v)| (Id::decode_osp_triple(k), v)),
            ),
        };

        edges.filter_map(|(k, v)| match self.edge_props.get(&v) {
            Some(v) => Some(Ok((k, v.clone()))),
            None => None,
        })
    }
}

impl<Id: IdType, NodeProps: Property + PartialEq, EdgeProps: Property + PartialEq>
    TripleStoreIntoIter<Id, NodeProps, EdgeProps> for MemTripleStore<Id, NodeProps, EdgeProps>
{
    fn into_iter_nodes(
        self,
        order: EdgeOrder,
    ) -> (
        impl Iterator<Item = Result<(Id, NodeProps), Self::Error>>,
        impl Iterator<Item = Result<(Triple<Id>, EdgeProps), Self::Error>>,
    ) {
        let node_iter = self.node_props.into_iter().map(|o| Ok(o));
        let edge_iter = {
            let edges: Box<dyn Iterator<Item = _>> = match order {
                EdgeOrder::SPO => Box::new(
                    self.spo_data
                        .into_iter()
                        .map(|(k, v)| (Id::decode_spo_triple(&k), v)),
                ),
                EdgeOrder::POS => Box::new(
                    self.pos_data
                        .into_iter()
                        .map(|(k, v)| (Id::decode_pos_triple(&k), v)),
                ),
                EdgeOrder::OSP => Box::new(
                    self.osp_data
                        .into_iter()
                        .map(|(k, v)| (Id::decode_osp_triple(&k), v)),
                ),
            };

            edges.filter_map(
                move |(k, v): (Triple<Id>, Id)| match self.edge_props.get(&v) {
                    Some(v) => Some(Ok((k, v.clone()))),
                    None => None,
                },
            )
        };
        (node_iter, edge_iter)
    }

    fn into_iter_vertices(self) -> impl Iterator<Item = Result<(Id, NodeProps), ()>> {
        self.node_props.into_iter().map(|o| Ok(o))
    }

    fn into_iter_edges_with_props(
        self,
        order: EdgeOrder,
    ) -> impl Iterator<Item = Result<PropsTriple<Id, NodeProps, EdgeProps>, ()>> {
        let edges: Box<dyn Iterator<Item = _>> = match order {
            EdgeOrder::SPO => Box::new(
                self.spo_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_spo_triple(&k), v)),
            ),
            EdgeOrder::POS => Box::new(
                self.pos_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_pos_triple(&k), v)),
            ),
            EdgeOrder::OSP => Box::new(
                self.osp_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_osp_triple(&k), v)),
            ),
        };

        edges.filter_map(move |(k, v): (Triple<Id>, Id)| {
            MemTripleStore::iter_impl(&self.node_props, &self.edge_props, k, &v)
        })
    }

    fn into_iter_edges(
        self,
        order: EdgeOrder,
    ) -> impl Iterator<Item = Result<(Triple<Id>, EdgeProps), ()>> {
        let edges: Box<dyn Iterator<Item = _>> = match order {
            EdgeOrder::SPO => Box::new(
                self.spo_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_spo_triple(&k), v)),
            ),
            EdgeOrder::POS => Box::new(
                self.pos_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_pos_triple(&k), v)),
            ),
            EdgeOrder::OSP => Box::new(
                self.osp_data
                    .into_iter()
                    .map(|(k, v)| (Id::decode_osp_triple(&k), v)),
            ),
        };

        edges.filter_map(move |(k, v)| match self.edge_props.get(&v) {
            Some(v) => Some(Ok((k, v.clone()))),
            None => None,
        })
    }
}

#[cfg(test)]
mod test {
    use crate::{MemTripleStore, UlidIdGenerator};

    #[test]
    fn test_iter_spo() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_spo(db);
    }

    #[test]
    fn test_iter_pos() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_pos(db);
    }

    #[test]
    fn test_iter_osp() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_osp(db);
    }

    #[test]
    fn test_iter_edge_spo() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_edge_spo(db);
    }

    #[test]
    fn test_iter_edge_pos() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_edge_pos(db);
    }

    #[test]
    fn test_iter_edge_osp() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_edge_osp(db);
    }

    #[test]
    fn test_iter_node() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_iter_node(db);
    }

    #[test]
    fn test_into_iter_spo() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_spo(db);
    }

    #[test]
    fn test_into_iter_pos() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_pos(db);
    }

    #[test]
    fn test_into_iter_osp() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_osp(db);
    }

    #[test]
    fn test_into_iter_edge_spo() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_edge_spo(db);
    }

    #[test]
    fn test_into_iter_edge_pos() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_edge_pos(db);
    }

    #[test]
    fn test_into_iter_edge_osp() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_edge_osp(db);
    }

    #[test]
    fn test_into_iter_node() {
        let db = MemTripleStore::new(UlidIdGenerator::new());
        crate::conformance::iter::test_into_iter_node(db);
    }
}