rules_rdf
Bazel rules for RDF — toolchain types for SPARQL, SHACL validation, format conversion, and reasoning. Concrete implementations live in sibling repos like rules_jena.
| Latest | 0.4.0 |
|---|---|
| Versions | 5 |
| Category | Bazel rules |
| Maintainers | Matt Marshall |
| Registry | https://registry.tbzl.dev/modules/rules_rdf/ |
| Source | github.com/tomato-bazel/rules_rdf |
bazel_dep(name = "rules_rdf", version = "0.4.0")
View source & releases on GitHub ↗
Bazel rules for RDF. Defines abstract toolchain types for the four operations that show up in every production RDF/knowledge-graph pipeline — SPARQL query execution, SHACL validation, format conversion, and reasoning — and leaves the engine choice to a concrete toolchain registered by the consumer. The host repo only registers toolchains; the rules themselves are engine-agnostic.
rules_rdf also hosts the canonical RDF statement substrate —
//rdf:statement_proto (fastverk.rdf.v1): Jena-protobuf-shaped
Term / Triple / Quad / Literal / PrefixDecl / RdfStatement, the
L1 wire format graph data reduces to (keyed on stable IRIs). Schema-only;
consumers generate their own language bindings.
Status: v0.2.0
What v0.2 adds on top of v0.1.0:
rdf_reason(//reason:defs.bzl) — build-action rule that runs the registeredrdf_reasonertoolchain over a base dataset and emits the derived-triples graph (Turtle) as a file artifact. Provides a freshRdfDatasetInfoso consumers can chain reason → validate → query. Supports built-in profiles (rdfs,owl-rl,owl-mini,owl-micro) +customwith a Jena rule file.rdf_transform(//transform:defs.bzl) — converts a dataset between serializations via the registeredrdf_serializertoolchain. Output extension follows the target format.- Binary RDF support —
rdfthriftandrdfprotobufadded toRDF_FORMATS(Apache Jena’s binary serializations). Useful as cached intermediate forms; significantly faster to parse than Turtle for large datasets. Consumed byrdf_transform’sout_format+ accepted byrdf_dataset’ssrcsvia.rt/.rpb/.binextensions. - Four no-op smoke plugins (bash) covering every toolchain
type.
bazel test //...runs 14/14 — every public rule exercised end-to-end without needing rules_jena.
v0.1.0 status (still shipped):
What ships:
- Four
toolchain_typedeclarations in//rdf:(sparql_engine,rdf_validator,rdf_serializer,rdf_reasoner). - One
rdf_*_toolchainrule per type for plugin registration (//rdf:toolchains.bzl), each carrying the binary + its runfiles so py_binary / java_binary plugins resolve cleanly inside the Bazel sandbox. - Five providers (
SparqlEngineToolchainInfo,RdfValidatorToolchainInfo,RdfSerializerToolchainInfo,RdfReasonerToolchainInfo,RdfDatasetInfo). rdf_dataset(name, srcs, in_format)— bundle RDF files into a format-tagged provider for downstream rules.sparql_query_test(name, dataset, query)— zero-row SPARQL gate. The workhorse rule; resolvessparql_engine_toolchain_type.rdf_validate_test(name, dataset, shapes, severity)— SHACL gate viardf_validator_toolchain_type.rdf_plugin_contract_test(name, plugin, toolchain_type)— runs the conformance driver (Python) against any plugin executable. Four scenarios:valid_minimal,malformed_input,unknown_flag,determinism.- Plugin contract finalized at
rdf/plugin_contract.md(v1). - Stardoc-generated reference in
docs/for every public-API file. - End-to-end smoke test in
examples/smoke/— a no-op Python SPARQL engine registered as a toolchain, exercised through bothsparql_query_testandrdf_plugin_contract_test. Both pass.
Deferred to v0.2:
sparql_query_run,rdf_transform,rdf_reason(need wider toolchain coverage; rules_jena unblocks them).- ShEx support in
rdf_validate_test(the toolchain contract leaves room via a future--shapes-languageflag). - Cross-format dataset support (mixed
in_formatin one dataset).
Architecture
Plugins implement a minimal stdin/argv/stdout contract; per-operation Bazel rules wrap them. Concrete RDF engines (Apache Jena, RDF4J, Oxigraph, …) live in sibling repos and register toolchains against the abstract types defined here.
//rdf: operation-neutral core
- toolchain_type definitions per RDF operation
- provider definitions (RdfDatasetInfo, …)
- rdf_*_toolchain rules (register a plugin)
- rdf_plugin_contract_test rule (verify a plugin conforms)
- plugin_contract.md (authoritative spec)
//sparql: SPARQL query rules
- sparql_query_test, sparql_query_run
//shacl: SHACL validation rules
- rdf_validate_test
//convert: format conversion rules
- rdf_transform
//reason: inference rules
- rdf_reason
Adding a new RDF engine is:
- Write four plugin binaries (one per toolchain type) — or a single multi-tool binary dispatched on a subcommand flag. Each conforms to the plugin contract.
- Register one
rdf_*_toolchainper operation pointing at the appropriate plugin. - Gate registration with
rdf_plugin_contract_test.
Planned toolchain types
| Type | Operation | Inputs | Output |
|---|---|---|---|
sparql_engine_toolchain_type | Run a SPARQL query against an RDF dataset | dataset (one or more graph files) + .rq query file | query results (SRX / JSON / TSV / CSV / Turtle for CONSTRUCT) |
rdf_validator_toolchain_type | Validate a dataset against a SHACL shapes graph | dataset + shapes.ttl | validation report (Turtle, sh:ValidationReport) |
rdf_serializer_toolchain_type | Convert RDF between serializations | dataset in format A | same graph in format B (Turtle ↔ N-Triples ↔ JSON-LD ↔ RDF/XML ↔ TriG ↔ N-Quads) |
rdf_reasoner_toolchain_type | Materialise inferred triples | dataset + reasoning profile (rdfs, owl-rl, custom rules) | derived-triples graph (Turtle) |
Each type resolves a single plugin executable per consumer; an engine ships up to four plugins (or one binary with four subcommands) and registers each independently so a consumer can mix-and-match — e.g. Jena for SPARQL and Oxigraph for reasoning — without rebuilding the toolchain.
Planned user-facing rules
| Rule | Toolchain | Purpose |
|---|---|---|
rdf_dataset | (none) | Bundle one or more graph files + format hints into an RdfDatasetInfo provider consumed by every downstream rule. |
sparql_query_test | sparql_engine_toolchain_type | Zero-row gate — run a .rq query and fail the build if the result set is non-empty. The canonical SPARQL gate idiom. |
sparql_query_run | sparql_engine_toolchain_type | Run a query and emit the result set as a build artifact. |
rdf_validate_test | rdf_validator_toolchain_type | Run SHACL validation; fail the build on any sh:Violation. |
rdf_transform | rdf_serializer_toolchain_type | Convert a dataset between serializations. Idempotent on the same format. |
rdf_reason | rdf_reasoner_toolchain_type | Emit the inferred triples for a dataset under a reasoning profile. |
sparql_query_test is the workhorse — the production graph at
kg/java/ uses the same “non-empty result set means violation”
idiom for every PR gate, and rules_rdf lifts that idiom into a
first-class Bazel rule.
The plugin contract
A plugin is any executable that conforms to:
INPUT
stdin the RDF document bytes (concatenated dataset, format declared via --in-format)
argv --key=value pairs
OUTPUT
stdout the generated output (query results, validation report, converted graph, inferred triples)
stderr diagnostics
EXIT
0 success
non-zero failure
Standard argv flags every plugin receives: --rule-name=NAME and
--in-format=FORMAT. Per-toolchain flags (--query=PATH,
--shapes=PATH, --out-format=FORMAT, --profile=NAME) are passed
through by the calling rule. See
rdf/plugin_contract.md for the
authoritative spec (currently v0.1 draft).
Concrete implementations
- fastverk/rules_jena —
Apache Jena backend. Ships plugins for all four toolchain types
(
jena_sparql,jena_shacl,jena_riot,jena_reasoner) and a Maven-pinnedJENA_DEPSset so consumers don’t re-declare it.
Others (RDF4J, Oxigraph) are not blocked by anything in this repo — the contract is the integration point. PRs to list third-party implementations here are welcome.
Install
.bazelrc:
common --registry=https://registry.fastverk.com/
common --registry=https://bcr.bazel.build/
MODULE.bazel:
bazel_dep(name = "rules_rdf", version = "0.2.0")
No toolchains are registered by default — pull in a concrete
implementation (e.g. rules_jena) and register its toolchains in
your MODULE.bazel.
Compatibility
- Bazel: 7.4+, bzlmod required (tested on 9.1).
License
MIT.
Usage#
Real usage, taken from the module’s examples/.
examples/smoke/BUILD.bazel
load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
load("@rules_rdf//rdf:contract_test.bzl", "rdf_plugin_contract_test")
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load(
"@rules_rdf//rdf:toolchains.bzl",
"rdf_reasoner_toolchain",
"rdf_serializer_toolchain",
"rdf_validator_toolchain",
"sparql_engine_toolchain",
)
load("@rules_rdf//rdf:namespace.bzl", "rdf_namespace_manifest")
load("@rules_rdf//reason:defs.bzl", "rdf_reason")
load("@rules_rdf//sparql:defs.bzl", "sparql_query", "sparql_query_test")
load("@rules_rdf//transform:defs.bzl", "rdf_transform")
load("@rules_rdf//validate:defs.bzl", "rdf_validate_test")
package(default_visibility = ["//visibility:public"])
# No-op plugins for every rules_rdf toolchain type. Bash scripts —
# not py_binary — so they have no stage2 bootstrap to stage in
# action runfiles trees. Real implementations (rules_jena's jena_*)
# replace these for production.
sh_binary(name = "no_op_sparql", srcs = ["no_op_sparql.sh"])
sh_binary(name = "no_op_validator", srcs = ["no_op_validator.sh"])
sh_binary(name = "no_op_serializer", srcs = ["no_op_serializer.sh"])
sh_binary(name = "no_op_reasoner", srcs = ["no_op_reasoner.sh"])
sparql_engine_toolchain(name = "no_op_sparql_toolchain", binary = ":no_op_sparql")
rdf_validator_toolchain(name = "no_op_validator_toolchain", binary = ":no_op_validator")
rdf_serializer_toolchain(name = "no_op_serializer_toolchain", binary = ":no_op_serializer")
rdf_reasoner_toolchain(name = "no_op_reasoner_toolchain", binary = ":no_op_reasoner")
toolchain(
name = "no_op_sparql_toolchain_def",
toolchain = ":no_op_sparql_toolchain",
toolchain_type = "@rules_rdf//rdf:sparql_engine_toolchain_type",
)
toolchain(
name = "no_op_validator_toolchain_def",
toolchain = ":no_op_validator_toolchain",
toolchain_type = "@rules_rdf//rdf:rdf_validator_toolchain_type",
)
toolchain(
name = "no_op_serializer_toolchain_def",
toolchain = ":no_op_serializer_toolchain",
toolchain_type = "@rules_rdf//rdf:rdf_serializer_toolchain_type",
)
toolchain(
name = "no_op_reasoner_toolchain_def",
toolchain = ":no_op_reasoner_toolchain",
toolchain_type = "@rules_rdf//rdf:rdf_reasoner_toolchain_type",
)
# Source data — a 1-triple Turtle file every smoke target chains off.
rdf_dataset(
name = "sample",
srcs = ["sample.ttl"],
in_format = "turtle",
)
# A linked vocabulary + a dataset that deps on it. `composed`'s
# transitive_files closure = sample.ttl + linked.ttl, so every consuming
# rule (query/reason/validate/transform) sees both graphs — the
# import-closure model used to ground schema.org + SKOS + DC.
rdf_dataset(
name = "linked",
srcs = ["linked.ttl"],
in_format = "turtle",
)
rdf_dataset(
name = "composed",
srcs = ["sample.ttl"],
in_format = "turtle",
deps = [":linked"],
)
# -- End-to-end smokes ---------------------------------------------------------
sparql_query_test(
name = "zero_row_gate_smoke",
dataset = ":sample",
query = "query.rq",
)
# Exercises the transitive closure through a consumer: the no-op engine
# receives both sample.ttl and linked.ttl.
sparql_query_test(
name = "closure_smoke",
dataset = ":composed",
query = "query.rq",
)
# Import-closure aspect: parent owl:imports child; with child in deps the
# closure is complete, so the strict manifest builds. Drop the dep and
# `strict = True` would fail the build (the completeness gate).
rdf_dataset(
name = "ont_child",
srcs = ["ont_child.ttl"],
in_format = "turtle",
)
rdf_dataset(
name = "ont_parent",
srcs = ["ont_parent.ttl"],
in_format = "turtle",
deps = [":ont_child"],
)
rdf_namespace_manifest(
name = "closure_manifest",
dataset = ":ont_parent",
strict = True,
)
rdf_validate_test(
name = "validate_smoke",
dataset = ":sample",
shapes = "shapes.ttl",
)
rdf_transform(
name = "transform_smoke",
dataset = ":sample",
out_format = "ntriples",
)
# Producer: emit SELECT results as a build artifact (vs the zero-row
# gate). Turns a reasoned graph into downstream-consumable data.
sparql_query(
name = "select_smoke",
dataset = ":sample",
out_format = "tsv",
query = "query.rq",
)
rdf_reason(
name = "reason_smoke",
base = ":sample",
profile = "rdfs",
)
# -- Conformance gates ---------------------------------------------------------
rdf_plugin_contract_test(
name = "no_op_sparql_conforms",
plugin = ":no_op_sparql",
toolchain_type = "sparql_engine",
)
rdf_plugin_contract_test(
name = "no_op_validator_conforms",
plugin = ":no_op_validator",
toolchain_type = "rdf_validator",
)
# … truncated — see the repo for the full exampleRules & providers#
Generated with Stardoc from the module's .bzl sources.
from docs/ROADMAP.md
rules_rdf roadmap
Two waypoints between today’s scaffold and a usable abstract RDF toolchain layer. Each waypoint is one published bazel-registry release.
v0.1 — toolchain types + plugin contract + placeholder rules
The goal is for a consumer to be able to declare every planned target
type (rdf_dataset, sparql_query_test, rdf_validate_test,
rdf_transform, rdf_reason) today, against a no-op default
toolchain, then swap in a real implementation (e.g.
rules_jena) without
touching their BUILD files. This makes rules_rdf adoptable
incrementally — consumers can wire their build graph before any
engine is integrated.
Deliverables:
- Plugin contract document at
rdf/plugin_contract.md(draft already in tree). Same shape as rules_jsonschema’splugin_contract.md, adjusted for RDF semantics:- stdin = the RDF document bytes (the dataset; format declared
via
--in-format), not a JSON schema. - argv =
--key=valuepairs (same as jsonschema). Standard flags:--rule-name,--in-format. Per-toolchain flags:--query,--shapes,--out-format,--profile. - stdout = generated output (query results / validation report / converted graph / inferred triples). Same single-file-per- invocation discipline.
- stderr = diagnostics.
- exit = 0 / non-zero.
- stdin = the RDF document bytes (the dataset; format declared
via
- All four toolchain types defined in
//rdf:BUILD.bazel:sparql_engine_toolchain_type,rdf_validator_toolchain_type,rdf_serializer_toolchain_type,rdf_reasoner_toolchain_type. - Providers:
RdfDatasetInfo,RdfEngineToolchainInfo,RdfValidatorToolchainInfo,RdfSerializerToolchainInfo,RdfReasonerToolchainInfo. Each toolchain info wraps a singlebinaryFile, matching the jsonschema pattern. - Default user-facing rules implemented as
_no_opplaceholders:rdf_dataset— real (returnsRdfDatasetInfo; no toolchain needed).sparql_query_test,sparql_query_run,rdf_validate_test,rdf_transform,rdf_reason— declare their toolchain dependency and accept all their final attrs, but the in-repo default toolchain points at a_no_opbinary that writes an empty stdout and exits 0. Consumers can declare targets and they build; swapping inrules_jenamakes them actually run.
- Conformance test driver
rdf_plugin_contract_testcovering the same scenarios as the jsonschema driver —valid_minimal(small dataset round-trips),malformed_input(garbage on stdin → exit non-zero, empty stdout),unknown_flag(rejects unknown argv),determinism(byte-identical stdout on identical invocations). One driver, parameterised by toolchain type. - stardoc for the public surface, with
diff_testfreshness.
Out of scope for v0.1: chained pipelines, real-engine examples, result-set diff helpers.
v0.2 — cross-toolchain wiring + real-engine examples
Once rules_jena is published and registered, rules_rdf grows the
glue that ties multiple toolchains together in one pipeline.
Deliverables:
- Chained pipelines —
rdf_validate_testandsparql_query_testaccept the output ofrdf_reasonas their dataset, so a consumer can express “materialise inferences, then run shape validation on the closure” as a typed build graph. The intermediate inferred graph is a realRdfDatasetInfo-bearing target, not a hidden side effect. - Result-set helpers — a small Starlark helper for the common
zero-row-CSV gate pattern, plus an
rdf_results_diff_testfor golden SPARQL result sets (SRX/JSON normalisation). - Examples directory using a real RDF corpus:
- W3C example datasets
fetched via
http_filewith a pinned sha256 (the same fetch-and-pin discipline rules_docker_compose uses for the compose-spec schema). - One end-to-end smoke target per toolchain type, registered
against
rules_jena.
- W3C example datasets
fetched via
- CI matrix running the conformance test driver against every registered concrete implementation we know about, gating rules_rdf releases on at least one concrete backend passing.
After v0.2 the abstract layer is feature-complete; further work moves into the concrete-implementation repos.
from docs/contract_test.md
rdf_plugin_contract_test(name, plugin, toolchain_type) runs
the rules_rdf conformance test driver against any executable
claiming to implement the plugin contract for the named toolchain
type. See plugin_contract.md for what the
driver asserts.
Plugin authors gate toolchain registration on it:
load("@rules_rdf//rdf:contract_test.bzl", "rdf_plugin_contract_test")
rdf_plugin_contract_test(
name = "jena_sparql_conforms",
plugin = "//jena:jena_sparql",
toolchain_type = "sparql_engine",
)
The four toolchain types each have their own minimum-valid input
inside the driver; pass the bare name (without the
_toolchain_type suffix or @rules_rdf//rdf: prefix).
rdf_plugin_contract_test
load("@rules_rdf//rdf:contract_test.bzl", "rdf_plugin_contract_test")
rdf_plugin_contract_test(name, plugin, toolchain_type)
Run the rules_rdf conformance test driver against a plugin binary. See plugin_contract.md.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| plugin | The plugin binary to test. Any executable that claims to implement the rules_rdf plugin contract. | Label | required | |
| toolchain_type | Which toolchain type’s scenarios to run: one of sparql_engine, rdf_validator, rdf_serializer, rdf_reasoner. | String | required |
from docs/dataset.md
rdf_dataset(name, srcs, in_format) — declare a labeled
collection of RDF files.
This is the single source of “what triples are in this graph?” that every other rule consumes. Carrying both the file depset and the format string up-front lets sparql_query_test / rdf_validate_test / … avoid sniffing extensions at action time and lets consumers mix datasets with declared formats in one BUILD target without ambiguity.
Multi-file datasets are concatenated by the consuming rule in
lexicographic order before being piped to the plugin’s stdin
(see rdf/plugin_contract.md). Consumers that care about ordering
should name files to sort accordingly.
rdf_dataset
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
rdf_dataset(name, deps, srcs, in_format)
A labeled collection of RDF source files + linked-graph deps.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| deps | Other rdf_datasets this graph links to (imported ontologies, vocabulary modules). Their files are folded into this dataset’s transitive_files closure, so reasoning/query over the linked vocabularies resolves. Deps should share in_format (normalize otherwise). | List of labels | optional | [] |
| srcs | RDF source files. Concatenated in lexicographic order by consuming rules before being piped to the plugin’s stdin. | List of labels | required | |
| in_format | Serialization of every file in srcs. Mixed-format datasets aren’t supported in v0.1 — use rdf_transform first. | String | optional | "turtle" |
from docs/providers.md
Providers for the four rules_rdf toolchain types.
Each provider wraps both the executable and the runfiles needed
to invoke it. Carrying runfiles in the provider matters for
plugin implementations that aren’t a single self-contained binary
— py_binary, java_binary, sh_binary all stage helper files via
runfiles. Consuming rules merge the provider’s runfiles into
their own to make the plugin actually executable inside a Bazel
sandbox.
RdfDatasetInfo
load("@rules_rdf//rdf:providers.bzl", "RdfDatasetInfo")
RdfDatasetInfo(files, transitive_files, in_format)
A declared RDF dataset.
FIELDS
RdfReasonerToolchainInfo
load("@rules_rdf//rdf:providers.bzl", "RdfReasonerToolchainInfo")
RdfReasonerToolchainInfo(binary, runfiles, files_to_run)
An RDF inference engine. Resolved by rdf_reason.
FIELDS
RdfSerializerToolchainInfo
load("@rules_rdf//rdf:providers.bzl", "RdfSerializerToolchainInfo")
RdfSerializerToolchainInfo(binary, runfiles, files_to_run)
An RDF format converter. Resolved by rdf_transform.
FIELDS
RdfValidatorToolchainInfo
load("@rules_rdf//rdf:providers.bzl", "RdfValidatorToolchainInfo")
RdfValidatorToolchainInfo(binary, runfiles, files_to_run)
An RDF validator (SHACL today; ShEx in scope for v0.2). Resolved by rdf_validate_test.
FIELDS
SparqlEngineToolchainInfo
load("@rules_rdf//rdf:providers.bzl", "SparqlEngineToolchainInfo")
SparqlEngineToolchainInfo(binary, runfiles, files_to_run)
A SPARQL query engine. Resolved by sparql_query_test and sparql_query_run.
FIELDS
from docs/reason.md
User-facing inference rules.
rdf_reason runs the registered rdf_reasoner toolchain over an
RDF dataset and emits the derived-triples graph (Turtle) as a
build artifact. Unlike sparql_query_test / rdf_validate_test,
this is a regular rule — its output is a file that downstream
rules can declare as a src or data dependency.
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load("@rules_rdf//reason:defs.bzl", "rdf_reason")
rdf_dataset(name = "ontology", srcs = glob(["*.ttl"]))
rdf_reason(
name = "inferred",
base = ":ontology",
profile = "rdfs",
)
For custom rule sets (Jena RETE rules):
rdf_reason(
name = "inferred",
base = ":ontology",
profile = "custom",
rules = "rules/transitive.rule",
)
The reasoner toolchain implementation decides which profiles are
supported; the abstract layer only validates that profile = "custom" is paired with rules and vice versa.
rdf_reason
load("@rules_rdf//reason:defs.bzl", "rdf_reason")
rdf_reason(name, base, include_base, profile, rules)
Run inference over an RDF dataset; emit the derived-triples graph (Turtle).
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| base | RDF dataset to run inference over. | Label | required | |
| include_base | If True, emit base + derived triples; otherwise only the derived (default). | Boolean | optional | False |
| profile | Reasoning profile. custom requires rules. | String | optional | "rdfs" |
| rules | Custom rule file (Jena RETE syntax). Required iff profile = ‘custom’. | Label | optional | None |
from docs/sparql.md
User-facing SPARQL rules.
sparql_query_test is the zero-row gate idiom: declare an
invariant as a SPARQL query whose result set is empty when the
graph satisfies the invariant. CI runs it as a Bazel test; any
non-empty row triggers a failure.
It’s the rules_rdf analog of the production GateZeroRows.java
pattern in the Aion RFC repo’s kg/java/. v0.1 wires the rule
through sparql_engine_toolchain_type; the actual SPARQL
execution comes from whichever concrete toolchain the consumer
registered (rules_jena, a future rules_rdflib, etc.).
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load("@rules_rdf//sparql:defs.bzl", "sparql_query_test")
rdf_dataset(name = "corpus", srcs = glob(["*.ttl"]))
sparql_query_test(
name = "no_dangling_refs",
dataset = ":corpus",
query = "queries/dangling.rq",
)
sparql_query
load("@rules_rdf//sparql:defs.bzl", "sparql_query")
sparql_query(name, dataset, out_format, query)
Run a SPARQL query and emit the results as a build artifact (the producer counterpart to sparql_query_test’s gate). Turns a reasoned graph into queryable, downstream-consumable data — e.g. grounding tuples for training-data generation.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| dataset | The rdf_dataset (closure) to query. | Label | required | |
| out_format | Result serialization. Tabular (tsv/csv/json/xml) for SELECT/ASK; RDF (turtle/ntriples/…) for CONSTRUCT/DESCRIBE (also yields an rdf_dataset). | String | required | |
| query | The SPARQL query file (SELECT/ASK → tabular; CONSTRUCT/DESCRIBE → graph). | Label | required |
sparql_query_smoke_test
load("@rules_rdf//sparql:defs.bzl", "sparql_query_smoke_test")
sparql_query_smoke_test(name, dataset, queries)
Assert that a set of SPARQL queries all parse + execute against a dataset. The query-smoke gate idiom — catches syntax errors and reference rot after schema changes.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| dataset | An rdf_dataset the queries run against. | Label | required | |
| queries | SPARQL query files. The test passes iff every one parses and executes without error (no row-count assertion — that’s sparql_query_test). | List of labels | required |
sparql_query_test
load("@rules_rdf//sparql:defs.bzl", "sparql_query_test")
sparql_query_test(name, dataset, query)
Run a SPARQL query against an RDF dataset; fail if the result set is non-empty. The zero-row gate idiom.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| dataset | An rdf_dataset whose triples the query runs against. | Label | required | |
| query | The SPARQL query file. Result set must be empty for the test to pass (per --fail-on-nonempty). | Label | required |
from docs/toolchains.md
Toolchain registration rules for rules_rdf.
One rule per toolchain type. Each takes the plugin binary as a
mandatory exec-config label and exposes the matching *ToolchainInfo
provider with both the binary File and its runfiles bundle.
Concrete plugins (rules_jena, rules_rdflib, …) register via:
sparql_engine_toolchain(
name = "jena_arq_sparql_toolchain",
binary = ":jena_sparql",
)
toolchain(
name = "jena_arq_sparql",
toolchain = ":jena_arq_sparql_toolchain",
toolchain_type = "@rules_rdf//rdf:sparql_engine_toolchain_type",
)
rdf_reasoner_toolchain
load("@rules_rdf//rdf:toolchains.bzl", "rdf_reasoner_toolchain")
rdf_reasoner_toolchain(name, binary)
Declare an RDF reasoner (inference) toolchain.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| binary | The plugin executable. Must conform to the contract in rdf/plugin_contract.md. | Label | required |
rdf_serializer_toolchain
load("@rules_rdf//rdf:toolchains.bzl", "rdf_serializer_toolchain")
rdf_serializer_toolchain(name, binary)
Declare an RDF serializer (format-converter) toolchain.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| binary | The plugin executable. Must conform to the contract in rdf/plugin_contract.md. | Label | required |
rdf_validator_toolchain
load("@rules_rdf//rdf:toolchains.bzl", "rdf_validator_toolchain")
rdf_validator_toolchain(name, binary)
Declare an RDF validator toolchain.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| binary | The plugin executable. Must conform to the contract in rdf/plugin_contract.md. | Label | required |
sparql_engine_toolchain
load("@rules_rdf//rdf:toolchains.bzl", "sparql_engine_toolchain")
sparql_engine_toolchain(name, binary)
Declare a SPARQL engine toolchain.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| binary | The plugin executable. Must conform to the contract in rdf/plugin_contract.md. | Label | required |
from docs/transform.md
User-facing format-conversion rule.
rdf_transform re-serializes an RDF dataset into a different
format via the registered rdf_serializer toolchain. The output
is a regular build artifact.
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load("@rules_rdf//transform:defs.bzl", "rdf_transform")
rdf_dataset(name = "src_turtle", srcs = ["data.ttl"], in_format = "turtle")
rdf_transform(
name = "data_ntriples",
dataset = ":src_turtle",
out_format = "ntriples",
)
Output filename = <name>.<ext> where <ext> is the canonical
extension for out_format (.ttl, .nt, .nq, .trig,
.jsonld, .rdf).
rdf_transform
load("@rules_rdf//transform:defs.bzl", "rdf_transform")
rdf_transform(name, dataset, out_format)
Convert an RDF dataset between serializations.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| dataset | RDF dataset to convert. | Label | required | |
| out_format | Target serialization. | String | required |
from docs/validate.md
User-facing RDF validation rules.
rdf_validate_test runs a SHACL shapes graph against an RDF
dataset and fails the build if any violations are reported.
Resolves through rdf_validator_toolchain_type so the actual
SHACL engine is pluggable (rules_jena’s
org.apache.jena.shacl.ShaclValidator, a future
rules_pyshacl, …).
load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load("@rules_rdf//validate:defs.bzl", "rdf_validate_test")
rdf_dataset(name = "ontology", srcs = glob(["ontology/*.ttl"]))
rdf_validate_test(
name = "ontology_conforms",
dataset = ":ontology",
shapes = "shapes.ttl",
)
ShEx support is in scope for v0.2 (the toolchain contract leaves
room for it via the --shapes-language arg, but for v0.1 the
shapes file is assumed Turtle-encoded SHACL).
rdf_validate_test
load("@rules_rdf//validate:defs.bzl", "rdf_validate_test")
rdf_validate_test(name, dataset, severity, shapes)
Validate an RDF dataset against a SHACL shapes graph.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| dataset | An rdf_dataset to validate. | Label | required | |
| severity | Minimum severity that fails the build. | String | optional | "violation" |
| shapes | SHACL shapes graph (Turtle). | Label | required |
Conformance#
No gate findings. 10 contested atoms. See how gating works or the full report.
Contested atoms
Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.
| Atom | Resolved here | Elsewhere |
|---|---|---|
apple_support | 1.24.2 | 2.2.0 ×1 |
bazel_skylib | 1.8.2 | 1.9.0 ×2 |
gazelle | 0.36.0 | 0.30.0 ×50.44.0 ×10.51.0 ×3 |
nlohmann_json | 3.6.1 | 3.12.0.bcr.1 ×1 |
protobuf | 33.4 | 34.0.bcr.1 ×2 |
rules_go | 0.60.0 | 0.39.1 ×5 |
rules_jvm_external | 6.7 | 6.8 ×4 |
rules_python | 1.7.0 | 2.0.1 ×1 |
rules_swift | 3.1.2 | 3.6.1 ×1 |
upb | 0.0.0-20220923-a547704 | 0.0.0-20230516-61a97ef ×1 |
Dependencies#
Depends on
Used by (6 in the registry)
Versions#
5 published versions, newest first. Each resolves to an immutable, integrity-checked archive.
| Version | Integrity (sha256) | Source archive |
|---|---|---|
0.4.0 latest | w3Rmkz8M2kjVm0tl… | tag archive ↗ |
0.3.0 | 5Fgb2PtEFsWkm8y3… | tag archive ↗ |
0.2.0 | NECrbS8zRPEUjADr… | tag archive ↗ |
0.1.0 | NzaQNK5SZ9AZXTbo… | tag archive ↗ |
0.0.1 | PWU1ZHKEXMrLgABL… | tag archive ↗ |
Changelog#
All notable changes to rules_rdf. The format is loosely Keep a Changelog — version headers mirror the published bazel-registry entries.
0.4.0 — canonical RDF statement substrate proto
//rdf:statement_proto(fastverk.rdf.v1,dev.fastverk.rdf.v1): the canonical RDF statement substrate —Term(IRI / literal / bnode),Triple/Quad,Literal(lexical + language/datatype),PrefixDecl, andRdfStatement(the stream unit). The message shapes mirror Apache Jena’s RDF Protobuf wire format, so a stream converts mechanically into a JenaModel/Datasetand round-trips through therdfprotobufserialization rules_rdf already speaks. This is the L1 wire format every graph reduces to, keyed on stable IRIs; domain vocabularies + SHACL shapes layer on top. Schema-only — consumers generate their own bindings (java_proto_library, …), so the only new dependency isprotobuf(forproto_library). Provenance is carried out of band by the domain (e.g. as the key inKV<Context, RdfStatement>), keeping the substrate neutral.
0.3.0 — hermetic RDF-resource fetch + linked-graph closure
rdf_resource_repositoryrepository rule +rdfbzlmod module extension (rdf.resourcetag class). Sha-pinned fetch of a single RDF document (TTL / JSON-LD / N-Triples / …) from a URL (with mirror fallback) into a repo whose default BUILD overlay exports the raw file and declares a readyrdf_dataset(:dataset). The pin-an-ontology primitive for grounding vendored vocabularies (schema.org, SKOS, DC) into the build graph forrdf_transform/sparql_query/rdf_reason.rdf_datasetgainsdeps(otherrdf_datasets it links to) andRdfDatasetInfogainstransitive_files— the linked-graph closure (own files + the transitive closure of every dep).sparql_query/rdf_reason/rdf_validate/rdf_transformnow operate over the closure, so cross-vocabulary subclass/subproperty chains resolve (a schema.org type whose superclass lives in an imported module). Fully backward compatible: with nodeps,transitive_files == files.rdf_namespace_aspect(+rdf_namespace_manifest): traverses a dataset’sdepsgraph, extracting per-node namespaces +owl:imports(via the stdlibns_tool), and folds them into a manifest with the harvested namespace set (the grounding vocabulary) + an import-completeness check.strict = Truefails the build if anyowl:importsis unprovided in the closure.sparql_queryproducer rule: runs a SELECT/ASK (→ tsv/csv/json/xml) or CONSTRUCT/DESCRIBE (→ turtle/… , and yields anrdf_dataset) over a dataset’s closure, emitting results as a build artifact — the producer counterpart tosparql_query_test’s gate. Turns a reasoned graph into downstream-consumable data (e.g. grounding tuples for training-data generation).
0.2.0 — build-action rules + binary RDF formats
rdf_reason(//reason:defs.bzl) — build-action rule that runs the registeredrdf_reasonertoolchain over a base dataset; emits the derived-triples Turtle file. Provides a freshRdfDatasetInfoso consumers can chain reason → validate → query.rdf_transform(//transform:defs.bzl) — convert between serializations via the registeredrdf_serializertoolchain. Output extension auto-selected fromout_format.- Binary RDF formats added to
RDF_FORMATS:rdfthrift(.rt) andrdfprotobuf(.rpb/.bin). Apache Jena’s binary serializations — useful as cached intermediate forms. - Smoke fixtures rewritten as bash plugins (no py_binary
bootstrap to stage in action runfiles trees). Four no-op
plugins cover every toolchain type;
bazel test //...runs 14/14 (8 stardoc diff_tests + 4 conformance + 4 rule smokes). - Stardoc for
reason/defs.bzl+transform/defs.bzl.
0.1.0 — first usable surface
- Four
toolchain_types under//rdf::sparql_engine,rdf_validator,rdf_serializer,rdf_reasoner. - Toolchain registration rules + providers carrying both the plugin binary and its runfiles (so py_binary / java_binary plugins resolve in the sandbox).
rdf_dataset+RdfDatasetInfoprovider.sparql_query_test— zero-row SPARQL gate, the workhorse rule.rdf_validate_test— SHACL gate.rdf_plugin_contract_testrule + Python driver. Four scenarios:valid_minimal,malformed_input,unknown_flag,determinism.- Plugin contract finalized at
rdf/plugin_contract.md(v1). - Stardoc reference for all six public-API .bzl files.
- End-to-end smoke (
examples/smoke/) using a no-op Python SPARQL engine. Validates the contract pipeline without depending on a concrete RDF backend.
0.0.1 — scaffold
- Initial scaffold via
rels scaffold. No public API yet.