Makes sparesults formatter API closer to oxrdfio

pull/635/head
Tpt 1 year ago committed by Thomas Tanon
parent 0783d1dcda
commit 6a21cb0625
  1. 19
      cli/src/main.rs
  2. 4
      fuzz/src/result_format.rs
  3. 8
      lib/sparesults/README.md
  4. 2
      lib/sparesults/src/lib.rs
  5. 84
      lib/sparesults/src/serializer.rs
  6. 9
      lib/src/sparql/model.rs
  7. 8
      lib/src/sparql/results.rs
  8. 4
      python/src/sparql.rs

@ -555,7 +555,7 @@ pub fn main() -> anyhow::Result<()> {
};
if let Some(results_file) = results_file {
let mut writer = QueryResultsSerializer::from_format(format)
.solutions_writer(
.serialize_solutions_to_write(
BufWriter::new(File::create(results_file)?),
solutions.variables().to_vec(),
)?;
@ -565,7 +565,7 @@ pub fn main() -> anyhow::Result<()> {
close_file_writer(writer.finish()?)?;
} else {
let mut writer = QueryResultsSerializer::from_format(format)
.solutions_writer(
.serialize_solutions_to_write(
stdout().lock(),
solutions.variables().to_vec(),
)?;
@ -595,14 +595,15 @@ pub fn main() -> anyhow::Result<()> {
};
if let Some(results_file) = results_file {
close_file_writer(
QueryResultsSerializer::from_format(format).write_boolean_result(
BufWriter::new(File::create(results_file)?),
result,
)?,
QueryResultsSerializer::from_format(format)
.serialize_boolean_to_write(
BufWriter::new(File::create(results_file)?),
result,
)?,
)?;
} else {
QueryResultsSerializer::from_format(format)
.write_boolean_result(stdout().lock(), result)?
.serialize_boolean_to_write(stdout().lock(), result)?
.flush()?;
}
}
@ -1318,7 +1319,7 @@ fn evaluate_sparql_query(
move |w| {
Ok((
QueryResultsSerializer::from_format(format)
.solutions_writer(w, solutions.variables().to_vec())?,
.serialize_solutions_to_write(w, solutions.variables().to_vec())?,
solutions,
))
},
@ -1338,7 +1339,7 @@ fn evaluate_sparql_query(
let format = query_results_content_negotiation(request)?;
let mut body = Vec::new();
QueryResultsSerializer::from_format(format)
.write_boolean_result(&mut body, result)
.serialize_boolean_to_write(&mut body, result)
.map_err(internal_server_error)?;
Ok(Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, format.media_type())

@ -18,7 +18,7 @@ pub fn fuzz_result_format(format: QueryResultsFormat, data: &[u8]) {
// We try to write again
let mut writer = serializer
.solutions_writer(
.serialize_solutions_to_write(
Vec::new(),
solutions
.get(0)
@ -49,7 +49,7 @@ pub fn fuzz_result_format(format: QueryResultsFormat, data: &[u8]) {
// We try to write again
let mut serialized = Vec::new();
serializer
.write_boolean_result(&mut serialized, value)
.serialize_boolean_to_write(&mut serialized, value)
.unwrap();
// And to parse again

@ -28,15 +28,15 @@ fn convert_json_to_tsv(json_file: &[u8]) -> Result<Vec<u8>> {
match json_parser.read_results(json_file)? {
QueryResultsReader::Boolean(value) => {
// it's a boolean result, we copy it in TSV to the output buffer
tsv_serializer.write_boolean_result(Vec::new(), value)
tsv_serializer.serialize_boolean_to_write(Vec::new(), value)
},
QueryResultsReader::Solutions(solutions_reader) => {
// it's a set of solutions, we create a writer and we write to it while reading in streaming from the JSON file
let mut solutions_writer = tsv_serializer.solutions_writer(Vec::new(), solutions_reader.variables().to_vec())?;
let mut serialize_solutions_to_write = tsv_serializer.serialize_solutions_to_write(Vec::new(), solutions_reader.variables().to_vec())?;
for solution in solutions_reader {
solutions_writer.write(&solution?)?;
serialize_solutions_to_write.write(&solution?)?;
}
solutions_writer.finish()
serialize_solutions_to_write.finish()
}
}
}

@ -16,5 +16,5 @@ mod xml;
pub use crate::error::{ParseError, SyntaxError};
pub use crate::format::QueryResultsFormat;
pub use crate::parser::{QueryResultsParser, QueryResultsReader, SolutionsReader};
pub use crate::serializer::{QueryResultsSerializer, SolutionsWriter};
pub use crate::serializer::{QueryResultsSerializer, ToWriteSolutionsWriter};
pub use crate::solution::QuerySolution;

@ -25,12 +25,12 @@ use std::io::{self, Write};
///
/// // boolean
/// let mut buffer = Vec::new();
/// json_serializer.write_boolean_result(&mut buffer, true)?;
/// json_serializer.serialize_boolean_to_write(&mut buffer, true)?;
/// assert_eq!(buffer, b"{\"head\":{},\"boolean\":true}");
///
/// // solutions
/// let mut buffer = Vec::new();
/// let mut writer = json_serializer.solutions_writer(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// let mut writer = json_serializer.serialize_solutions_to_write(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// writer.write(once((VariableRef::new_unchecked("foo"), LiteralRef::from("test"))))?;
/// writer.finish()?;
/// assert_eq!(buffer, b"{\"head\":{\"vars\":[\"foo\",\"bar\"]},\"results\":{\"bindings\":[{\"foo\":{\"type\":\"literal\",\"value\":\"test\"}}]}}");
@ -55,21 +55,30 @@ impl QueryResultsSerializer {
///
/// let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Xml);
/// let mut buffer = Vec::new();
/// json_serializer.write_boolean_result(&mut buffer, true)?;
/// json_serializer.serialize_boolean_to_write(&mut buffer, true)?;
/// assert_eq!(buffer, b"<?xml version=\"1.0\"?><sparql xmlns=\"http://www.w3.org/2005/sparql-results#\"><head></head><boolean>true</boolean></sparql>");
/// # std::io::Result::Ok(())
/// ```
pub fn write_boolean_result<W: Write>(&self, writer: W, value: bool) -> io::Result<W> {
pub fn serialize_boolean_to_write<W: Write>(&self, write: W, value: bool) -> io::Result<W> {
match self.format {
QueryResultsFormat::Xml => write_boolean_xml_result(writer, value),
QueryResultsFormat::Json => write_boolean_json_result(writer, value),
QueryResultsFormat::Csv => write_boolean_csv_result(writer, value),
QueryResultsFormat::Tsv => write_boolean_tsv_result(writer, value),
QueryResultsFormat::Xml => write_boolean_xml_result(write, value),
QueryResultsFormat::Json => write_boolean_json_result(write, value),
QueryResultsFormat::Csv => write_boolean_csv_result(write, value),
QueryResultsFormat::Tsv => write_boolean_tsv_result(write, value),
}
}
#[deprecated(note = "Use serialize_boolean_to_write")]
pub fn write_boolean_result<W: Write>(&self, writer: W, value: bool) -> io::Result<W> {
self.serialize_boolean_to_write(writer, value)
}
/// Returns a `SolutionsWriter` allowing writing query solutions into the given [`Write`] implementation.
///
/// <div class="warning">Do not forget to run the [`finish`](ToWriteSolutionsWriter::finish()) method to properly write the last bytes of the file.</div>
///
/// <div class="warning">This writer does unbuffered writes. You might want to use [`BufWriter`](io::BufWriter) to avoid that.</div>
///
/// Example in XML (the API is the same for JSON and TSV):
/// ```
/// use sparesults::{QueryResultsFormat, QueryResultsSerializer};
@ -78,40 +87,51 @@ impl QueryResultsSerializer {
///
/// let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Xml);
/// let mut buffer = Vec::new();
/// let mut writer = json_serializer.solutions_writer(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// let mut writer = json_serializer.serialize_solutions_to_write(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// writer.write(once((VariableRef::new_unchecked("foo"), LiteralRef::from("test"))))?;
/// writer.finish()?;
/// assert_eq!(buffer, b"<?xml version=\"1.0\"?><sparql xmlns=\"http://www.w3.org/2005/sparql-results#\"><head><variable name=\"foo\"/><variable name=\"bar\"/></head><results><result><binding name=\"foo\"><literal>test</literal></binding></result></results></sparql>");
/// # std::io::Result::Ok(())
/// ```
pub fn solutions_writer<W: Write>(
pub fn serialize_solutions_to_write<W: Write>(
&self,
writer: W,
write: W,
variables: Vec<Variable>,
) -> io::Result<SolutionsWriter<W>> {
Ok(SolutionsWriter {
) -> io::Result<ToWriteSolutionsWriter<W>> {
Ok(ToWriteSolutionsWriter {
formatter: match self.format {
QueryResultsFormat::Xml => {
SolutionsWriterKind::Xml(XmlSolutionsWriter::start(writer, &variables)?)
ToWriteSolutionsWriterKind::Xml(XmlSolutionsWriter::start(write, &variables)?)
}
QueryResultsFormat::Json => {
SolutionsWriterKind::Json(JsonSolutionsWriter::start(writer, &variables)?)
ToWriteSolutionsWriterKind::Json(JsonSolutionsWriter::start(write, &variables)?)
}
QueryResultsFormat::Csv => {
SolutionsWriterKind::Csv(CsvSolutionsWriter::start(writer, variables)?)
ToWriteSolutionsWriterKind::Csv(CsvSolutionsWriter::start(write, variables)?)
}
QueryResultsFormat::Tsv => {
SolutionsWriterKind::Tsv(TsvSolutionsWriter::start(writer, variables)?)
ToWriteSolutionsWriterKind::Tsv(TsvSolutionsWriter::start(write, variables)?)
}
},
})
}
#[deprecated(note = "Use serialize_solutions_to_write")]
pub fn solutions_writer<W: Write>(
&self,
writer: W,
variables: Vec<Variable>,
) -> io::Result<ToWriteSolutionsWriter<W>> {
self.serialize_solutions_to_write(writer, variables)
}
}
/// Allows writing query results.
/// Could be built using a [`QueryResultsSerializer`].
///
/// <div class="warning">Do not forget to run the [`finish`](SolutionsWriter::finish()) method to properly write the last bytes of the file.</div>
/// <div class="warning">Do not forget to run the [`finish`](ToWriteSolutionsWriter::finish()) method to properly write the last bytes of the file.</div>
///
/// <div class="warning">This writer does unbuffered writes. You might want to use [`BufWriter`](io::BufWriter) to avoid that.</div>
///
/// Example in TSV (the API is the same for JSON and XML):
/// ```
@ -121,25 +141,25 @@ impl QueryResultsSerializer {
///
/// let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Tsv);
/// let mut buffer = Vec::new();
/// let mut writer = json_serializer.solutions_writer(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// let mut writer = json_serializer.serialize_solutions_to_write(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// writer.write(once((VariableRef::new_unchecked("foo"), LiteralRef::from("test"))))?;
/// writer.finish()?;
/// assert_eq!(buffer, b"?foo\t?bar\n\"test\"\t\n");
/// # std::io::Result::Ok(())
/// ```
#[must_use]
pub struct SolutionsWriter<W: Write> {
formatter: SolutionsWriterKind<W>,
pub struct ToWriteSolutionsWriter<W: Write> {
formatter: ToWriteSolutionsWriterKind<W>,
}
enum SolutionsWriterKind<W: Write> {
enum ToWriteSolutionsWriterKind<W: Write> {
Xml(XmlSolutionsWriter<W>),
Json(JsonSolutionsWriter<W>),
Csv(CsvSolutionsWriter<W>),
Tsv(TsvSolutionsWriter<W>),
}
impl<W: Write> SolutionsWriter<W> {
impl<W: Write> ToWriteSolutionsWriter<W> {
/// Writes a solution.
///
/// Example in JSON (the API is the same for XML and TSV):
@ -150,7 +170,7 @@ impl<W: Write> SolutionsWriter<W> {
///
/// let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Json);
/// let mut buffer = Vec::new();
/// let mut writer = json_serializer.solutions_writer(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// let mut writer = json_serializer.serialize_solutions_to_write(&mut buffer, vec![Variable::new_unchecked("foo"), Variable::new_unchecked("bar")])?;
/// writer.write(once((VariableRef::new_unchecked("foo"), LiteralRef::from("test"))))?;
/// writer.write(&QuerySolution::from((vec![Variable::new_unchecked("bar")], vec![Some(Literal::from("test").into())])))?;
/// writer.finish()?;
@ -163,20 +183,20 @@ impl<W: Write> SolutionsWriter<W> {
) -> io::Result<()> {
let solution = solution.into_iter().map(|(v, s)| (v.into(), s.into()));
match &mut self.formatter {
SolutionsWriterKind::Xml(writer) => writer.write(solution),
SolutionsWriterKind::Json(writer) => writer.write(solution),
SolutionsWriterKind::Csv(writer) => writer.write(solution),
SolutionsWriterKind::Tsv(writer) => writer.write(solution),
ToWriteSolutionsWriterKind::Xml(writer) => writer.write(solution),
ToWriteSolutionsWriterKind::Json(writer) => writer.write(solution),
ToWriteSolutionsWriterKind::Csv(writer) => writer.write(solution),
ToWriteSolutionsWriterKind::Tsv(writer) => writer.write(solution),
}
}
/// Writes the last bytes of the file.
pub fn finish(self) -> io::Result<W> {
match self.formatter {
SolutionsWriterKind::Xml(write) => write.finish(),
SolutionsWriterKind::Json(write) => write.finish(),
SolutionsWriterKind::Csv(write) => write.finish(),
SolutionsWriterKind::Tsv(write) => write.finish(),
ToWriteSolutionsWriterKind::Xml(write) => write.finish(),
ToWriteSolutionsWriterKind::Json(write) => write.finish(),
ToWriteSolutionsWriterKind::Csv(write) => write.finish(),
ToWriteSolutionsWriterKind::Tsv(write) => write.finish(),
}
}
}

@ -58,12 +58,12 @@ impl QueryResults {
match self {
Self::Boolean(value) => {
serializer
.write_boolean_result(writer, value)
.serialize_boolean_to_write(writer, value)
.map_err(EvaluationError::ResultsSerialization)?;
}
Self::Solutions(solutions) => {
let mut writer = serializer
.solutions_writer(writer, solutions.variables().to_vec())
.serialize_solutions_to_write(writer, solutions.variables().to_vec())
.map_err(EvaluationError::ResultsSerialization)?;
for solution in solutions {
writer
@ -79,7 +79,10 @@ impl QueryResults {
let p = VariableRef::new_unchecked("predicate");
let o = VariableRef::new_unchecked("object");
let mut writer = serializer
.solutions_writer(writer, vec![s.into_owned(), p.into_owned(), o.into_owned()])
.serialize_solutions_to_write(
writer,
vec![s.into_owned(), p.into_owned(), o.into_owned()],
)
.map_err(EvaluationError::ResultsSerialization)?;
for triple in triples {
let triple = triple?;

@ -15,15 +15,15 @@
//! match json_parser.read_results(json_file)? {
//! QueryResultsReader::Boolean(value) => {
//! // it's a boolean result, we copy it in TSV to the output buffer
//! tsv_serializer.write_boolean_result(Vec::new(), value)
//! tsv_serializer.serialize_boolean_to_write(Vec::new(), value)
//! },
//! QueryResultsReader::Solutions(solutions_reader) => {
//! // it's a set of solutions, we create a writer and we write to it while reading in streaming from the JSON file
//! let mut solutions_writer = tsv_serializer.solutions_writer(Vec::new(), solutions_reader.variables().to_vec())?;
//! let mut serialize_solutions_to_write = tsv_serializer.serialize_solutions_to_write(Vec::new(), solutions_reader.variables().to_vec())?;
//! for solution in solutions_reader {
//! solutions_writer.write(&solution?)?;
//! serialize_solutions_to_write.write(&solution?)?;
//! }
//! solutions_writer.finish()
//! serialize_solutions_to_write.finish()
//! }
//! }
//! }

@ -247,7 +247,7 @@ impl PyQuerySolutions {
PyWritable::do_write(
|output, format| {
let mut writer = QueryResultsSerializer::from_format(format)
.solutions_writer(
.serialize_solutions_to_write(
output,
match &self.inner {
PyQuerySolutionsVariant::Query(inner) => inner.variables().to_vec(),
@ -349,7 +349,7 @@ impl PyQueryBoolean {
|output, format| {
py.allow_threads(|| {
QueryResultsSerializer::from_format(format)
.write_boolean_result(output, self.inner)
.serialize_boolean_to_write(output, self.inner)
.map_err(map_io_err)
})
},

Loading…
Cancel
Save