use super::*;
use crate::dataset::{DTerm, Dataset, MutableDataset, SetDataset};
use crate::quad::Quad;
use crate::term::{
matcher::{Any, GraphNameMatcher},
GraphName,
};
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct UnionGraph<T: Dataset>(T);
impl<T: Dataset> UnionGraph<T> {
pub fn new(wrapped: T) -> Self {
UnionGraph(wrapped)
}
pub fn unwrap(self) -> T {
self.0
}
}
impl<T: Dataset> Graph for UnionGraph<T> {
type Triple<'x> = [DTerm<'x, T>; 3] where Self: 'x;
type Error = T::Error;
fn triples(&self) -> GTripleSource<Self> {
Box::new(
self.0
.quads()
.map(|r| r.map(Quad::into_triple)),
)
}
fn triples_matching<'s, S, P, O>(&'s self, sm: S, pm: P, om: O) -> GTripleSource<'s, Self>
where
S: TermMatcher + 's,
P: TermMatcher + 's,
O: TermMatcher + 's,
{
Box::new(
self.0
.quads_matching(sm, pm, om, Any)
.map(|r| r.map(Quad::into_triple)),
)
}
fn subjects(&self) -> GTermSource<Self> {
self.0.subjects()
}
fn predicates(&self) -> GTermSource<Self> {
self.0.predicates()
}
fn objects(&self) -> GTermSource<Self> {
self.0.objects()
}
fn iris(&self) -> GTermSource<Self> {
self.0.iris()
}
fn blank_nodes(&self) -> GTermSource<Self> {
self.0.blank_nodes()
}
fn literals(&self) -> GTermSource<Self> {
self.0.literals()
}
fn quoted_triples<'s>(&'s self) -> GTermSource<'s, Self>
where
GTerm<'s, Self>: Clone,
{
self.0.quoted_triples()
}
fn variables(&self) -> GTermSource<Self> {
self.0.variables()
}
}
#[derive(Clone, Copy, Debug)]
pub struct PartialUnionGraph<D: Dataset, M: GraphNameMatcher> {
d: D,
m: M,
}
impl<D: Dataset, M: GraphNameMatcher + Copy> PartialUnionGraph<D, M> {
pub fn new(d: D, m: M) -> Self {
PartialUnionGraph { d, m }
}
pub fn unwrap(self) -> (D, M) {
(self.d, self.m)
}
}
impl<D: Dataset, M: GraphNameMatcher + Copy> Graph for PartialUnionGraph<D, M> {
type Triple<'x> = [DTerm<'x, D>; 3] where Self: 'x;
type Error = D::Error;
fn triples(&self) -> GTripleSource<Self> {
Box::new(
self.d
.quads_matching(Any, Any, Any, self.m)
.map(|r| r.map(Quad::into_triple)),
)
}
fn triples_matching<'s, S, P, O>(&'s self, sm: S, pm: P, om: O) -> GTripleSource<'s, Self>
where
S: TermMatcher + 's,
P: TermMatcher + 's,
O: TermMatcher + 's,
{
Box::new(
self.d
.quads_matching(sm, pm, om, self.m)
.map(|r| r.map(Quad::into_triple)),
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct DatasetGraph<D: Dataset, G: Term> {
d: D,
g: GraphName<G>,
}
impl<D: Dataset, G: Term> DatasetGraph<D, G> {
pub fn new(d: D, g: GraphName<G>) -> Self {
DatasetGraph { d, g }
}
pub fn unwrap(self) -> (D, GraphName<G>) {
(self.d, self.g)
}
fn g(&self) -> GraphName<G::BorrowTerm<'_>> {
self.g.as_ref().map(|gn| gn.borrow_term())
}
fn gd(&mut self) -> (Option<G::BorrowTerm<'_>>, &mut D) {
(self.g.as_ref().map(|gn| gn.borrow_term()), &mut self.d)
}
}
impl<D: Dataset, G: Term> Graph for DatasetGraph<D, G> {
type Triple<'x> = [DTerm<'x, D>; 3] where Self: 'x;
type Error = D::Error;
fn triples(&self) -> GTripleSource<Self> {
Box::new(
self.d
.quads_matching(Any, Any, Any, [self.g()])
.map(|r| r.map(Quad::into_triple)),
)
}
fn triples_matching<'s, S, P, O>(&'s self, sm: S, pm: P, om: O) -> GTripleSource<'s, Self>
where
S: TermMatcher + 's,
P: TermMatcher + 's,
O: TermMatcher + 's,
{
Box::new(
self.d
.quads_matching(sm, pm, om, [self.g()])
.map(|r| r.map(Quad::into_triple)),
)
}
}
impl<D: SetDataset, G: Term> SetGraph for DatasetGraph<D, G> {}
impl<D: MutableDataset, G: Term> MutableGraph for DatasetGraph<D, G> {
type MutationError = D::MutationError;
fn insert<TS, TP, TO>(&mut self, s: TS, p: TP, o: TO) -> MgResult<Self, bool>
where
TS: Term,
TP: Term,
TO: Term,
{
let (g, d) = self.gd();
d.insert(s, p, o, g)
}
fn remove<TS, TP, TO>(&mut self, s: TS, p: TP, o: TO) -> MgResult<Self, bool>
where
TS: Term,
TP: Term,
TO: Term,
{
let (g, d) = self.gd();
d.remove(s, p, o, g)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::quad::Spog;
use crate::term::{graph_name_eq, FromTerm};
use sophia_iri::Iri;
use std::collections::BTreeSet;
static G1: Iri<&'static str> = Iri::new_unchecked_const("http://example.com/g1");
static G2: Iri<&'static str> = Iri::new_unchecked_const("http://example.com/g2");
static G3: Iri<&'static str> = Iri::new_unchecked_const("http://example.com/g3");
type MyTerm = SimpleTerm<'static>;
type MyQuad = Spog<MyTerm>;
type MyDS = BTreeSet<MyQuad>;
#[derive(Clone, Copy, Debug)]
struct GM;
impl GraphNameMatcher for GM {
type Term = MyTerm;
fn matches<T2: Term + ?Sized>(&self, graph_name: GraphName<&T2>) -> bool {
graph_name_eq(graph_name.map(|gn| gn.borrow_term()), Some(G1))
|| graph_name_eq(graph_name.map(|gn| gn.borrow_term()), Some(G2))
}
}
type MyUG = UnionGraph<MyDS>;
fn collect_union_graph<T: TripleSource>(mut ts: T) -> Result<MyUG, T::Error> {
let mut ds = MyDS::new();
ts.for_each_triple(|t| {
let [s, p, o] = t.spo();
ds.insert_quad(([s, p, o], Some(s))).unwrap();
})?;
Ok(ds.into_union_graph())
}
crate::test_immutable_graph_impl!(union_graph, MyUG, true, true, collect_union_graph);
type MyPUG = PartialUnionGraph<MyDS, GM>;
fn collect_partial_union_graph<T: TripleSource>(mut ts: T) -> Result<MyPUG, T::Error> {
let g1: GraphName<MyTerm> = Some(G1.into_term());
let g2: GraphName<MyTerm> = Some(G2.into_term());
let g3: GraphName<MyTerm> = Some(G3.into_term());
let mut ds = MyDS::new();
let mut b = true;
ts.for_each_triple(|t| {
let [s, p, o] = t.spo();
if b {
ds.insert_quad(([s, p, o].map(MyTerm::from_term), g1.clone()))
.unwrap();
ds.insert_quad(([o, p, s].map(MyTerm::from_term), g3.clone()))
.unwrap();
} else {
ds.insert_quad(([s, p, o].map(MyTerm::from_term), g2.clone()))
.unwrap();
}
b = !b;
})?;
Ok(PartialUnionGraph::new(ds, GM))
}
crate::test_immutable_graph_impl!(
partial_union_graph,
MyPUG,
true,
true,
collect_partial_union_graph
);
type MyDG = DatasetGraph<MyDS, MyTerm>;
fn collect_dataset_graph<T: TripleSource>(mut ts: T) -> Result<MyDG, T::Error> {
let g1: GraphName<MyTerm> = Some(G1.into_term());
let g2: GraphName<MyTerm> = Some(G2.into_term());
let mut ds = MyDS::new();
ts.for_each_triple(|t| {
let [s, p, o] = t.spo();
ds.insert_quad(([s, p, o].map(MyTerm::from_term), g1.clone()))
.unwrap();
ds.insert_quad(([o, p, s].map(MyTerm::from_term), g2.clone()))
.unwrap();
})?;
Ok(DatasetGraph::new(ds, g1))
}
crate::test_graph_impl!(dataset_graph, MyDG, true, true, collect_dataset_graph);
#[allow(dead_code)] fn check_trait_impls() {
let mut ds = MyDS::new();
let g1: Option<MyTerm> = Some(G1.into_term());
for _ in ds.graph(g1.clone()).triples() {}
let mut gm = ds.graph_mut(g1);
for _ in gm.triples() {}
gm.remove_triple([1, 2, 3]).unwrap();
for _ in ds.partial_union_graph(GM).triples() {}
for _ in ds.union_graph().triples() {}
for _ in ds.into_union_graph().triples() {}
}
}