Renames some sparql module element and improves documentation

QueryResult -> QueryResults
QueryResultFormat -> QueryResultsFormat
QuerySolutionsIterator -> QuerySolutionIter
QueryTriplesIterator -> QueryTripleIter
pull/46/head
Tpt 4 years ago
parent e787eb69f5
commit 6b3062f496
  1. 5
      README.md
  2. 6
      js/README.md
  3. 8
      js/src/store.rs
  4. 20
      lib/src/io/read.rs
  5. 26
      lib/src/io/write.rs
  6. 6
      lib/src/lib.rs
  7. 22
      lib/src/model/blank_node.rs
  8. 6
      lib/src/model/literal.rs
  9. 4
      lib/src/model/named_node.rs
  10. 2
      lib/src/model/vocab.rs
  11. 26
      lib/src/sparql/eval.rs
  12. 8
      lib/src/sparql/json_results.rs
  13. 24
      lib/src/sparql/mod.rs
  14. 104
      lib/src/sparql/model.rs
  15. 57
      lib/src/sparql/xml_results.rs
  16. 68
      lib/src/store/memory.rs
  17. 5
      lib/src/store/mod.rs
  18. 14
      lib/src/store/rocksdb.rs
  19. 14
      lib/src/store/sled.rs
  20. 2
      python/src/memory_store.rs
  21. 2
      python/src/sled_store.rs
  22. 26
      python/src/store_utils.rs
  23. 18
      server/src/main.rs
  24. 16
      testsuite/src/sparql_evaluator.rs
  25. 18
      wikibase/src/main.rs

@ -4,10 +4,9 @@ Oxigraph
[![actions status](https://github.com/oxigraph/oxigraph/workflows/build/badge.svg)](https://github.com/oxigraph/oxigraph/actions)
[![Gitter](https://badges.gitter.im/oxigraph/community.svg)](https://gitter.im/oxigraph/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Oxigraph is a work in progress graph database implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
Oxigraph is a graph database implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
There is no released version yet.
The storage format is not stable yet and may be at any time.
Its goal is to provide a compliant, safe and fast graph database based on the [RocksDB](https://rocksdb.org/) and [Sled](https://sled.rs/) key-value stores.
It is written in Rust.
@ -20,7 +19,7 @@ It is split into multiple parts:
* The `server` directory contains a stand-alone binary of a web server implementing the [SPARQL 1.1 Protocol](https://www.w3.org/TR/sparql11-protocol/). It uses the [RocksDB](https://rocksdb.org/) key-value store.
* The `wikibase` directory contains a stand-alone binary of a web server able to synchronize with a [Wikibase instance](https://wikiba.se/).
Are currently implemented:
Oxigraph implements the following specifications:
* [SPARQL 1.1 Query](https://www.w3.org/TR/sparql11-query/).
* [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/).
* [Turtle](https://www.w3.org/TR/turtle/), [TriG](https://www.w3.org/TR/trig/), [N-Triples](https://www.w3.org/TR/n-triples/), [N-Quads](https://www.w3.org/TR/n-quads/) and [RDF XML](https://www.w3.org/TR/rdf-syntax-grammar/) RDF serialization formats for both data ingestion and retrieval using the [Rio library](https://github.com/oxigraph/rio).

@ -7,9 +7,9 @@ Oxigraph for JavaScript
This package provides a JavaScript API on top of Oxigraph compiled with WebAssembly.
Oxigraph is a work in progress graph database written in Rust implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
Oxigraph is a graph database written in Rust implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
It is a work in progress and currently offers a simple in-memory store with [SPARQL 1.1 Query](https://www.w3.org/TR/sparql11-query/) capabilities.
Oxigraph or JavaScript is a work in progress and currently offers a simple in-memory store with [SPARQL 1.1 Query](https://www.w3.org/TR/sparql11-query/) capabilities.
The store is also able to load RDF serialized in [Turtle](https://www.w3.org/TR/turtle/), [TriG](https://www.w3.org/TR/trig/), [N-Triples](https://www.w3.org/TR/n-triples/), [N-Quads](https://www.w3.org/TR/n-quads/) and [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/).
@ -163,4 +163,4 @@ The Oxigraph bindings are written in Rust using [the Rust WASM toolkit](https://
The [The Rust Wasm Book](https://rustwasm.github.io/docs/book/) is a great tutorial to get started.
To build the JavaScript bindings, just run `wasm-pack build`, to run the tests of the JS bindings written in JS just do a usual `npm test`.
To build the JavaScript bindings, run `wasm-pack build`, to run the tests of the JS bindings written in JS run `npm test`.

@ -4,7 +4,7 @@ use crate::utils::to_err;
use js_sys::{Array, Map};
use oxigraph::io::{DatasetFormat, GraphFormat};
use oxigraph::model::*;
use oxigraph::sparql::{QueryOptions, QueryResult};
use oxigraph::sparql::{QueryOptions, QueryResults};
use oxigraph::MemoryStore;
use std::convert::{TryFrom, TryInto};
use std::io::Cursor;
@ -110,7 +110,7 @@ impl JsMemoryStore {
.query(query, QueryOptions::default())
.map_err(to_err)?;
let output = match results {
QueryResult::Solutions(solutions) => {
QueryResults::Solutions(solutions) => {
let results = Array::new();
for solution in solutions {
let solution = solution.map_err(to_err)?;
@ -125,14 +125,14 @@ impl JsMemoryStore {
}
results.into()
}
QueryResult::Graph(quads) => {
QueryResults::Graph(quads) => {
let results = Array::new();
for quad in quads {
results.push(&JsQuad::from(quad.map_err(to_err)?.in_graph(None)).into());
}
results.into()
}
QueryResult::Boolean(b) => b.into(),
QueryResults::Boolean(b) => b.into(),
};
Ok(output)
}

@ -14,9 +14,9 @@ use std::io::BufRead;
/// Parsers for RDF graph serialization formats.
///
/// It currently supports the following formats:
/// * [N-Triples](https://www.w3.org/TR/n-triples/) (`GraphFormat::NTriples`)
/// * [Turtle](https://www.w3.org/TR/turtle/) (`GraphFormat::Turtle`)
/// * [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) (`GraphFormat::RdfXml`)
/// * [N-Triples](https://www.w3.org/TR/n-triples/) ([`GraphFormat::NTriples`](../enum.GraphFormat.html#variant.NTriples))
/// * [Turtle](https://www.w3.org/TR/turtle/) ([`GraphFormat::Turtle`](../enum.GraphFormat.html#variant.Turtle))
/// * [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) ([`GraphFormat::RdfXml`](../enum.GraphFormat.html#variant.RdfXml))
///
/// ```
/// use oxigraph::io::{GraphFormat, GraphParser};
@ -37,6 +37,7 @@ pub struct GraphParser {
}
impl GraphParser {
/// Builds a parser for the given format
pub fn from_format(format: GraphFormat) -> Self {
Self {
format,
@ -64,7 +65,7 @@ impl GraphParser {
Ok(self)
}
/// Executes the parsing itself
/// Executes the parsing itself on a [`BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) implementation and returns an iterator of triples
pub fn read_triples<R: BufRead>(&self, reader: R) -> Result<TripleReader<R>, io::Error> {
Ok(TripleReader {
mapper: RioMapper::default(),
@ -82,7 +83,7 @@ impl GraphParser {
}
}
/// Allows reading triples.
/// An iterator yielding read triples.
/// Could be built using a [`GraphParser`](struct.GraphParser.html).
///
/// ```
@ -162,8 +163,8 @@ impl<R: BufRead> TripleReader<R> {
/// A parser for RDF dataset serialization formats.
///
/// It currently supports the following formats:
/// * [N-Quads](https://www.w3.org/TR/n-quads/) (`DatasetFormat::NQuads`)
/// * [TriG](https://www.w3.org/TR/trig/) (`DatasetFormat::TriG`)
/// * [N-Quads](https://www.w3.org/TR/n-quads/) ([`DatasetFormat::NQuads`](../enum.DatasetFormat.html#variant.NQuads))
/// * [TriG](https://www.w3.org/TR/trig/) ([`DatasetFormat::TriG`](../enum.DatasetFormat.html#variant.TriG))
///
/// ```
/// use oxigraph::io::{DatasetFormat, DatasetParser};
@ -184,6 +185,7 @@ pub struct DatasetParser {
}
impl DatasetParser {
/// Builds a parser for the given format
pub fn from_format(format: DatasetFormat) -> Self {
Self {
format,
@ -211,7 +213,7 @@ impl DatasetParser {
Ok(self)
}
/// Executes the parsing itself
/// Executes the parsing itself on a [`BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) implementation and returns an iterator of quads
pub fn read_quads<R: BufRead>(&self, reader: R) -> Result<QuadReader<R>, io::Error> {
Ok(QuadReader {
mapper: RioMapper::default(),
@ -226,7 +228,7 @@ impl DatasetParser {
}
}
/// Allows reading quads.
/// An iterator yielding read quads.
/// Could be built using a [`DatasetParser`](struct.DatasetParser.html).
///
/// ```

@ -11,9 +11,9 @@ use std::io::Write;
/// A serializer for RDF graph serialization formats.
///
/// It currently supports the following formats:
/// * [N-Triples](https://www.w3.org/TR/n-triples/) (`GraphFormat::NTriples`)
/// * [Turtle](https://www.w3.org/TR/turtle/) (`GraphFormat::Turtle`)
/// * [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) (`GraphFormat::RdfXml`)
/// * [N-Triples](https://www.w3.org/TR/n-triples/) ([`GraphFormat::NTriples`](../enum.GraphFormat.html#variant.NTriples))
/// * [Turtle](https://www.w3.org/TR/turtle/) ([`GraphFormat::Turtle`](../enum.GraphFormat.html#variant.Turtle))
/// * [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) ([`GraphFormat::RdfXml`](../enum.GraphFormat.html#variant.RdfXml))
///
/// ```
/// use oxigraph::io::{GraphFormat, GraphSerializer};
@ -37,11 +37,12 @@ pub struct GraphSerializer {
}
impl GraphSerializer {
/// Builds a serializer for the given format
pub fn from_format(format: GraphFormat) -> Self {
Self { format }
}
/// Returns a `TripleWriter` allowing writing triples into the given `Write` implementation
/// Returns a `TripleWriter` allowing writing triples into the given [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) implementation
pub fn triple_writer<W: Write>(&self, writer: W) -> Result<TripleWriter<W>, io::Error> {
Ok(TripleWriter {
formatter: match self.format {
@ -54,9 +55,9 @@ impl GraphSerializer {
}
/// Allows writing triples.
/// Could be built using a `GraphSerializer`.
/// Could be built using a [`GraphSerializer`](struct.GraphSerializer.html).
///
/// Warning: Do not forget to run the `finish` method to properly write the last bytes of the file.
/// Warning: Do not forget to run the [`finish`](#method.finish) method to properly write the last bytes of the file.
///
/// ```
/// use oxigraph::io::{GraphFormat, GraphSerializer};
@ -86,6 +87,7 @@ enum TripleWriterKind<W: Write> {
}
impl<W: Write> TripleWriter<W> {
/// Writes a triple
pub fn write<'a>(&mut self, triple: impl Into<TripleRef<'a>>) -> Result<(), io::Error> {
let triple = triple.into();
match &mut self.formatter {
@ -110,8 +112,8 @@ impl<W: Write> TripleWriter<W> {
/// A serializer for RDF graph serialization formats.
///
/// It currently supports the following formats:
/// * [N-Quads](https://www.w3.org/TR/n-quads/) (`DatasetFormat::NQuads`)
/// * [TriG](https://www.w3.org/TR/trig/) (`DatasetFormat::TriG`)
/// * [N-Quads](https://www.w3.org/TR/n-quads/) ([`DatasetFormat::NQuads`](../enum.DatasetFormat.html#variant.NQuads))
/// * [TriG](https://www.w3.org/TR/trig/) ([`DatasetFormat::TriG`](../enum.DatasetFormat.html#variant.TriG))
///
/// ```
/// use oxigraph::io::{DatasetFormat, DatasetSerializer};
@ -136,11 +138,12 @@ pub struct DatasetSerializer {
}
impl DatasetSerializer {
/// Builds a serializer for the given format
pub fn from_format(format: DatasetFormat) -> Self {
Self { format }
}
/// Returns a `QuadWriter` allowing writing triples into the given `Write` implementation
/// Returns a `QuadWriter` allowing writing triples into the given [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) implementation
pub fn quad_writer<W: Write>(&self, writer: W) -> Result<QuadWriter<W>, io::Error> {
Ok(QuadWriter {
formatter: match self.format {
@ -152,9 +155,9 @@ impl DatasetSerializer {
}
/// Allows writing triples.
/// Could be built using a `DatasetSerializer`.
/// Could be built using a [`DatasetSerializer`](struct.DatasetSerializer.html).
///
/// Warning: Do not forget to run the `finish` method to properly write the last bytes of the file.
/// Warning: Do not forget to run the [`finish`](#method.finish) method to properly write the last bytes of the file.
///
/// ```
/// use oxigraph::io::{DatasetFormat, DatasetSerializer};
@ -184,6 +187,7 @@ enum QuadWriterKind<W: Write> {
}
impl<W: Write> QuadWriter<W> {
/// Writes a quad
pub fn write<'a>(&mut self, quad: impl Into<QuadRef<'a>>) -> Result<(), io::Error> {
let quad = quad.into();
match &mut self.formatter {

@ -1,4 +1,4 @@
//! Oxigraph is a work in progress graph database implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
//! Oxigraph is a graph database implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
//!
//! Its goal is to provide a compliant, safe and fast graph database.
//!
@ -19,7 +19,7 @@
//! ```
//! use oxigraph::MemoryStore;
//! use oxigraph::model::*;
//! use oxigraph::sparql::{QueryOptions, QueryResult};
//! use oxigraph::sparql::{QueryOptions, QueryResults};
//!
//! let store = MemoryStore::new();
//!
@ -33,7 +33,7 @@
//! assert_eq!(vec![quad], results);
//!
//! // SPARQL query
//! if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
//! if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
//! assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
//! }
//! # Result::<_,Box<dyn std::error::Error>>::Ok(())

@ -7,9 +7,9 @@ use std::str;
/// An owned RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
///
/// The common way to create a new blank node is to use the `BlankNode::default` trait method.
/// The common way to create a new blank node is to use the [`BlankNode::default`](#impl-Default) function.
///
/// It is also possible to create a blank node from a blank node identifier using the `BlankNode::new` method.
/// It is also possible to create a blank node from a blank node identifier using the [`BlankNode::new`](#method.new) function.
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// The default string formatter is returning a N-Triples, Turtle and SPARQL compatible representation:
@ -36,8 +36,8 @@ impl BlankNode {
///
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// In most cases, it is much more convenient to create a blank node using `BlankNode::default()`.
/// `BlankNode::default()` creates a random ID that could be easily inlined by Oxigraph stores.
/// In most cases, it is much more convenient to create a blank node using [`BlankNode::default()`](#impl-Default)
///that creates a random ID that could be easily inlined by Oxigraph stores.
pub fn new(id: impl Into<String>) -> Result<Self, BlankNodeIdParseError> {
let id = id.into();
validate_blank_node_identifier(&id)?;
@ -49,7 +49,7 @@ impl BlankNode {
/// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
/// according to N-Triples, Turtle and SPARQL grammars.
///
/// Except if you really know what you do, you should use [`new`](#method.new).
/// [`new`](#method.new) is a safe version of this constructor and should be used for untrusted data.
pub fn new_unchecked(id: impl Into<String>) -> Self {
let id = id.into();
if let Some(numerical_id) = to_integer_id(&id) {
@ -61,7 +61,7 @@ impl BlankNode {
/// Creates a blank node from a unique numerical id
///
/// In most cases, it is much more convenient to create a blank node using `BlankNode::default()`.
/// In most cases, it is much more convenient to create a blank node using [`BlankNode::default()`](#impl-Default).
pub fn new_from_unique_id(id: impl Into<u128>) -> Self {
let id = id.into();
Self(BlankNodeContent::Anonymous {
@ -117,9 +117,9 @@ impl Default for BlankNode {
/// A borrowed RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
///
/// The common way to create a new blank node is to use the `BlankNode::default` trait method.
/// The common way to create a new blank node is to use the [`BlankNode::default`](#impl-Default) trait method.
///
/// It is also possible to create a blank node from a blank node identifier using the `BlankNodeRef::new` method.
/// It is also possible to create a blank node from a blank node identifier using the [`BlankNodeRef::new`](#method.new) function.
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// The default string formatter is returning a N-Triples, Turtle and SPARQL compatible representation:
@ -146,8 +146,8 @@ impl<'a> BlankNodeRef<'a> {
///
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// In most cases, it is much more convenient to create a blank node using `BlankNode::default()`.
/// `BlankNode::default()` creates a random ID that could be easily inlined by Oxigraph stores.
/// In most cases, it is much more convenient to create a blank node using [`BlankNode::default()`](#impl-Default)
/// that creates a random ID that could be easily inlined by Oxigraph stores.
pub fn new(id: &'a str) -> Result<Self, BlankNodeIdParseError> {
validate_blank_node_identifier(id)?;
Ok(Self::new_unchecked(id))
@ -158,7 +158,7 @@ impl<'a> BlankNodeRef<'a> {
/// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
/// according to N-Triples, Turtle and SPARQL grammars.
///
/// Except if you really know what you do, you should use [`new`](#method.new).
/// [`new`](#method.new) is a safe version of this constructor and should be used for untrusted data.
pub fn new_unchecked(id: &'a str) -> Self {
if let Some(numerical_id) = to_integer_id(id) {
Self(BlankNodeRefContent::Anonymous {

@ -82,8 +82,7 @@ impl Literal {
/// is valid [BCP47](https://tools.ietf.org/html/bcp47) language tag,
/// and is lowercase.
///
/// Except if you really know what you do,
/// you should use [`new_language_tagged_literal`](#method.new_language_tagged_literal).
/// [`new_language_tagged_literal`](#method.new_language_tagged_literal) is a safe version of this constructor and should be used for untrusted data.
#[inline]
pub fn new_language_tagged_literal_unchecked(
value: impl Into<String>,
@ -462,8 +461,7 @@ impl<'a> LiteralRef<'a> {
/// is valid [BCP47](https://tools.ietf.org/html/bcp47) language tag,
/// and is lowercase.
///
/// Except if you really know what you do,
/// you should use [`new_language_tagged_literal`](#method.new_language_tagged_literal).
/// [`new_language_tagged_literal`](#method.new_language_tagged_literal) is a safe version of this constructor and should be used for untrusted data.
#[inline]
pub fn new_language_tagged_literal_unchecked(value: &'a str, language: &'a str) -> Self {
LiteralRef(LiteralRefContent::LanguageTaggedString { value, language })

@ -34,7 +34,7 @@ impl NamedNode {
///
/// It is the caller's responsibility to ensure that `iri` is a valid IRI.
///
/// Except if you really know what you do, you should use [`parse`](#method.parse).
/// [`parse`](#method.parse) is a safe version of this constructor and should be used for untrusted data.
#[inline]
pub fn new_unchecked(iri: impl Into<String>) -> Self {
Self { iri: iri.into() }
@ -123,7 +123,7 @@ impl<'a> NamedNodeRef<'a> {
///
/// It is the caller's responsibility to ensure that `iri` is a valid IRI.
///
/// Except if you really know what you do, you should use [`parse`](#method.parse).
/// [`parse`](#method.parse) is a safe version of this constructor and should be used for untrusted data.
#[inline]
pub const fn new_unchecked(iri: &'a str) -> Self {
Self { iri }

@ -1,7 +1,7 @@
//! Provides ready to use [`NamedNodeRef`s](struct.NamedNodeRef.html) for basic RDF vocabularies
pub mod rdf {
//! [RDF 1.1](https://www.w3.org/TR/rdf11-concepts/) vocabulary
//! [RDF](https://www.w3.org/TR/rdf11-concepts/) vocabulary
use crate::model::named_node::NamedNodeRef;
/// The class of containers of alternatives.

@ -70,9 +70,9 @@ where
&self,
plan: &PlanNode<S::StrId>,
variables: Rc<Vec<Variable>>,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
let iter = self.eval_plan(plan, EncodedTuple::with_capacity(variables.len()));
Ok(QueryResult::Solutions(
Ok(QueryResults::Solutions(
self.decode_bindings(iter, variables),
))
}
@ -80,12 +80,12 @@ where
pub fn evaluate_ask_plan(
&self,
plan: &PlanNode<S::StrId>,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
let from = EncodedTuple::with_capacity(plan.maybe_bound_variables().len());
match self.eval_plan(plan, from).next() {
Some(Ok(_)) => Ok(QueryResult::Boolean(true)),
Some(Ok(_)) => Ok(QueryResults::Boolean(true)),
Some(Err(error)) => Err(error),
None => Ok(QueryResult::Boolean(false)),
None => Ok(QueryResults::Boolean(false)),
}
}
@ -93,9 +93,9 @@ where
&self,
plan: &PlanNode<S::StrId>,
construct: Rc<Vec<TripleTemplate<S::StrId>>>,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
let from = EncodedTuple::with_capacity(plan.maybe_bound_variables().len());
Ok(QueryResult::Graph(QueryTriplesIterator {
Ok(QueryResults::Graph(QueryTripleIter {
iter: Box::new(ConstructIterator {
eval: self.clone(),
iter: self.eval_plan(plan, from),
@ -109,9 +109,9 @@ where
pub fn evaluate_describe_plan(
&self,
plan: &PlanNode<S::StrId>,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
let from = EncodedTuple::with_capacity(plan.maybe_bound_variables().len());
Ok(QueryResult::Graph(QueryTriplesIterator {
Ok(QueryResults::Graph(QueryTripleIter {
iter: Box::new(DescribeIterator {
eval: self.clone(),
iter: self.eval_plan(plan, from),
@ -520,7 +520,7 @@ where
variables: Rc<Vec<Variable>>,
from: &EncodedTuple<S::StrId>,
) -> Result<EncodedTuplesIterator<S::StrId>, EvaluationError> {
if let QueryResult::Solutions(iter) = self.service_handler.handle(
if let QueryResults::Solutions(iter) = self.service_handler.handle(
self.dataset.decode_named_node(
get_pattern_value(service_name, from)
.ok_or_else(|| EvaluationError::msg("The SERVICE name is not bound"))?,
@ -1816,10 +1816,10 @@ where
&self,
iter: EncodedTuplesIterator<S::StrId>,
variables: Rc<Vec<Variable>>,
) -> QuerySolutionsIterator {
) -> QuerySolutionIter {
let eval = self.clone();
let tuple_size = variables.len();
QuerySolutionsIterator::new(
QuerySolutionIter::new(
variables,
Box::new(iter.map(move |values| {
let mut result = vec![None; tuple_size];
@ -1837,7 +1837,7 @@ where
fn encode_bindings(
&self,
variables: Rc<Vec<Variable>>,
iter: QuerySolutionsIterator,
iter: QuerySolutionIter,
) -> EncodedTuplesIterator<S::StrId> {
let eval = self.clone();
Box::new(iter.map(move |solution| {

@ -7,16 +7,16 @@ use crate::sparql::model::*;
use std::io::Write;
pub fn write_json_results(
results: QueryResult,
results: QueryResults,
mut sink: impl Write,
) -> Result<(), EvaluationError> {
match results {
QueryResult::Boolean(value) => {
QueryResults::Boolean(value) => {
sink.write_all(b"{\"head\":{},\"boolean\":")?;
sink.write_all(if value { b"true" } else { b"false" })?;
sink.write_all(b"}")?;
}
QueryResult::Solutions(solutions) => {
QueryResults::Solutions(solutions) => {
sink.write_all(b"{\"head\":{\"vars\":[")?;
let mut start_vars = true;
for variable in solutions.variables() {
@ -75,7 +75,7 @@ pub fn write_json_results(
}
sink.write_all(b"]}}")?;
}
QueryResult::Graph(_) => {
QueryResults::Graph(_) => {
return Err(invalid_input_error(
"Graphs could not be formatted to SPARQL query results XML format",
)

@ -1,4 +1,6 @@
//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation.
//!
//! SPARQL evaluation is done from a store. See [`MemoryStore`](../store/memory/struct.MemoryStore.html#method.query) for an example.
mod algebra;
mod dataset;
@ -16,11 +18,11 @@ use crate::sparql::algebra::QueryVariants;
use crate::sparql::dataset::DatasetView;
pub use crate::sparql::error::EvaluationError;
use crate::sparql::eval::SimpleEvaluator;
pub use crate::sparql::model::QueryResult;
pub use crate::sparql::model::QueryResultFormat;
pub use crate::sparql::model::QueryResults;
pub use crate::sparql::model::QueryResultsFormat;
pub use crate::sparql::model::QuerySolution;
pub use crate::sparql::model::QuerySolutionsIterator;
pub use crate::sparql::model::QueryTriplesIterator;
pub use crate::sparql::model::QuerySolutionIter;
pub use crate::sparql::model::QueryTripleIter;
pub use crate::sparql::model::Variable;
pub use crate::sparql::parser::ParseError;
pub use crate::sparql::parser::Query;
@ -141,7 +143,7 @@ impl<S: ReadableEncodedStore + 'static> SimplePreparedQuery<S> {
}
/// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult, EvaluationError> {
pub fn exec(&self) -> Result<QueryResults, EvaluationError> {
match &self.0 {
SimplePreparedQueryAction::Select {
plan,
@ -201,7 +203,7 @@ impl QueryOptions {
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryOptions, QueryResult, ServiceHandler, Query, EvaluationError};
/// use oxigraph::sparql::{QueryOptions, QueryResults, ServiceHandler, Query, EvaluationError};
///
/// #[derive(Default)]
/// struct TestServiceHandler {
@ -211,7 +213,7 @@ impl QueryOptions {
/// impl ServiceHandler for TestServiceHandler {
/// type Error = EvaluationError;
///
/// fn handle(&self,service_name: NamedNode, query: Query) -> Result<QueryResult,EvaluationError> {
/// fn handle(&self,service_name: NamedNode, query: Query) -> Result<QueryResults,EvaluationError> {
/// if service_name == "http://example.com/service" {
/// self.store.query(query, QueryOptions::default())
/// } else {
@ -225,7 +227,7 @@ impl QueryOptions {
/// let ex = NamedNode::new("http://example.com")?;
/// service.store.insert(Quad::new(ex.clone(), ex.clone(), ex.clone(), None));
///
/// if let QueryResult::Solutions(mut solutions) = store.query(
/// if let QueryResults::Solutions(mut solutions) = store.query(
/// "SELECT ?s WHERE { SERVICE <http://example.com/service> { ?s ?p ?o } }",
/// QueryOptions::default().with_service_handler(service)
/// )? {
@ -237,7 +239,7 @@ pub trait ServiceHandler {
type Error: Error + Send + Sync + 'static;
/// Evaluates a [`Query`](struct.Query.html) against a given service identified by a [`NamedNode`](../model/struct.NamedNode.html).
fn handle(&self, service_name: NamedNode, query: Query) -> Result<QueryResult, Self::Error>;
fn handle(&self, service_name: NamedNode, query: Query) -> Result<QueryResults, Self::Error>;
}
struct EmptyServiceHandler;
@ -245,7 +247,7 @@ struct EmptyServiceHandler;
impl ServiceHandler for EmptyServiceHandler {
type Error = EvaluationError;
fn handle(&self, _: NamedNode, _: Query) -> Result<QueryResult, EvaluationError> {
fn handle(&self, _: NamedNode, _: Query) -> Result<QueryResults, EvaluationError> {
Err(EvaluationError::msg(
"The SERVICE feature is not implemented",
))
@ -263,7 +265,7 @@ impl<S: ServiceHandler> ServiceHandler for ErrorConversionServiceHandler<S> {
&self,
service_name: NamedNode,
query: Query,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
self.handler
.handle(service_name, query)
.map_err(EvaluationError::wrap)

@ -6,31 +6,31 @@ use crate::sparql::error::EvaluationError;
use crate::sparql::json_results::write_json_results;
use crate::sparql::xml_results::{read_xml_results, write_xml_results};
use rand::random;
use std::fmt;
use std::io::{BufRead, Write};
use std::rc::Rc;
use std::{fmt, io};
/// Results of a [SPARQL query](https://www.w3.org/TR/sparql11-query/)
pub enum QueryResult {
pub enum QueryResults {
/// Results of a [SELECT](https://www.w3.org/TR/sparql11-query/#select) query
Solutions(QuerySolutionsIterator),
Solutions(QuerySolutionIter),
/// Result of a [ASK](https://www.w3.org/TR/sparql11-query/#ask) query
Boolean(bool),
/// Results of a [CONSTRUCT](https://www.w3.org/TR/sparql11-query/#construct) or [DESCRIBE](https://www.w3.org/TR/sparql11-query/#describe) query
Graph(QueryTriplesIterator),
Graph(QueryTripleIter),
}
impl QueryResult {
impl QueryResults {
/// Reads a SPARQL query results serialization
pub fn read(
reader: impl BufRead + 'static,
format: QueryResultFormat,
) -> Result<Self, EvaluationError> {
format: QueryResultsFormat,
) -> Result<Self, io::Error> {
match format {
QueryResultFormat::Xml => read_xml_results(reader),
QueryResultFormat::Json => Err(invalid_input_error(
QueryResultsFormat::Xml => read_xml_results(reader),
QueryResultsFormat::Json => Err(invalid_input_error(
"JSON SPARQL results format parsing has not been implemented yet",
)
.into()), //TODO: implement
)), //TODO: implement
}
}
@ -41,25 +41,25 @@ impl QueryResult {
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryOptions, QueryResultFormat};
/// use oxigraph::sparql::{QueryOptions, QueryResultsFormat};
///
/// let store = MemoryStore::new();
/// let ex = NamedNode::new("http://example.com")?;
/// store.insert(Quad::new(ex.clone(), ex.clone(), ex.clone(), None));
///
/// let mut results = Vec::new();
/// store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())?.write(&mut results, QueryResultFormat::Json)?;
/// store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())?.write(&mut results, QueryResultsFormat::Json)?;
/// assert_eq!(results, "{\"head\":{\"vars\":[\"s\"]},\"results\":{\"bindings\":[{\"s\":{\"type\":\"uri\",\"value\":\"http://example.com\"}}]}}".as_bytes());
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub fn write(
self,
writer: impl Write,
format: QueryResultFormat,
format: QueryResultsFormat,
) -> Result<(), EvaluationError> {
match format {
QueryResultFormat::Xml => write_xml_results(self, writer),
QueryResultFormat::Json => write_json_results(self, writer),
QueryResultsFormat::Xml => write_xml_results(self, writer),
QueryResultsFormat::Json => write_json_results(self, writer),
}
}
@ -89,7 +89,7 @@ impl QueryResult {
write: impl Write,
format: GraphFormat,
) -> Result<(), EvaluationError> {
if let QueryResult::Graph(triples) = self {
if let QueryResults::Graph(triples) = self {
let mut writer = GraphSerializer::from_format(format).triple_writer(write)?;
for triple in triples {
writer.write(&triple?)?;
@ -105,89 +105,89 @@ impl QueryResult {
}
}
impl From<QuerySolutionsIterator> for QueryResult {
impl From<QuerySolutionIter> for QueryResults {
#[inline]
fn from(value: QuerySolutionsIterator) -> Self {
QueryResult::Solutions(value)
fn from(value: QuerySolutionIter) -> Self {
QueryResults::Solutions(value)
}
}
/// [SPARQL query](https://www.w3.org/TR/sparql11-query/) serialization formats
/// [SPARQL query](https://www.w3.org/TR/sparql11-query/) results serialization formats
///
/// This enumeration is non exhaustive. New formats like CSV will be added in the future.
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
#[non_exhaustive]
pub enum QueryResultFormat {
pub enum QueryResultsFormat {
/// [SPARQL Query Results XML Format](http://www.w3.org/TR/rdf-sparql-XMLres/)
Xml,
/// [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/)
Json,
}
impl QueryResultFormat {
impl QueryResultsFormat {
/// The format canonical IRI according to the [Unique URIs for file formats registry](https://www.w3.org/ns/formats/).
///
/// ```
/// use oxigraph::sparql::QueryResultFormat;
/// use oxigraph::sparql::QueryResultsFormat;
///
/// assert_eq!(QueryResultFormat::Json.iri(), "http://www.w3.org/ns/formats/SPARQL_Results_JSON")
/// assert_eq!(QueryResultsFormat::Json.iri(), "http://www.w3.org/ns/formats/SPARQL_Results_JSON")
/// ```
#[inline]
pub fn iri(self) -> &'static str {
match self {
QueryResultFormat::Xml => "http://www.w3.org/ns/formats/SPARQL_Results_XML",
QueryResultFormat::Json => "http://www.w3.org/ns/formats/SPARQL_Results_JSON",
QueryResultsFormat::Xml => "http://www.w3.org/ns/formats/SPARQL_Results_XML",
QueryResultsFormat::Json => "http://www.w3.org/ns/formats/SPARQL_Results_JSON",
}
}
/// The format [IANA media type](https://tools.ietf.org/html/rfc2046).
///
/// ```
/// use oxigraph::sparql::QueryResultFormat;
/// use oxigraph::sparql::QueryResultsFormat;
///
/// assert_eq!(QueryResultFormat::Json.media_type(), "application/sparql-results+json")
/// assert_eq!(QueryResultsFormat::Json.media_type(), "application/sparql-results+json")
/// ```
#[inline]
pub fn media_type(self) -> &'static str {
match self {
QueryResultFormat::Xml => "application/sparql-results+xml",
QueryResultFormat::Json => "application/sparql-results+json",
QueryResultsFormat::Xml => "application/sparql-results+xml",
QueryResultsFormat::Json => "application/sparql-results+json",
}
}
/// The format [IANA-registered](https://tools.ietf.org/html/rfc2046) file extension.
///
/// ```
/// use oxigraph::sparql::QueryResultFormat;
/// use oxigraph::sparql::QueryResultsFormat;
///
/// assert_eq!(QueryResultFormat::Json.file_extension(), "srj")
/// assert_eq!(QueryResultsFormat::Json.file_extension(), "srj")
/// ```
#[inline]
pub fn file_extension(self) -> &'static str {
match self {
QueryResultFormat::Xml => "srx",
QueryResultFormat::Json => "srj",
QueryResultsFormat::Xml => "srx",
QueryResultsFormat::Json => "srj",
}
}
/// Looks for a known format from a media type.
///
/// It supports some media type aliases.
/// For example "application/xml" is going to return `QueryResultFormat::Xml` even if it is not its canonical media type.
/// For example "application/xml" is going to return `Xml` even if it is not its canonical media type.
///
/// Example:
/// ```
/// use oxigraph::sparql::QueryResultFormat;
/// use oxigraph::sparql::QueryResultsFormat;
///
/// assert_eq!(QueryResultFormat::from_media_type("application/sparql-results+json; charset=utf-8"), Some(QueryResultFormat::Json))
/// assert_eq!(QueryResultsFormat::from_media_type("application/sparql-results+json; charset=utf-8"), Some(QueryResultsFormat::Json))
/// ```
pub fn from_media_type(media_type: &str) -> Option<Self> {
if let Some(base_type) = media_type.split(';').next() {
match base_type {
"application/sparql-results+xml" | "application/xml" | "text/xml" => {
Some(QueryResultFormat::Xml)
Some(QueryResultsFormat::Xml)
}
"application/sparql-results+json" | "application/json" | "text/json" => {
Some(QueryResultFormat::Json)
Some(QueryResultsFormat::Json)
}
_ => None,
}
@ -197,26 +197,26 @@ impl QueryResultFormat {
}
}
/// An iterator over query result solutions
/// An iterator over [`QuerySolution`s](struct.QuerySolution.html)
///
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryResults, QueryOptions};
///
/// let store = MemoryStore::new();
/// if let QueryResult::Solutions(solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// for solution in solutions {
/// println!("{:?}", solution?.get("s"));
/// }
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub struct QuerySolutionsIterator {
pub struct QuerySolutionIter {
variables: Rc<Vec<Variable>>,
iter: Box<dyn Iterator<Item = Result<Vec<Option<Term>>, EvaluationError>>>,
}
impl QuerySolutionsIterator {
impl QuerySolutionIter {
pub fn new(
variables: Rc<Vec<Variable>>,
iter: Box<dyn Iterator<Item = Result<Vec<Option<Term>>, EvaluationError>>>,
@ -228,10 +228,10 @@ impl QuerySolutionsIterator {
///
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::sparql::{QueryResult, QueryOptions, Variable};
/// use oxigraph::sparql::{QueryResults, QueryOptions, Variable};
///
/// let store = MemoryStore::new();
/// if let QueryResult::Solutions(solutions) = store.query("SELECT ?s ?o WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(solutions) = store.query("SELECT ?s ?o WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// assert_eq!(solutions.variables(), &[Variable::new("s"), Variable::new("o")]);
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
@ -242,7 +242,7 @@ impl QuerySolutionsIterator {
}
}
impl Iterator for QuerySolutionsIterator {
impl Iterator for QuerySolutionIter {
type Item = Result<QuerySolution, EvaluationError>;
#[inline]
@ -344,21 +344,21 @@ impl VariableSolutionIndex for Variable {
///
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryResults, QueryOptions};
///
/// let store = MemoryStore::new();
/// if let QueryResult::Graph(triples) = store.query("CONSTRUCT WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Graph(triples) = store.query("CONSTRUCT WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// for triple in triples {
/// println!("{}", triple?);
/// }
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub struct QueryTriplesIterator {
pub struct QueryTripleIter {
pub(crate) iter: Box<dyn Iterator<Item = Result<Triple, EvaluationError>>>,
}
impl Iterator for QueryTriplesIterator {
impl Iterator for QueryTripleIter {
type Item = Result<Triple, EvaluationError>;
#[inline]

@ -12,19 +12,20 @@ use quick_xml::events::Event;
use quick_xml::Reader;
use quick_xml::Writer;
use std::collections::BTreeMap;
use std::io;
use std::io::BufRead;
use std::io::Write;
use std::iter::empty;
use std::rc::Rc;
pub fn write_xml_results(results: QueryResult, sink: impl Write) -> Result<(), EvaluationError> {
pub fn write_xml_results(results: QueryResults, sink: impl Write) -> Result<(), EvaluationError> {
match results {
QueryResult::Boolean(value) => {
QueryResults::Boolean(value) => {
write_boolean(value, sink).map_err(map_xml_error)?;
Ok(())
}
QueryResult::Solutions(solutions) => write_solutions(solutions, sink),
QueryResult::Graph(_) => Err(invalid_input_error(
QueryResults::Solutions(solutions) => write_solutions(solutions, sink),
QueryResults::Graph(_) => Err(invalid_input_error(
"Graphs could not be formatted to SPARQL query results XML format",
)
.into()),
@ -50,10 +51,7 @@ fn write_boolean(value: bool, sink: impl Write) -> Result<(), quick_xml::Error>
Ok(())
}
fn write_solutions(
solutions: QuerySolutionsIterator,
sink: impl Write,
) -> Result<(), EvaluationError> {
fn write_solutions(solutions: QuerySolutionIter, sink: impl Write) -> Result<(), EvaluationError> {
let mut writer = Writer::new(sink);
writer
.write_event(Event::Decl(BytesDecl::new(b"1.0", None, None)))
@ -148,7 +146,7 @@ fn write_solutions(
Ok(())
}
pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, EvaluationError> {
pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResults, io::Error> {
enum State {
Start,
Sparql,
@ -176,8 +174,7 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
return Err(invalid_data_error(format!(
"Unexpected namespace found in RDF/XML query result: {}",
reader.decode(ns).map_err(map_xml_error)?
))
.into());
)));
}
}
event
@ -188,14 +185,14 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
if event.name() == b"sparql" {
state = State::Sparql;
} else {
return Err(invalid_data_error(format!("Expecting <sparql> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting <sparql> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
}
State::Sparql => {
if event.name() == b"head" {
state = State::Head;
} else {
return Err(invalid_data_error(format!("Expecting <head> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting <head> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
}
State::Head => {
@ -208,7 +205,7 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
} else if event.name() == b"link" {
// no op
} else {
return Err(invalid_data_error(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
}
State::AfterHead => {
@ -219,7 +216,7 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
for (i,var) in variables.iter().enumerate() {
mapping.insert(var.as_bytes().to_vec(), i);
}
return Ok(QueryResult::Solutions(QuerySolutionsIterator::new(
return Ok(QueryResults::Solutions(QuerySolutionIter::new(
Rc::new(variables.into_iter().map(Variable::new).collect()),
Box::new(ResultsIterator {
reader,
@ -229,17 +226,17 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
}),
)));
} else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" {
return Err(invalid_data_error(format!("Expecting sparql tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting sparql tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
}
State::Boolean => return Err(invalid_data_error(format!("Unexpected tag inside of <boolean> tag: {}", reader.decode(event.name()).map_err(map_xml_error)?)).into())
State::Boolean => return Err(invalid_data_error(format!("Unexpected tag inside of <boolean> tag: {}", reader.decode(event.name()).map_err(map_xml_error)?)))
},
Event::Empty(event) => match state {
State::Sparql => {
if event.name() == b"head" {
state = State::AfterHead;
} else {
return Err(invalid_data_error(format!("Expecting <head> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting <head> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
}
State::Head => {
@ -252,42 +249,42 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult, E
} else if event.name() == b"link" {
// no op
} else {
return Err(invalid_data_error(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)).into());
return Err(invalid_data_error(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name()).map_err(map_xml_error)?)));
}
},
State::AfterHead => {
if event.name() == b"results" {
return Ok(QueryResult::Solutions(QuerySolutionsIterator::new(
return Ok(QueryResults::Solutions(QuerySolutionIter::new(
Rc::new(variables.into_iter().map(Variable::new).collect()),
Box::new(empty()),
)))
} else {
return Err(invalid_data_error(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name()).map_err(map_xml_error)?)).into())
return Err(invalid_data_error(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name()).map_err(map_xml_error)?)))
}
}
_ => return Err(invalid_data_error(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name()).map_err(map_xml_error)?)).into())
_ => return Err(invalid_data_error(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name()).map_err(map_xml_error)?)))
},
Event::Text(event) => {
let value = event.unescaped().map_err(map_xml_error)?;
return match state {
State::Boolean => {
return if value.as_ref() == b"true" {
Ok(QueryResult::Boolean(true))
Ok(QueryResults::Boolean(true))
} else if value.as_ref() == b"false" {
Ok(QueryResult::Boolean(false))
Ok(QueryResults::Boolean(false))
} else {
Err(invalid_data_error(format!("Unexpected boolean value. Found {}", reader.decode(&value).map_err(map_xml_error)?)).into())
Err(invalid_data_error(format!("Unexpected boolean value. Found {}", reader.decode(&value).map_err(map_xml_error)?)))
};
}
_ => Err(invalid_data_error(format!("Unexpected textual value found: {}", reader.decode(&value).map_err(map_xml_error)?)).into())
_ => Err(invalid_data_error(format!("Unexpected textual value found: {}", reader.decode(&value).map_err(map_xml_error)?)))
};
},
Event::End(_) => if let State::Head = state {
state = State::AfterHead;
} else {
return Err(invalid_data_error("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into());
return Err(invalid_data_error("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag"));
},
Event::Eof => return Err(invalid_data_error("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into()),
Event::Eof => return Err(invalid_data_error("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag")),
_ => (),
}
}
@ -521,10 +518,10 @@ fn build_literal(
}
}
fn map_xml_error(error: quick_xml::Error) -> EvaluationError {
fn map_xml_error(error: quick_xml::Error) -> io::Error {
match error {
quick_xml::Error::Io(error) => error,
quick_xml::Error::UnexpectedEof(_) => io::Error::new(io::ErrorKind::UnexpectedEof, error),
_ => invalid_data_error(error),
}
.into()
}

@ -3,7 +3,7 @@
use crate::error::{invalid_input_error, UnwrapInfallible};
use crate::io::{DatasetFormat, DatasetParser, GraphFormat, GraphParser};
use crate::model::*;
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResults, SimplePreparedQuery};
use crate::store::numeric_encoder::{
Decoder, ReadEncoder, StrContainer, StrEncodingAware, StrId, StrLookup, WriteEncoder,
};
@ -23,14 +23,14 @@ use std::vec::IntoIter;
use std::{fmt, io};
/// In-memory store.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query and update it using SPARQL.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query it using SPARQL.
/// It is cheap to build using the [`MemoryStore::new()`](#method.new) method.
///
/// Usage example:
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryResults, QueryOptions};
///
/// let store = MemoryStore::new();
///
@ -44,7 +44,7 @@ use std::{fmt, io};
/// assert_eq!(vec![quad], results);
///
/// // SPARQL query
/// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
@ -94,7 +94,7 @@ impl MemoryStore {
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryResults, QueryOptions};
///
/// let store = MemoryStore::new();
///
@ -103,7 +103,7 @@ impl MemoryStore {
/// store.insert(Quad::new(ex.clone(), ex.clone(), ex.clone(), None));
///
/// // SPARQL query
/// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
@ -112,7 +112,7 @@ impl MemoryStore {
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
self.prepare_query(query, options)?.exec()
}
@ -123,7 +123,7 @@ impl MemoryStore {
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryResults, QueryOptions};
///
/// let store = MemoryStore::new();
///
@ -133,7 +133,7 @@ impl MemoryStore {
///
/// // SPARQL query
/// let prepared_query = store.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())?;
/// if let QueryResult::Solutions(mut solutions) = prepared_query.exec()? {
/// if let QueryResults::Solutions(mut solutions) = prepared_query.exec()? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
@ -164,8 +164,8 @@ impl MemoryStore {
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
/// store.insert(quad.clone());
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// // quad filter by object
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, Some((&ex).into()), None).collect();
/// assert_eq!(vec![quad], results);
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
@ -241,13 +241,11 @@ impl MemoryStore {
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
///
/// // transaction
/// store.transaction(|transaction| {
/// transaction.insert(quad.clone());
/// Ok(()) as Result<(),Infallible>
/// })?;
///
/// // quad filter
/// assert!(store.contains(&quad));
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
@ -289,10 +287,9 @@ impl MemoryStore {
/// let file = b"<http://example.com> <http://example.com> <http://example.com> .";
/// store.load_graph(file.as_ref(), GraphFormat::NTriples, &GraphName::DefaultGraph, None)?;
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// // we inspect the store contents
/// let ex = NamedNodeRef::new("http://example.com").unwrap();
/// assert!(store.contains(QuadRef::new(ex, ex, ex, None)));
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
///
@ -328,10 +325,9 @@ impl MemoryStore {
/// let file = b"<http://example.com> <http://example.com> <http://example.com> <http://example.com> .";
/// store.load_dataset(file.as_ref(), DatasetFormat::NQuads, None)?;
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results);
/// // we inspect the store contents
/// let ex = NamedNodeRef::new("http://example.com").unwrap();
/// assert!(store.contains(QuadRef::new(ex, ex, ex, ex)));
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
///
@ -396,9 +392,6 @@ impl MemoryStore {
/// assert_eq!(file, buffer.as_slice());
/// # std::io::Result::Ok(())
/// ```
///
/// Errors related to parameter validation like the base IRI use the [`InvalidInput`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidInput) error kind.
/// Errors related to a bad syntax in the loaded file use the [`InvalidData`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData) or [`UnexpectedEof`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.UnexpectedEof) error kinds.
pub fn dump_graph<'a>(
&self,
writer: impl Write,
@ -413,7 +406,7 @@ impl MemoryStore {
)
}
/// Dumps the store dataset into a file.
/// Dumps the store into a file.
///
/// Usage example:
/// ```
@ -430,9 +423,6 @@ impl MemoryStore {
/// assert_eq!(file, buffer.as_slice());
/// # std::io::Result::Ok(())
/// ```
///
/// Errors related to parameter validation like the base IRI use the [`InvalidInput`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidInput) error kind.
/// Errors related to a bad syntax in the loaded file use the [`InvalidData`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData) or [`UnexpectedEof`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.UnexpectedEof) error kinds.
pub fn dump_dataset(&self, writer: impl Write, format: DatasetFormat) -> Result<(), io::Error> {
dump_dataset(
self.quads_for_pattern(None, None, None, None).map(Ok),
@ -1087,7 +1077,7 @@ pub struct MemoryPreparedQuery(SimplePreparedQuery<MemoryStore>);
impl MemoryPreparedQuery {
/// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult, EvaluationError> {
pub fn exec(&self) -> Result<QueryResults, EvaluationError> {
self.0.exec()
}
}
@ -1119,16 +1109,18 @@ impl MemoryTransaction {
/// transaction.load_graph(file.as_ref(), GraphFormat::NTriples, &GraphName::DefaultGraph, None)
/// })?;
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com").unwrap();
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// // we inspect the store content
/// let ex = NamedNodeRef::new("http://example.com").unwrap();
/// assert!(store.contains(&Quad::new(ex.clone(), ex.clone(), ex.clone(), ex.clone())));
/// # Result::<_, oxigraph::sparql::EvaluationError>::Ok(())
/// ```
///
/// If the file parsing fails in the middle of the file, the triples read before are still
/// considered by the transaction. Rollback the transaction by making the transaction closure
/// return an error if you don't want that.
///
/// Errors related to parameter validation like the base IRI use the [`InvalidInput`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidInput) error kind.
/// Errors related to a bad syntax in the loaded file use the [`InvalidData`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData) or [`UnexpectedEof`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.UnexpectedEof) error kinds.
pub fn load_graph<'a>(
&mut self,
reader: impl BufRead,
@ -1164,16 +1156,18 @@ impl MemoryTransaction {
/// let file = b"<http://example.com> <http://example.com> <http://example.com> <http://example.com> .";
/// store.load_dataset(file.as_ref(), DatasetFormat::NQuads, None)?;
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com").unwrap();
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results);
/// // we inspect the store content
/// let ex = NamedNodeRef::new("http://example.com").unwrap();
/// assert!(store.contains(QuadRef::new(ex, ex, ex, ex)));
/// # Result::<_, oxigraph::sparql::EvaluationError>::Ok(())
/// ```
///
/// If the file parsing fails in the middle of the file, the quads read before are still
/// considered by the transaction. Rollback the transaction by making the transaction closure
/// return an error if you don't want that.
///
/// Errors related to parameter validation like the base IRI use the [`InvalidInput`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidInput) error kind.
/// Errors related to a bad syntax in the loaded file use the [`InvalidData`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData) or [`UnexpectedEof`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.UnexpectedEof) error kinds.
pub fn load_dataset(
&mut self,
reader: impl BufRead,

@ -1,7 +1,4 @@
//! RDF quads storage implementations.
//!
//! They encode a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset)
//! and allow querying and updating them using SPARQL.
//! RDF [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) storage implementations.
#[cfg(any(feature = "rocksdb", feature = "sled"))]
mod binary_encoder;

@ -3,7 +3,7 @@
use crate::error::invalid_data_error;
use crate::io::{DatasetFormat, GraphFormat};
use crate::model::*;
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResults, SimplePreparedQuery};
use crate::store::binary_encoder::*;
use crate::store::numeric_encoder::{
Decoder, ReadEncoder, StrContainer, StrEncodingAware, StrLookup, WriteEncoder,
@ -24,7 +24,7 @@ use std::sync::Arc;
use std::{fmt, str};
/// Store based on the [RocksDB](https://rocksdb.org/) key-value database.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query and update it using SPARQL.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query it using SPARQL.
///
/// To use it, the `"rocksdb"` feature needs to be activated.
///
@ -32,7 +32,7 @@ use std::{fmt, str};
/// ```
/// use oxigraph::RocksDbStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryOptions, QueryResult};
/// use oxigraph::sparql::{QueryOptions, QueryResults};
/// # use std::fs::remove_dir_all;
///
/// # {
@ -48,7 +48,7 @@ use std::{fmt, str};
/// assert_eq!(vec![quad], results?);
///
/// // SPARQL query
/// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// }
/// #
@ -126,7 +126,7 @@ impl RocksDbStore {
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
self.prepare_query(query, options)?.exec()
}
@ -314,7 +314,7 @@ impl RocksDbStore {
)
}
/// Dumps the store dataset into a file.
/// Dumps the store into a file.
///
/// See [`MemoryStore`](../memory/struct.MemoryStore.html#method.dump_dataset) for a usage example.
pub fn dump_dataset(&self, writer: impl Write, syntax: DatasetFormat) -> Result<(), io::Error> {
@ -729,7 +729,7 @@ pub struct RocksDbPreparedQuery(SimplePreparedQuery<RocksDbStore>);
impl RocksDbPreparedQuery {
/// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult, EvaluationError> {
pub fn exec(&self) -> Result<QueryResults, EvaluationError> {
self.0.exec()
}
}

@ -3,7 +3,7 @@
use crate::error::invalid_data_error;
use crate::io::{DatasetFormat, GraphFormat};
use crate::model::*;
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResults, SimplePreparedQuery};
use crate::store::binary_encoder::*;
use crate::store::numeric_encoder::{
Decoder, ReadEncoder, StrContainer, StrEncodingAware, StrLookup, WriteEncoder,
@ -25,7 +25,7 @@ use std::path::Path;
use std::{fmt, io, str};
/// Store based on the [Sled](https://sled.rs/) key-value database.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query and update it using SPARQL.
/// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query it using SPARQL.
///
/// To use it, the `"sled"` feature needs to be activated.
///
@ -34,7 +34,7 @@ use std::{fmt, io, str};
/// Usage example:
/// ```
/// use oxigraph::SledStore;
/// use oxigraph::sparql::{QueryOptions, QueryResult};
/// use oxigraph::sparql::{QueryOptions, QueryResults};
/// use oxigraph::model::*;
/// # use std::fs::remove_dir_all;
///
@ -51,7 +51,7 @@ use std::{fmt, io, str};
/// assert_eq!(vec![quad], results?);
///
/// // SPARQL query
/// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// };
/// #
@ -136,7 +136,7 @@ impl SledStore {
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
) -> Result<QueryResult, EvaluationError> {
) -> Result<QueryResults, EvaluationError> {
self.prepare_query(query, options)?.exec()
}
@ -348,7 +348,7 @@ impl SledStore {
)
}
/// Dumps the store dataset into a file.
/// Dumps the store into a file.
///
/// See [`MemoryStore`](../memory/struct.MemoryStore.html#method.dump_dataset) for a usage example.
pub fn dump_dataset(&self, writer: impl Write, format: DatasetFormat) -> Result<(), io::Error> {
@ -1161,7 +1161,7 @@ pub struct SledPreparedQuery(SimplePreparedQuery<SledStore>);
impl SledPreparedQuery {
/// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult, EvaluationError> {
pub fn exec(&self) -> Result<QueryResults, EvaluationError> {
self.0.exec()
}
}

@ -12,7 +12,7 @@ use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol};
use std::io::BufReader;
/// In-memory store.
/// It encodes a `RDF dataset <https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset>`_ and allows to query and update it using SPARQL.
/// It encodes a `RDF dataset <https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset>`_ and allows to query it using SPARQL.
///
///
/// The :py:func:`str` function provides a serialization of the store data compatible with NTriples, Turtle and SPARQL:

@ -14,7 +14,7 @@ use std::io::BufReader;
/// Store based on the `Sled <https://sled.rs/>`_ key-value database.
///
/// In-memory store.
/// It encodes a `RDF dataset <https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset>`_ and allows to query and update it using SPARQL.
/// It encodes a `RDF dataset <https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset>`_ and allows to query it using SPARQL.
///
/// :param path: the path of the directory in which Sled should read and write its data. If the directoty does not exist, it is created. If no directory is provided a temporary one is created and removed when the Python garbage collector removes the store.
/// :type path: str or None

@ -1,7 +1,7 @@
use crate::model::*;
use oxigraph::model::*;
use oxigraph::sparql::{
EvaluationError, QueryResult, QuerySolution, QuerySolutionsIterator, QueryTriplesIterator,
EvaluationError, QueryResults, QuerySolution, QuerySolutionIter, QueryTripleIter,
};
use pyo3::exceptions::{IOError, RuntimeError, SyntaxError, TypeError, ValueError};
use pyo3::prelude::*;
@ -47,11 +47,11 @@ pub fn extract_quads_pattern(
))
}
pub fn query_results_to_python(py: Python<'_>, results: QueryResult) -> PyResult<PyObject> {
pub fn query_results_to_python(py: Python<'_>, results: QueryResults) -> PyResult<PyObject> {
Ok(match results {
QueryResult::Solutions(inner) => QuerySolutionIter { inner }.into_py(py),
QueryResult::Graph(inner) => TripleResultIter { inner }.into_py(py),
QueryResult::Boolean(b) => b.into_py(py),
QueryResults::Solutions(inner) => PyQuerySolutionIter { inner }.into_py(py),
QueryResults::Graph(inner) => PyQueryTripleIter { inner }.into_py(py),
QueryResults::Boolean(b) => b.into_py(py),
})
}
@ -102,13 +102,13 @@ impl PyMappingProtocol for PyQuerySolution {
}
}
#[pyclass(unsendable)]
pub struct QuerySolutionIter {
inner: QuerySolutionsIterator,
#[pyclass(unsendable, name = QuerySolutionIter)]
pub struct PyQuerySolutionIter {
inner: QuerySolutionIter,
}
#[pyproto]
impl PyIterProtocol for QuerySolutionIter {
impl PyIterProtocol for PyQuerySolutionIter {
fn __iter__(slf: PyRefMut<Self>) -> Py<Self> {
slf.into()
}
@ -123,13 +123,13 @@ impl PyIterProtocol for QuerySolutionIter {
}
}
#[pyclass(unsendable)]
pub struct TripleResultIter {
inner: QueryTriplesIterator,
#[pyclass(unsendable, name = QueryTripleIter)]
pub struct PyQueryTripleIter {
inner: QueryTripleIter,
}
#[pyproto]
impl PyIterProtocol for TripleResultIter {
impl PyIterProtocol for PyQueryTripleIter {
fn __iter__(slf: PyRefMut<Self>) -> Py<Self> {
slf.into()
}

@ -22,7 +22,7 @@ use http_types::{
};
use oxigraph::io::{DatasetFormat, GraphFormat};
use oxigraph::model::{GraphName, NamedNode};
use oxigraph::sparql::{Query, QueryOptions, QueryResult, QueryResultFormat, ServiceHandler};
use oxigraph::sparql::{Query, QueryOptions, QueryResults, QueryResultsFormat, ServiceHandler};
use oxigraph::RocksDbStore;
use std::fmt;
use std::io::{BufReader, Cursor};
@ -183,7 +183,7 @@ async fn evaluate_sparql_query(
let options = QueryOptions::default().with_service_handler(HttpService::default());
let results = store.query(query, options)?;
//TODO: stream
if let QueryResult::Graph(_) = results {
if let QueryResults::Graph(_) = results {
let format = content_negotiation(
request,
&[
@ -202,10 +202,10 @@ async fn evaluate_sparql_query(
let format = content_negotiation(
request,
&[
QueryResultFormat::Xml.media_type(),
QueryResultFormat::Json.media_type(),
QueryResultsFormat::Xml.media_type(),
QueryResultsFormat::Json.media_type(),
],
QueryResultFormat::from_media_type,
QueryResultsFormat::from_media_type,
)?;
let mut body = Vec::default();
results.write(&mut body, format)?;
@ -325,7 +325,7 @@ impl ServiceHandler for HttpService {
&self,
service_name: NamedNode,
query: Query,
) -> std::result::Result<QueryResult, HttpServiceError> {
) -> std::result::Result<QueryResults, HttpServiceError> {
let mut request = Request::new(
Method::Post,
Url::parse(service_name.as_str()).map_err(Error::from)?,
@ -343,7 +343,7 @@ impl ServiceHandler for HttpService {
let (content_type, data) = response?;
let syntax = if let Some(content_type) = content_type {
QueryResultFormat::from_media_type(content_type.essence()).ok_or_else(|| {
QueryResultsFormat::from_media_type(content_type.essence()).ok_or_else(|| {
format_err!(
"Unexpected federated query result type from {}: {}",
service_name,
@ -351,9 +351,9 @@ impl ServiceHandler for HttpService {
)
})?
} else {
QueryResultFormat::Xml
QueryResultsFormat::Xml
};
Ok(QueryResult::read(Cursor::new(data), syntax).map_err(Error::from)?)
Ok(QueryResults::read(Cursor::new(data), syntax).map_err(Error::from)?)
}
}

@ -131,12 +131,12 @@ fn evaluate_sparql_test(test: &Test) -> Result<()> {
fn load_sparql_query_result(url: &str) -> Result<StaticQueryResults> {
if url.ends_with(".srx") {
StaticQueryResults::from_query_results(
QueryResult::read(read_file(url)?, QueryResultFormat::Xml)?,
QueryResults::read(read_file(url)?, QueryResultsFormat::Xml)?,
false,
)
} else if url.ends_with(".srj") {
StaticQueryResults::from_query_results(
QueryResult::read(read_file(url)?, QueryResultFormat::Json)?,
QueryResults::read(read_file(url)?, QueryResultsFormat::Json)?,
false,
)
} else {
@ -174,7 +174,7 @@ impl ServiceHandler for StaticServiceHandler {
&self,
service_name: NamedNode,
query: Query,
) -> std::result::Result<QueryResult, EvaluationError> {
) -> std::result::Result<QueryResults, EvaluationError> {
self.services
.get(&service_name)
.ok_or_else(|| {
@ -190,12 +190,12 @@ impl ServiceHandler for StaticServiceHandler {
}
}
fn to_dataset(result: QueryResult, with_order: bool) -> Result<MemoryStore> {
fn to_dataset(result: QueryResults, with_order: bool) -> Result<MemoryStore> {
match result {
QueryResult::Graph(graph) => Ok(graph
QueryResults::Graph(graph) => Ok(graph
.map(|t| t.map(|t| t.in_graph(None)))
.collect::<Result<_, _>>()?),
QueryResult::Boolean(value) => {
QueryResults::Boolean(value) => {
let store = MemoryStore::new();
let result_set = BlankNode::default();
store.insert(Quad::new(
@ -212,7 +212,7 @@ fn to_dataset(result: QueryResult, with_order: bool) -> Result<MemoryStore> {
));
Ok(store)
}
QueryResult::Solutions(solutions) => {
QueryResults::Solutions(solutions) => {
let store = MemoryStore::new();
let result_set = BlankNode::default();
store.insert(Quad::new(
@ -363,7 +363,7 @@ impl fmt::Display for StaticQueryResults {
}
impl StaticQueryResults {
fn from_query_results(results: QueryResult, with_order: bool) -> Result<StaticQueryResults> {
fn from_query_results(results: QueryResults, with_order: bool) -> Result<StaticQueryResults> {
Ok(Self::from_dataset(to_dataset(results, with_order)?))
}

@ -22,7 +22,7 @@ use http_types::{
};
use oxigraph::io::GraphFormat;
use oxigraph::model::NamedNode;
use oxigraph::sparql::{Query, QueryOptions, QueryResult, QueryResultFormat, ServiceHandler};
use oxigraph::sparql::{Query, QueryOptions, QueryResults, QueryResultsFormat, ServiceHandler};
use oxigraph::RocksDbStore;
use std::fmt;
use std::io::Cursor;
@ -191,7 +191,7 @@ async fn evaluate_sparql_query(
.with_default_graph_as_union()
.with_service_handler(HttpService::default());
let results = store.query(query, options)?;
if let QueryResult::Graph(_) = results {
if let QueryResults::Graph(_) = results {
let format = content_negotiation(
request,
&[
@ -210,10 +210,10 @@ async fn evaluate_sparql_query(
let format = content_negotiation(
request,
&[
QueryResultFormat::Xml.media_type(),
QueryResultFormat::Json.media_type(),
QueryResultsFormat::Xml.media_type(),
QueryResultsFormat::Json.media_type(),
],
QueryResultFormat::from_media_type,
QueryResultsFormat::from_media_type,
)?;
let mut body = Vec::default();
results.write(&mut body, format)?;
@ -315,7 +315,7 @@ impl ServiceHandler for HttpService {
&self,
service_name: NamedNode,
query: Query,
) -> std::result::Result<QueryResult, HttpServiceError> {
) -> std::result::Result<QueryResults, HttpServiceError> {
let mut request = Request::new(
Method::Post,
Url::parse(service_name.as_str()).map_err(Error::from)?,
@ -333,7 +333,7 @@ impl ServiceHandler for HttpService {
let (content_type, data) = response?;
let syntax = if let Some(content_type) = content_type {
QueryResultFormat::from_media_type(content_type.essence()).ok_or_else(|| {
QueryResultsFormat::from_media_type(content_type.essence()).ok_or_else(|| {
format_err!(
"Unexpected federated query result type from {}: {}",
service_name,
@ -341,9 +341,9 @@ impl ServiceHandler for HttpService {
)
})?
} else {
QueryResultFormat::Xml
QueryResultsFormat::Xml
};
Ok(QueryResult::read(Cursor::new(data), syntax).map_err(Error::from)?)
Ok(QueryResults::read(Cursor::new(data), syntax).map_err(Error::from)?)
}
}

Loading…
Cancel
Save