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, RDF/XML and JSON-LD.
It is distributed using an NPM package that is compatible with Node.JS 18+ and modern web browsers compatible with WebAssembly reference types and JavaScript WeakRef.
To install:
npm install oxigraphAnd then import:
import { Store } from "oxigraph";Note that a bundler compatible with WebAssembly like Vite or WebPack is likely required to make the package work.
Insert the triple <http://example/> <http://schema.org/name> "example" and log the name of <http://example/> in SPARQL:
import { Store } from "oxigraph";
import dataModel from "@rdfjs/data-model";
const store = new Store();
const ex = dataModel.namedNode("http://example/");
const schemaName = dataModel.namedNode("http://schema.org/name");
store.add(dataModel.triple(ex, schemaName, dataModel.literal("example")));
for (const binding of store.query("SELECT ?name WHERE { <http://example/> <http://schema.org/name> ?name }")) {
console.log(binding.get("name").value);
}Oxigraph currently provides a simple JS API. It relies on the RDF/JS DataModel API to represent RDF terms and its '@rdfjs/data-model` implementation.
Parse some content and return Quads.
The method arguments are:
input: the serialized RDF triples or quads. It allows different types:string | UInt8Array. In this case the output is returned as a plainQuad[].Iterable<string | UInt8Array>. In this case the output is returned as anIterable<Quad>that consumes the input iterator lazily.AsyncIterable<string | UInt8Array>. In this case the output is returned as anAsyncIterable<Quad>that consumes the input iterator lazily.
options: an object containing various options (all optional exceptformat):format: the format of the serialization as astring. See below for the supported formats.base_iri: the base IRI to use to resolve the relative IRIs in the serialization as astringor aNamedNode.to_named_graph: for triple serialization formats, the name of the named graph the output quad should be in. If set, must beNamedNode,BlankNodeorDefaultGraph.unchecked: disables careful data validation like checking if the IRIs or language tags are valid. Also automatically recovers from some small syntax errors.
The available formats are:
- JSON-LD:
application/ld+jsonorjsonld - Turtle:
text/turtleorttl - TriG:
application/trigortrig - N-Triples:
application/n-triplesornt - N-Quads:
application/n-quadsornq - N3:
text/n3orn3 - RDF/XML:
application/rdf+xmlorrdf
Example of parsing a Turtle file with the base IRI http://example.com:
parse(
"<http://example.com> <http://example.com> <> .",
{
format: "text/turtle",
base_iri: "http://example.com",
}
)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.
import { Store } from "oxigraph";
const store = new Store();If provided, the Store will be initialized with a sequence of quads.
import {Store} from "oxigraph";
import dataModel from "@rdfjs/data-model";
const store = new Store([dataModel.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, dataModel.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 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:
console.log(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
default_graph: [dataModel.defaultGraph(), dataModel.namedNode("http://example.com")], // the default graph of the query is the union of the store default graph and the http://example.com graph
named_graphs: [dataModel.namedNode("http://example.com"), dataModel.blankNode("b")], // we restrict the available named graphs to the two listed
results_format: "json", // the response will be serialized a string in the JSON format (media types like application/sparql-results+json also work)
}));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
})Loads serialized RDF triples or quad into the store. The method arguments are:
data: the serialized RDF triples or quads as a single buffer or an iterable of buffers.options: an object containing various options (all optional exceptformat):format: the format of the serialization as astring. See below for the supported formats.base_iri: the base IRI to use to resolve the relative IRIs in the serialization as astringor aNamedNode.to_named_graph: for triple serialization formats, the name of the named graph the triple should be loaded to as aNamedNode,BlankNodeorDefaultGraph.unchecked: disables careful data validation like checking if the IRIs or language tags are valid. Also automatically recovers from some small syntax errors.no_transaction: disables transactional guarantees: if the file has a syntax error, the start of it might be loaded into the store even if parsing fails.
The available formats are:
- JSON-LD:
application/ld+jsonorjsonld - Turtle:
text/turtleorttl - TriG:
application/trigortrig - N-Triples:
application/n-triplesornt - N-Quads:
application/n-quadsornq - N3:
text/n3orn3 - RDF/XML:
application/rdf+xmlorrdf
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> <> .",
{
format: "text/turtle",
base_iri: "http://example.com",
to_graph_name: dataModel.namedNode("http://example.com/graph")
}
);Returns serialized RDF triples or quad from the store.
The method argument is a single object, options, with the following options (all optional except format):
format: the format type of the serialization as astring. See below for the supported types.from_named_graph: for triple serialization formats, the name of the named graph the triple should be loaded from as aNamedNode,BlankNodeorDefaultGraph..
The available formats are:
- JSON-LD:
application/ld+jsonorjsonld - Turtle:
text/turtleorttl - TriG:
application/trigortrig - N-Triples:
application/n-triplesornt - N-Quads:
application/n-quadsornq - N3:
text/n3orn3 - RDF/XML:
application/rdf+xmlorrdf
Example of building a Turtle file from the named graph <http://example.com/graph>:
store.dump({
format: "text/turtle",
from_graph_name: dataModel.namedNode("http://example.com/graph")
});- The package is now build from bundlers and not for plain Node.JS or web browsers.
If you don't use a bundler you can still avoid using one by directly importing the
oxigraph_bg.wasmandoxigraph_bg.jsfiles. To import Oxigraph useimport { Store } from "oxigraph" - Oxigraph does not implement RDF/JS DataModel anymore. Use another library like '@rdfjs/data-model`.
- The
MemoryStoreclass is now calledStore(there is no other kind of stores...). - RDF/JS datamodel functions (
namedNode...) are now available at the root of theoxigraphpackage. You now need to calloxigraph.namedNodeinstead ofstore.dataFactory.namedNode. - RDF-star is now implemented.
Quadis now a valid value for theΩuadsubjectandobjectproperties.
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
rustupandcargoinstalled (possible instructions). npm installto install 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 fmtandcargo clippy. - JS code is formatted and linted with Biome.
npm run fmtto auto-format andnpm testto lint and test. - Tests are written in JavaScript using Mocha in the
testdirectory.npm testto 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.