This package provides a JavaScript API on top of Oxigraph, compiled with WebAssembly.
Oxigraph is a graph database written in Rust implementing the SPARQL standard.
Oxigraph for JavaScript is a work in progress and currently offers a simple in-memory store with SPARQL 1.1 Query and SPARQL 1.1 Update capabilities.
The store is also able to load RDF serialized in Turtle, TriG, N-Triples, N-Quads and RDF/XML.
It is distributed using a a NPM package that should work with Node.JS 12+ and modern web browsers compatible with WebAssembly.
To install:
npm install oxigraph
To load with Node.JS:
const oxigraph = require('oxigraph');
or with ES modules:
import oxigraph from './node_modules/oxigraph/node.js';
To load on an HTML web page (for WebPack 5 remove the <script>
tag and put the code in a JS file):
<script type="module">
import init, * as oxigraph from './node_modules/oxigraph/web.js'
(async function () {
await init(); // Required to compile the WebAssembly code.
// We can use here Oxigraph methods
})()
</script>
Insert the triple <http://example/> <http://schema.org/name> "example"
and log the name of <http://example/>
in SPARQL:
const oxigraph = require('oxigraph');
const store = new oxigraph.Store();
const ex = oxigraph.namedNode("http://example/");
const schemaName = oxigraph.namedNode("http://schema.org/name");
store.add(oxigraph.triple(ex, schemaName, oxigraph.literal("example")));
for (const binding of store.query("SELECT ?name WHERE { <http://example/> <http://schema.org/name> ?name }")) {
console.log(binding.get("name").value);
}
Insert the triple <http://example/> <http://schema.org/name> "example"
and log the name of <http://example/>
in
SPARQL:
<script type="module">
import init, * as oxigraph from './node_modules/oxigraph/web.js'
(async function () {
await init(); // Required to compile the WebAssembly.
const store = new oxigraph.Store();
const ex = oxigraph.namedNode("http://example/");
const schemaName = oxigraph.namedNode("http://schema.org/name");
store.add(oxigraph.triple(ex, schemaName, oxigraph.literal("example")));
for (const binding of store.query("SELECT ?name WHERE { <http://example/> <http://schema.org/name> ?name }")) {
console.log(binding.get("name").value);
}
})()
</script>
This example works with WebPack too if you remove the <script>
tag and put the code in a JS file.
Oxigraph currently provides a simple JS API.
Oxigraph implements the RDF/JS datamodel specification.
For that, the oxigraph
module implements the RDF/JS DataFactory
interface.
Example:
const oxigraph = require('oxigraph');
const ex = oxigraph.namedNode("http://example.com");
const blank = oxigraph.blankNode();
const foo = oxigraph.literal("foo");
const quad = oxigraph.quad(blank, ex, foo);
All terms overrides the the toString()
method to return a N-Quads/SPARQL-like representation of the terms.
Oxigraph API is centered around the Store
class.
A store contains an RDF dataset and allows to query and update them using SPARQL.
Creates a new store.
const oxigraph = require('oxigraph');
const store = new oxigraph.Store();
If provided, the Store
will be initialized with a sequence of quads.
const oxigraph = require('oxigraph');
const store = new oxigraph.Store([oxigraph.quad(blank, ex, foo)]);
Inserts a quad in the store.
Example:
store.add(quad);
Removes a quad from the store.
Example:
store.delete(quad);
Returns a boolean stating if the store contains the quad.
Example:
store.has(quad);
Store.prototype.match(optional Term? subject, optional Term? predicate, optional Term? object, optional Term? graph)
Returns an array with all the quads matching a given quad pattern.
Example to get all quads in the default graph with ex
for subject:
store.match(ex, null, null, oxigraph.defaultGraph());
Example to get all quads:
store.match();
Executes a SPARQL 1.1 Query.
For SELECT
queries the return type is an array of Map
which keys are the bound variables and values are the values the result is bound to.
For CONSTRUCT
and ÐESCRIBE
queries the return type is an array of Quad
.
For ASK
queries the return type is a boolean.
Example of SELECT query:
for (binding of store.query("SELECT DISTINCT ?s WHERE { ?s ?p ?o }")) {
console.log(binding.get("s").value);
}
Example of CONSTRUCT query:
const filteredStore = new oxigraph.Store(store.query("CONSTRUCT { <http:/example.com/> ?p ?o } WHERE { <http:/example.com/> ?p ?o }"));
Example of ASK query:
if (store.query("ASK { ?s ?s ?s }")) {
console.log("there is a triple with same subject, predicate and object");
}
It is also possible to provide some options in an object given as second argument:
if (store.query("ASK { <s> ?p ?o }", {
base_iri: "http://example.com/", // base IRI to resolve relative IRIs in the query
use_default_graph_as_union: true, // the default graph in the query is the union of all the dataset graphs
})) {
console.log("there is a triple with same subject, predicate and object");
}
Executes a SPARQL 1.1 Update.
The LOAD
operation is not supported yet.
Example of update:
store.update("DELETE WHERE { <http://example.com/s> ?p ?o }")
It is also possible to provide some options in an object given as second argument:
store.update("DELETE WHERE { <s> ?p ?o }", {
base_iri: "http://example.com/" // base IRI to resolve relative IRIs in the update
})
Store.prototype.load(String data, String format, NamedNode|String? baseIRI, NamedNode|BlankNode|DefaultGraph? toNamedGraph)
Loads serialized RDF triples or quad into the store. The method arguments are:
data
: the serialized RDF triples or quads.format
: the format of the serialization. See below for the supported formats.baseIRI
: the base IRI to use to resolve the relative IRIs in the serialization.toNamedGraph
: for triple serialization formats, the name of the named graph the triple should be loaded to.
The available formats are:
- Turtle:
text/turtle
orttl
- TriG:
application/trig
ortrig
- N-Triples:
application/n-triples
ornt
- N-Quads:
application/n-quads
ornq
- N3:
text/n3
orn3
- RDF/XML:
application/rdf+xml
orrdf
Example of loading a Turtle file into the named graph <http://example.com/graph>
with the base IRI http://example.com
:
store.load("<http://example.com> <http://example.com> <> .", "text/turtle", "http://example.com", oxigraph.namedNode("http://example.com/graph"));
Returns serialized RDF triples or quad from the store. The method arguments are:
format
: the format type of the serialization. See below for the supported types.fromNamedGraph
: for triple serialization formats, the name of the named graph the triple should be loaded from.
The available formats are:
- Turtle:
text/turtle
orttl
- TriG:
application/trig
ortrig
- N-Triples:
application/n-triples
ornt
- N-Quads:
application/n-quads
ornq
- N3:
text/n3
orn3
- RDF/XML:
application/rdf+xml
orrdf
Example of building a Turtle file from the named graph <http://example.com/graph>
:
store.dump("text/turtle", oxigraph.namedNode("http://example.com/graph"));
- The
MemoryStore
class is now calledStore
(there is no other kind of stores...). - RDF/JS datamodel functions (
namedNode
...) are now available at the root of theoxigraph
package. You now need to calloxigraph.namedNode
instead ofstore.dataFactory.namedNode
. - RDF-star is now implemented.
Quad
is now a valid value for theΩuad
subject
andobject
properties.
The Oxigraph bindings are written in Rust using the Rust WASM toolkit.
The The Rust Wasm Book is a great tutorial to get started.
To setup a dev environment:
- ensure to have a Rust toolchain with
rustup
andcargo
installed (possible instructions). - install
wasm-pack
:cargo install wasm-pack
(it is also in some Linux distribution repositories). npm install
to install pure JS dependencies.- you are good to go!
Testing and linting:
- Rust code is formatted with rustfmt and linted with clippy.
You can execute them with
cargo fmt
andcargo clippy
. - JS code is formatted and linted with Biome.
npm run fmt
to auto-format andnpm test
to lint and test. - Tests are written in JavaScript using Mocha in the
test
directory.npm test
to run them.
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Oxigraph by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.