Skip to main content

spareval/
model.rs

1use crate::error::QueryEvaluationError;
2use oxrdf::{Term, Triple, Variable};
3pub use sparesults::QuerySolution;
4use sparesults::{
5    ReaderQueryResultsParserOutput, ReaderSolutionsParser, SliceQueryResultsParserOutput,
6    SliceSolutionsParser,
7};
8use std::io::Read;
9use std::sync::Arc;
10
11/// Results of a [SPARQL query](https://www.w3.org/TR/sparql11-query/).
12pub enum QueryResults<'a> {
13    /// Results of a [SELECT](https://www.w3.org/TR/sparql11-query/#select) query.
14    Solutions(QuerySolutionIter<'a>),
15    /// Result of a [ASK](https://www.w3.org/TR/sparql11-query/#ask) query.
16    Boolean(bool),
17    /// Results of a [CONSTRUCT](https://www.w3.org/TR/sparql11-query/#construct) or [DESCRIBE](https://www.w3.org/TR/sparql11-query/#describe) query.
18    Graph(QueryTripleIter<'a>),
19}
20
21impl<'a> From<QuerySolutionIter<'a>> for QueryResults<'a> {
22    #[inline]
23    fn from(value: QuerySolutionIter<'a>) -> Self {
24        Self::Solutions(value)
25    }
26}
27
28impl From<bool> for QueryResults<'_> {
29    #[inline]
30    fn from(value: bool) -> Self {
31        Self::Boolean(value)
32    }
33}
34
35impl<'a> From<QueryTripleIter<'a>> for QueryResults<'a> {
36    #[inline]
37    fn from(value: QueryTripleIter<'a>) -> Self {
38        Self::Graph(value)
39    }
40}
41
42impl<'a, R: Read + 'a> From<ReaderQueryResultsParserOutput<R>> for QueryResults<'a> {
43    #[inline]
44    fn from(output: ReaderQueryResultsParserOutput<R>) -> Self {
45        match output {
46            ReaderQueryResultsParserOutput::Solutions(output) => Self::Solutions(output.into()),
47            ReaderQueryResultsParserOutput::Boolean(output) => Self::Boolean(output),
48        }
49    }
50}
51
52impl<'a> From<SliceQueryResultsParserOutput<'a>> for QueryResults<'a> {
53    #[inline]
54    fn from(output: SliceQueryResultsParserOutput<'a>) -> Self {
55        match output {
56            SliceQueryResultsParserOutput::Solutions(output) => Self::Solutions(output.into()),
57            SliceQueryResultsParserOutput::Boolean(output) => Self::Boolean(output),
58        }
59    }
60}
61
62/// An iterator over [`QuerySolution`]s.
63///
64/// ```
65/// use oxrdf::Dataset;
66/// use spareval::{QueryEvaluator, QueryResults};
67/// use spargebra::SparqlParser;
68///
69/// let query = SparqlParser::new().parse_query("SELECT ?s ?o WHERE { ?s ?p ?o }")?;
70/// let evaluator = QueryEvaluator::new();
71/// if let QueryResults::Solutions(solutions) = evaluator.prepare(&query).execute(&Dataset::new())?
72/// {
73///     for solution in solutions {
74///         println!("{:?}", solution?.get("s"));
75///     }
76/// }
77/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
78/// ```
79pub struct QuerySolutionIter<'a> {
80    variables: Arc<[Variable]>,
81    iter: Box<dyn Iterator<Item = Result<QuerySolution, QueryEvaluationError>> + 'a>,
82}
83
84impl<'a> QuerySolutionIter<'a> {
85    /// Construct a new iterator of solutions from an ordered list of solution variables and an iterator of solutions
86    pub fn new(
87        variables: Arc<[Variable]>,
88        iter: impl IntoIterator<Item = Result<QuerySolution, QueryEvaluationError>> + 'a,
89    ) -> Self {
90        Self {
91            variables,
92            iter: Box::new(iter.into_iter()),
93        }
94    }
95
96    /// Construct a new iterator of solutions from an ordered list of solution variables and an iterator of solution tuples
97    /// (each tuple using the same ordering as the variable list such that tuple element 0 is the value for the variable 0...)
98    pub fn from_tuples(
99        variables: Arc<[Variable]>,
100        iter: impl IntoIterator<Item = Result<Vec<Option<Term>>, QueryEvaluationError>> + 'a,
101    ) -> Self {
102        Self::new(
103            Arc::clone(&variables),
104            iter.into_iter()
105                .map(move |values| Ok((Arc::clone(&variables), values?).into())),
106        )
107    }
108
109    /// The variables used in the solutions.
110    ///
111    /// ```
112    /// use oxrdf::{Dataset, Variable};
113    /// use spareval::{QueryEvaluator, QueryResults};
114    /// use spargebra::SparqlParser;
115    ///
116    /// let query = SparqlParser::new().parse_query("SELECT ?s ?o WHERE { ?s ?p ?o }")?;
117    /// let evaluator = QueryEvaluator::new();
118    /// if let QueryResults::Solutions(solutions) = evaluator.prepare(&query).execute(&Dataset::new())?
119    /// {
120    ///     assert_eq!(
121    ///         solutions.variables(),
122    ///         &[Variable::new("s")?, Variable::new("o")?]
123    ///     );
124    /// }
125    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
126    /// ```
127    #[inline]
128    pub fn variables(&self) -> &[Variable] {
129        &self.variables
130    }
131}
132
133impl Iterator for QuerySolutionIter<'_> {
134    type Item = Result<QuerySolution, QueryEvaluationError>;
135
136    #[inline]
137    fn next(&mut self) -> Option<Self::Item> {
138        self.iter.next()
139    }
140
141    #[inline]
142    fn size_hint(&self) -> (usize, Option<usize>) {
143        self.iter.size_hint()
144    }
145}
146
147impl<'a, R: Read + 'a> From<ReaderSolutionsParser<R>> for QuerySolutionIter<'a> {
148    #[inline]
149    fn from(parser: ReaderSolutionsParser<R>) -> Self {
150        Self {
151            variables: parser.variables().into(),
152            iter: Box::new(
153                parser.map(|r| r.map_err(|e| QueryEvaluationError::Unexpected(e.into()))),
154            ),
155        }
156    }
157}
158
159impl<'a> From<SliceSolutionsParser<'a>> for QuerySolutionIter<'a> {
160    #[inline]
161    fn from(parser: SliceSolutionsParser<'a>) -> Self {
162        Self {
163            variables: parser.variables().into(),
164            iter: Box::new(
165                parser.map(|r| r.map_err(|e| QueryEvaluationError::Unexpected(e.into()))),
166            ),
167        }
168    }
169}
170
171/// An iterator over the triples that compose a graph solution.
172///
173/// ```
174/// use oxrdf::Dataset;
175/// use spareval::{QueryEvaluator, QueryResults};
176/// use spargebra::SparqlParser;
177///
178/// let query = SparqlParser::new().parse_query("CONSTRUCT WHERE { ?s ?p ?o }")?;
179/// let evaluator = QueryEvaluator::new();
180/// if let QueryResults::Graph(triples) = evaluator.prepare(&query).execute(&Dataset::new())? {
181///     for triple in triples {
182///         println!("{}", triple?);
183///     }
184/// }
185/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
186/// ```
187pub struct QueryTripleIter<'a> {
188    iter: Box<dyn Iterator<Item = Result<Triple, QueryEvaluationError>> + 'a>,
189}
190
191impl<'a> QueryTripleIter<'a> {
192    pub fn new(iter: impl Iterator<Item = Result<Triple, QueryEvaluationError>> + 'a) -> Self {
193        Self {
194            iter: Box::new(iter),
195        }
196    }
197}
198
199impl Iterator for QueryTripleIter<'_> {
200    type Item = Result<Triple, QueryEvaluationError>;
201
202    #[inline]
203    fn next(&mut self) -> Option<Self::Item> {
204        self.iter.next()
205    }
206
207    #[inline]
208    fn size_hint(&self) -> (usize, Option<usize>) {
209        self.iter.size_hint()
210    }
211}