sophia_api/dataset/
adapter.rs

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