1use crate::io::{RdfFormat, RdfSerializer};
2use crate::model::*;
3use crate::sparql::error::EvaluationError;
4use crate::sparql::results::{
5 QueryResultsFormat, QueryResultsParseError, QueryResultsParser, QueryResultsSerializer,
6 ReaderQueryResultsParserOutput, ReaderSolutionsParser,
7};
8pub use sparesults::QuerySolution;
9use spareval::{
10 QueryEvaluationError, QueryResults as EvalQueryResults,
11 QuerySolutionIter as EvalQuerySolutionIter, QueryTripleIter as EvalQueryTripleIter,
12};
13use std::io::{Read, Write};
14use std::sync::Arc;
15
16pub enum QueryResults {
18 Solutions(QuerySolutionIter),
20 Boolean(bool),
22 Graph(QueryTripleIter),
24}
25
26impl QueryResults {
27 pub fn read(
29 reader: impl Read + 'static,
30 format: QueryResultsFormat,
31 ) -> Result<Self, QueryResultsParseError> {
32 Ok(QueryResultsParser::from_format(format)
33 .for_reader(reader)?
34 .into())
35 }
36
37 pub fn write<W: Write>(
58 self,
59 writer: W,
60 format: QueryResultsFormat,
61 ) -> Result<W, EvaluationError> {
62 let serializer = QueryResultsSerializer::from_format(format);
63 match self {
64 Self::Boolean(value) => serializer.serialize_boolean_to_writer(writer, value),
65 Self::Solutions(solutions) => {
66 let mut serializer = serializer
67 .serialize_solutions_to_writer(writer, solutions.variables().to_vec())
68 .map_err(EvaluationError::ResultsSerialization)?;
69 for solution in solutions {
70 serializer
71 .serialize(&solution?)
72 .map_err(EvaluationError::ResultsSerialization)?;
73 }
74 serializer.finish()
75 }
76 Self::Graph(triples) => {
77 let s = VariableRef::new_unchecked("subject");
78 let p = VariableRef::new_unchecked("predicate");
79 let o = VariableRef::new_unchecked("object");
80 let mut serializer = serializer
81 .serialize_solutions_to_writer(
82 writer,
83 vec![s.into_owned(), p.into_owned(), o.into_owned()],
84 )
85 .map_err(EvaluationError::ResultsSerialization)?;
86 for triple in triples {
87 let triple = triple?;
88 serializer
89 .serialize([
90 (s, &triple.subject.into()),
91 (p, &triple.predicate.into()),
92 (o, &triple.object),
93 ])
94 .map_err(EvaluationError::ResultsSerialization)?;
95 }
96 serializer.finish()
97 }
98 }
99 .map_err(EvaluationError::ResultsSerialization)
100 }
101
102 pub fn write_graph<W: Write>(
129 self,
130 writer: W,
131 format: impl Into<RdfFormat>,
132 ) -> Result<W, EvaluationError> {
133 if let Self::Graph(triples) = self {
134 let mut serializer = RdfSerializer::from_format(format.into()).for_writer(writer);
135 for triple in triples {
136 serializer
137 .serialize_triple(&triple?)
138 .map_err(EvaluationError::ResultsSerialization)?;
139 }
140 serializer
141 .finish()
142 .map_err(EvaluationError::ResultsSerialization)
143 } else {
144 Err(EvaluationError::NotAGraph)
145 }
146 }
147}
148
149impl From<EvalQueryResults> for QueryResults {
150 #[inline]
151 fn from(results: EvalQueryResults) -> Self {
152 match results {
153 EvalQueryResults::Solutions(iter) => Self::Solutions(iter.into()),
154 EvalQueryResults::Boolean(value) => Self::Boolean(value),
155 EvalQueryResults::Graph(iter) => Self::Graph(iter.into()),
156 }
157 }
158}
159
160impl From<QuerySolutionIter> for QueryResults {
161 #[inline]
162 fn from(value: QuerySolutionIter) -> Self {
163 Self::Solutions(value)
164 }
165}
166
167impl<R: Read + 'static> From<ReaderQueryResultsParserOutput<R>> for QueryResults {
168 fn from(reader: ReaderQueryResultsParserOutput<R>) -> Self {
169 match reader {
170 ReaderQueryResultsParserOutput::Solutions(s) => Self::Solutions(s.into()),
171 ReaderQueryResultsParserOutput::Boolean(v) => Self::Boolean(v),
172 }
173 }
174}
175
176pub struct QuerySolutionIter {
191 inner: EvalQuerySolutionIter,
192}
193
194impl QuerySolutionIter {
195 pub fn new(
198 variables: Arc<[Variable]>,
199 iter: impl Iterator<Item = Result<Vec<Option<Term>>, EvaluationError>> + 'static,
200 ) -> Self {
201 Self {
202 inner: EvalQuerySolutionIter::new(
203 Arc::clone(&variables),
204 Box::new(iter.map(move |t| match t {
205 Ok(values) => Ok((Arc::clone(&variables), values).into()),
206 Err(e) => Err(QueryEvaluationError::Service(Box::new(e))),
207 })),
208 ),
209 }
210 }
211
212 #[inline]
228 pub fn variables(&self) -> &[Variable] {
229 self.inner.variables()
230 }
231}
232
233impl From<EvalQuerySolutionIter> for QuerySolutionIter {
234 #[inline]
235 fn from(inner: EvalQuerySolutionIter) -> Self {
236 Self { inner }
237 }
238}
239
240impl From<QuerySolutionIter> for EvalQuerySolutionIter {
241 #[inline]
242 fn from(iter: QuerySolutionIter) -> Self {
243 iter.inner
244 }
245}
246
247impl<R: Read + 'static> From<ReaderSolutionsParser<R>> for QuerySolutionIter {
248 fn from(reader: ReaderSolutionsParser<R>) -> Self {
249 Self {
250 inner: EvalQuerySolutionIter::new(
251 reader.variables().into(),
252 Box::new(reader.map(|t| t.map_err(|e| QueryEvaluationError::Service(Box::new(e))))),
253 ),
254 }
255 }
256}
257
258impl Iterator for QuerySolutionIter {
259 type Item = Result<QuerySolution, EvaluationError>;
260
261 #[inline]
262 fn next(&mut self) -> Option<Self::Item> {
263 Some(self.inner.next()?.map_err(Into::into))
264 }
265
266 #[inline]
267 fn size_hint(&self) -> (usize, Option<usize>) {
268 self.inner.size_hint()
269 }
270}
271
272pub struct QueryTripleIter {
287 inner: EvalQueryTripleIter,
288}
289
290impl From<EvalQueryTripleIter> for QueryTripleIter {
291 #[inline]
292 fn from(inner: EvalQueryTripleIter) -> Self {
293 Self { inner }
294 }
295}
296
297impl From<QueryTripleIter> for EvalQueryTripleIter {
298 #[inline]
299 fn from(iter: QueryTripleIter) -> Self {
300 iter.inner
301 }
302}
303
304impl Iterator for QueryTripleIter {
305 type Item = Result<Triple, EvaluationError>;
306
307 #[inline]
308 fn next(&mut self) -> Option<Self::Item> {
309 Some(self.inner.next()?.map_err(Into::into))
310 }
311
312 #[inline]
313 fn size_hint(&self) -> (usize, Option<usize>) {
314 self.inner.size_hint()
315 }
316}
317
318#[cfg(test)]
319#[allow(clippy::panic_in_result_fn)]
320mod tests {
321 use super::*;
322 use std::io::Cursor;
323
324 #[test]
325 fn test_send_sync() {
326 fn is_send_sync<T: Send + Sync>() {}
327 is_send_sync::<QuerySolution>();
328 }
329
330 #[test]
331 fn test_serialization_roundtrip() -> Result<(), EvaluationError> {
332 use std::str;
333
334 for format in [
335 QueryResultsFormat::Json,
336 QueryResultsFormat::Xml,
337 QueryResultsFormat::Tsv,
338 ] {
339 let results = vec![
340 QueryResults::Boolean(true),
341 QueryResults::Boolean(false),
342 QueryResults::Solutions(QuerySolutionIter::new(
343 [
344 Variable::new_unchecked("foo"),
345 Variable::new_unchecked("bar"),
346 ]
347 .as_ref()
348 .into(),
349 Box::new(
350 vec![
351 Ok(vec![None, None]),
352 Ok(vec![
353 Some(NamedNode::new_unchecked("http://example.com").into()),
354 None,
355 ]),
356 Ok(vec![
357 None,
358 Some(NamedNode::new_unchecked("http://example.com").into()),
359 ]),
360 Ok(vec![
361 Some(BlankNode::new_unchecked("foo").into()),
362 Some(BlankNode::new_unchecked("bar").into()),
363 ]),
364 Ok(vec![Some(Literal::new_simple_literal("foo").into()), None]),
365 Ok(vec![
366 Some(
367 Literal::new_language_tagged_literal_unchecked("foo", "fr")
368 .into(),
369 ),
370 None,
371 ]),
372 Ok(vec![
373 Some(Literal::from(1).into()),
374 Some(Literal::from(true).into()),
375 ]),
376 Ok(vec![
377 Some(Literal::from(1.33).into()),
378 Some(Literal::from(false).into()),
379 ]),
380 Ok(vec![
381 Some(
382 Triple::new(
383 NamedNode::new_unchecked("http://example.com/s"),
384 NamedNode::new_unchecked("http://example.com/p"),
385 Triple::new(
386 NamedNode::new_unchecked("http://example.com/os"),
387 NamedNode::new_unchecked("http://example.com/op"),
388 NamedNode::new_unchecked("http://example.com/oo"),
389 ),
390 )
391 .into(),
392 ),
393 None,
394 ]),
395 ]
396 .into_iter(),
397 ),
398 )),
399 ];
400
401 for ex in results {
402 let mut buffer = Vec::new();
403 ex.write(&mut buffer, format)?;
404 let ex2 = QueryResults::read(Cursor::new(buffer.clone()), format)?;
405 let mut buffer2 = Vec::new();
406 ex2.write(&mut buffer2, format)?;
407 assert_eq!(
408 str::from_utf8(&buffer).unwrap(),
409 str::from_utf8(&buffer2).unwrap()
410 );
411 }
412 }
413
414 Ok(())
415 }
416}