sophia_api/dataset/
adapter.rs

1//! I define adapters for the [`dataset`](super) related traits.
2use std::error::Error;
3
4use super::*;
5use crate::graph::{GTerm, Graph, MutableGraph};
6use crate::quad::Spog;
7use crate::term::{GraphName, Term};
8use crate::triple::Triple;
9
10/// I wrap a [`Graph`] as a [`Dataset`] containing only that graph as the default graph.
11#[derive(Clone, Copy, Debug)]
12pub struct GraphAsDataset<T>(T);
13
14impl<T> GraphAsDataset<T>
15where
16    T: Graph,
17{
18    /// Wrap the given graph with the given name.
19    pub fn new(graph: T) -> Self {
20        GraphAsDataset(graph)
21    }
22
23    /// Unwrap the inner graph and name.
24    pub fn unwrap(self) -> T {
25        self.0
26    }
27}
28
29impl<T> Dataset for GraphAsDataset<T>
30where
31    T: Graph,
32{
33    type Quad<'x> = Spog<GTerm<'x, T>> where Self: 'x;
34    type Error = T::Error;
35
36    fn quads(&self) -> impl Iterator<Item = DResult<Self, Self::Quad<'_>>> + '_ {
37        self.0
38            .triples()
39            // NB: for some reason, .map_ok(...) below does not compile since 1.66 nightly
40            .map(|r| r.map(Triple::into_quad))
41    }
42
43    #[allow(refining_impl_trait)]
44    fn quads_matching<'s, S, P, O, G>(
45        &'s self,
46        sm: S,
47        pm: P,
48        om: O,
49        gm: G,
50    ) -> Box<dyn Iterator<Item = DResult<Self, Self::Quad<'s>>> + 's>
51    where
52        S: TermMatcher + 's,
53        P: TermMatcher + 's,
54        O: TermMatcher + 's,
55        G: GraphNameMatcher + 's,
56    {
57        if gm.matches(None as GraphName<&GTerm<T>>) {
58            Box::new(
59                self.0
60                    .triples_matching(sm, pm, om)
61                    // NB: for some reason, .map_ok(...) below does not compile since 1.66 nightly
62                    .map(|r| r.map(Triple::into_quad)),
63            )
64        } else {
65            Box::new(std::iter::empty())
66        }
67    }
68
69    fn contains<TS, TP, TO, TG>(&self, s: TS, p: TP, o: TO, g: GraphName<TG>) -> DResult<Self, bool>
70    where
71        TS: Term,
72        TP: Term,
73        TO: Term,
74        TG: Term,
75    {
76        if g.is_none() {
77            self.0.contains(s, p, o)
78        } else {
79            Ok(false)
80        }
81    }
82
83    fn subjects(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
84        self.0.subjects()
85    }
86
87    fn predicates(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
88        self.0.predicates()
89    }
90
91    fn objects(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
92        self.0.objects()
93    }
94
95    fn graph_names(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
96        std::iter::empty()
97    }
98
99    fn iris(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
100        self.0.iris()
101    }
102
103    fn blank_nodes(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
104        self.0.blank_nodes()
105    }
106
107    fn literals(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
108        self.0.literals()
109    }
110
111    fn quoted_triples<'s>(&'s self) -> Box<dyn Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_>
112    where
113        GTerm<'s, T>: Clone,
114    {
115        self.0.quoted_triples()
116    }
117
118    fn variables(&self) -> impl Iterator<Item = DResult<Self, DTerm<'_, Self>>> + '_ {
119        self.0.variables()
120    }
121}
122
123impl<T> MutableDataset for GraphAsDataset<T>
124where
125    T: MutableGraph,
126{
127    type MutationError = GraphAsDatasetMutationError<T::MutationError>;
128
129    fn insert<TS, TP, TO, TG>(
130        &mut self,
131        s: TS,
132        p: TP,
133        o: TO,
134        g: GraphName<TG>,
135    ) -> MdResult<Self, bool>
136    where
137        TS: Term,
138        TP: Term,
139        TO: Term,
140        TG: Term,
141    {
142        if g.is_none() {
143            self.0
144                .insert(s, p, o)
145                .map_err(GraphAsDatasetMutationError::Graph)
146        } else {
147            Err(GraphAsDatasetMutationError::OnlyDefaultGraph)
148        }
149    }
150
151    fn remove<TS, TP, TO, TG>(
152        &mut self,
153        s: TS,
154        p: TP,
155        o: TO,
156        g: GraphName<TG>,
157    ) -> MdResult<Self, bool>
158    where
159        TS: Term,
160        TP: Term,
161        TO: Term,
162        TG: Term,
163    {
164        if g.is_none() {
165            self.0
166                .insert(s, p, o)
167                .map_err(GraphAsDatasetMutationError::Graph)
168        } else {
169            Ok(false)
170        }
171    }
172}
173
174/// Error raised by mutating a [`GraphAsDataset`].
175///
176/// In addition to the errors raised by the underlying [graph][GraphAsDatasetMutationError::Graph],
177/// [`GraphAsDataset`] may also raise error when quads are added [in a named graph][GraphAsDatasetMutationError::OnlyDefaultGraph].
178#[derive(thiserror::Error, Debug)]
179pub enum GraphAsDatasetMutationError<T: Error> {
180    /// Error in the underlying graph.
181    #[error("{0:?}")]
182    Graph(T),
183    /// Can not insert a quad in a named graph.
184    #[error("This dataset only supports a default graph")]
185    OnlyDefaultGraph,
186}
187
188#[cfg(test)]
189mod test {
190    use super::*;
191    use crate::graph::adapter::DatasetGraph;
192    use crate::source::{StreamError, TripleSource};
193    use std::collections::BTreeSet;
194
195    type MyTerm = SimpleTerm<'static>;
196    type MyGraph = BTreeSet<[MyTerm; 3]>;
197
198    // NB: using test_dataset_impl! for testing GraphAsDataset is not convenient,
199    // because GraphAsDataset is not a full-fledged dataset (it has only a default graph).
200    //
201    // In order to test it, we further wrap the dataset into a DatasetGraph,
202    // and call test_graph_impl! on it.
203    type MyGaDG = DatasetGraph<GraphAsDataset<MyGraph>, MyTerm>;
204    fn collect_graph_as_dataset<T: TripleSource>(ts: T) -> Result<MyGaDG, T::Error> {
205        ts.collect_triples()
206            .map(|g: MyGraph| DatasetGraph::new(g.into_dataset(), None))
207            .map_err(StreamError::unwrap_source_error)
208    }
209    crate::test_immutable_graph_impl!(
210        graph_as_dataset,
211        MyGaDG,
212        true,
213        true,
214        collect_graph_as_dataset
215    );
216
217    #[allow(dead_code)] // just check this compiles
218    fn check_trait_impls() {
219        let mut g: Vec<[SimpleTerm; 3]> = vec![];
220
221        // check that Graph::as_dataset implememnts Dataset
222        for _ in g.as_dataset().quads() {}
223
224        let mut gd = g.as_dataset_mut();
225        // check that Graph::as_dataset_mut implememnts Dataset
226        for _ in gd.quads() {}
227        // check that Graph::as_dataset_mut implememnts MutableDataset
228        gd.remove_quad(([1, 2, 3], None)).unwrap();
229
230        let mut gd = g.into_dataset();
231        // check that Graph::as_dataset_mut implememnts Dataset
232        for _ in gd.quads() {}
233        // check that Graph::as_dataset_mut implememnts MutableDataset
234        gd.remove_quad(([1, 2, 3], None)).unwrap();
235    }
236}