oxiland 0.13.0

Embedded RDF datasets, SPARQL, persistence, and streaming I/O for Rust
Documentation
# Design: 0.3 query / update / results API

Status: accepted with ADR-009–ADR-012  
Milestone: 0.3  
Engine: Oxigraph 0.5.9 (+ spargebra 0.4.6 for algebra `Slice`)

## Goals

Provide a Redland-shaped SPARQL facade that:

- configures queries before execution;
- streams solutions and graph results without mandatory materialization;
- exposes Update and dataset selection;
- serializes SPARQL results in XML/JSON/CSV/TSV where practical.

## Public types (owned facade)

| Type | Role |
|---|---|
| `Query` | Builder: text, base IRI, prefixes, limit/offset, dataset, cancel token |
| `Update` | Builder for SPARQL Update |
| `QueryResults` | Owned thin wrapper over Oxigraph streams (`Boolean` / `Solutions` / `Graph`) with non-draining `Debug` |
| `ResultsFormat` | Closed set: Xml, Json, Csv, Tsv |
| `CancellationToken` | Re-export; cancel from another thread |

Variable lookup uses Oxigraph `QuerySolution::get` (name or position). Unbound
bindings are `None` (ADR-009).

## Limit / offset

API `limit` / `offset` replace any existing algebra `Slice` (including
in-query `LIMIT`/`OFFSET`) on SELECT / CONSTRUCT / DESCRIBE with a single
`GraphPattern::Slice`, then `SparqlEvaluator::for_query`. ASK rejects
API-level slice with `Error::Unsupported` at builder time (use filters in the
query text if needed).

In-query `LIMIT`/`OFFSET` alone continue to work via normal SPARQL parsing when
API limit/offset are unset.

## Dataset

`Query::default_graph`, `default_graph_as_union`, and
`available_named_graphs` map to `PreparedSparqlQuery::dataset_mut()`.
Update USING datasets use `PreparedSparqlUpdate::using_datasets_mut()` when
configured via `Update::default_graph` / `default_graph_as_union`. Operations
that do not expose USING datasets (`INSERT DATA` / `DELETE DATA`) return
`Error::Unsupported` if dataset configuration is set.

## Results serialization

- ASK / SELECT → `ResultsFormat` serializers (sparesults via
  `oxigraph::sparql::results`).
- CONSTRUCT / DESCRIBE graphs → `serialize_graph_results_to_writer` or
  existing `io::Serializer` (RDF syntaxes).
- Unknown format names → `Error::Unsupported`.

## Cancellation

`Query::cancellation_token` / `Update::cancellation_token` forward to
`SparqlEvaluator::with_cancellation_token`. Wall-clock timeouts are not a
facade API; callers cancel the token from another thread (ADR-012).

## Fjall and Update

SPARQL Update mutates the Oxigraph store under the model write lock. For
`Model::open` stores, Oxiland resyncs the Fjall durable copy after a successful
update using compensated inserts/deletes so a mid-sync failure restores the
pre-update on-disk key set. The in-memory store is then reloaded from that
snapshot.

## Escape hatch

`oxiland::sparql` re-exports Oxigraph primitives for advanced use. Inventory
and parity evidence cite only the owned facade.