Quadstore
A LevelDB-backed graph database for JS runtimes (Node.js, Deno, browsers, ...) supporting SPARQL queries and the RDF/JS interface.
Install / Use
/learn @quadstorejs/QuadstoreREADME

QUADSTORE
Quadstore is a LevelDB-backed RDF graph database / triplestore for JavaScript runtimes (browsers, Node.js, Deno, Bun, ...) written in TypeScript.
- Implements the
Sink,SourceandStoreRDF/JS interfaces for maximum interoperability with other RDF libraries - Supports SPARQL queries via quadstore-comunica, a tailored configuration and distribution of the Comunica querying framework
- Natively capable of querying across named graphs
Table of contents
- QUADSTORE
- Table of contents
- Example of basic usage
- Status
- Usage
- Parsing and serializing RDF
- Storage backends
- Data model and return values
- Quadstore class
- Access to the backend
- Quadstore.prototype.open()
- Quadstore.prototype.close()
- Quadstore.prototype.get()
- Range matching
- Quadstore.prototype.put()
- Quadstore.prototype.multiPut()
- Quadstore.prototype.del()
- Quadstore.prototype.multiDel()
- Quadstore.prototype.patch()
- Quadstore.prototype.multiPatch()
- Quadstore.prototype.getStream()
- Quadstore.prototype.putStream()
- Quadstore.prototype.delStream()
- Quadstore.prototype.match()
- Quadstore.prototype.import()
- Quadstore.prototype.remove()
- Quadstore.prototype.removeMatches()
- Blank nodes and quad scoping
- SPARQL
- Browser usage
- Deno usage
- Performance
- LICENSE
Example of basic usage
import { MemoryLevel } from 'memory-level';
import { DataFactory } from 'rdf-data-factory';
import { Quadstore } from 'quadstore';
import { Engine } from 'quadstore-comunica';
// Any implementation of AbstractLevel can be used.
const backend = new MemoryLevel();
// Implementation of the RDF/JS DataFactory interface
const df = new DataFactory();
// Store and query engine are separate modules
const store = new Quadstore({backend, dataFactory: df});
const engine = new Engine(store);
// Open the store
await store.open();
// Put a single quad into the store using Quadstore's API
await store.put(df.quad(
df.namedNode('http://example.com/subject'),
df.namedNode('http://example.com/predicate'),
df.namedNode('http://example.com/object'),
df.defaultGraph(),
));
// Retrieves all quads using Quadstore's API
const { items } = await store.get({});
// Retrieves all quads using RDF/JS Stream interfaces
const quadsStream = store.match(undefined, undefined, undefined, undefined);
quadsStream.on('data', quad => console.log(quad));
// Queries the store via RDF/JS Query interfaces
const bindingsStream = await engine.queryBindings('SELECT * {?s ?p ?o}');
bindingsStream.on('data', binding => console.log(binding));
Status
Active, under development.
Changelog
See CHANGELOG.md.
Roadmap
We're currently working on the following features:
- optimizing SPARQL performance by pushing filters down from the engine to the persistence layer
We're also evaluating the following features for future developments:
- RDF* (see also these slides)
Notes
- uses Semantic Versioning, pre-releases are tagged accordingly;
- requires Node.js >= 18.0.0.
Usage
Parsing and serializing RDF
quadstore is compatible with all parsers and serializers implementing the
relevant RDF/JS interfaces, such as n3 and @rdfjs/formats.
See https://rdf.js.org for an open list of such libraries.
For example, here is how to use n3 in order to parse a Turtle file
into an instance of Quadstore in a streaming fashion, with full backpressure
handling, using classic-level as the backend:
import { Quadstore } from 'quadstore';
import { ClassicLevel } from 'classic-level';
import { DataFactory, StreamParser } from 'n3';
const store = new Quadstore({
backend: new ClassicLevel('/path/to/db'),
dataFactory: DataFactory,
});
await store.open();
const reader = fs.createReadStream('/path/to/file.ttl');
const parser = new StreamParser({ format: 'text/turtle' });
await store.putStream(reader.pipe(parser), { batchSize: 100 });
await store.close();
quadstore does not include any RDF parsing and/or serialization capability
by choice as no subset of formats would meet the requirements of every use
case and shipping support for all mainstream RDF formats would result in
exceedingly high bundle sizes.
Storage backends
quadstore can work with any storage backend that implements the
AbstractLevel interface. An incomplete list of available backends
is available at level/awesome#stores.
Our test suite focuses on the following backends:
classic-levelfor persistent, on-disk storage using LevelDBmemory-levelfor volatile in-memory storage using red-black treesbrowser-levelfor browser-side persistent storage using IndexedDB. For more information about browser-side usage, see the Browser usage section
Data model and return values
Except for those related to the RDF/JS stream interfaces, quadstore's
API is promise-based and all methods return objects that include both the actual
query results and the relevant metadata.
Objects returned by quadstore's APIs have the type property set to one of
the following values:
"VOID"- when there's no data returned by the database, such as with theputmethod;"QUADS"- when a query returns a collection of quads;"APPROXIMATE_SIZE"- when a query returns an approximate count of how many matching items are present.
For those methods that return objects with the type property set to
"QUADS", quadstore provides query results either in streaming mode or in
non-streaming mode.
Streaming methods such as getStream return objects with the iterator
property set to an instance of AsyncIterator, an implementation of a
subset of the stream.Readable interface.
Non-streaming methods such as get return objects with the items property
set to an array of quads.
Quads are returned as and expected to be instances of the
RDF/JS Quad interface as produced by the implementation of the
RDF/JS DataFactory interface passed to the Quadstore constructor.
Matching patterns, such as those used in the get and getStream methods,
are expected to be maps of term names to instances of the
RDF/JS Term interface.
Quadstore class
const Quadstore = require('quadstore').Quadstore;
const store = new Quadstore(opts);
Instantiates a new store. Supported properties for the opts argument
are:
opts.backend
The opts.backend option must be an instance of a leveldb backend.
See storage backends.
opts.dataFactory
The dataFactory option must be an implementation of the
RDF/JS DataFactory interface. Some of the available
implementations:
opts.indexes
The opts.indexes option allows users to configure which indexes will be used
by the store. If not set, the store will default to the following indexes:
[
['subject', 'predicate', 'object',
