@_linked/rdf-mem-store
v1.0.1
Published
In-memory RDF store and query resolver for @_linked/core
Readme
@_linked/rdf-mem-store
In-memory RDF store for @_linked/core. Provides RDF model classes, an in-memory quad graph, and a query resolver that executes query objects generated by core's Shape-based query DSL.
Installation
npm install @_linked/rdf-mem-store @_linked/coreQuick start
import {LinkedStorage} from '@_linked/core';
import {InMemoryStore, NamedNode, Literal} from '@_linked/rdf-mem-store';
// 1. Create and wire the store
const store = new InMemoryStore();
LinkedStorage.setDefaultStore(store);
// 2. Create nodes and data — all nodes and quads are global singletons,
// automatically available to every InMemoryStore
const alice = NamedNode.getOrCreate('https://example.org/alice');
const name = NamedNode.getOrCreate('https://schema.org/name');
alice.setValue(name, 'Alice');
// 3. Query using core's Shape DSL (see @_linked/core for Shape setup)
const results = await Person.select((p) => p.name);Wiring the store into core
InMemoryStore implements IQuadStore from @_linked/core. Register it as the default store so core's query DSL can resolve queries:
import {LinkedStorage} from '@_linked/core';
import {InMemoryStore} from '@_linked/rdf-mem-store';
const store = new InMemoryStore();
LinkedStorage.setDefaultStore(store);You can also route specific shapes to specific stores:
import {LinkedStorage} from '@_linked/core';
import {InMemoryStore} from '@_linked/rdf-mem-store';
const mainStore = new InMemoryStore();
const personStore = new InMemoryStore();
LinkedStorage.setDefaultStore(mainStore);
LinkedStorage.setStoreForShapes(personStore, Person);RDF models
This package provides the core RDF model classes. All nodes and quads are global singletons — calling NamedNode.getOrCreate(uri) twice with the same URI returns the same instance.
NamedNode
Represents a URI-identified RDF node. This is the primary building block.
import {NamedNode} from '@_linked/rdf-mem-store';
// Get or create a node (singleton per URI)
const node = NamedNode.getOrCreate('https://example.org/alice');
// Create a temporary node (auto-generated URI)
const temp = NamedNode.create();
// Check if a node exists without creating it
const existing = NamedNode.getNamedNode('https://example.org/alice'); // NamedNode | undefinedNamedNode satisfies NodeReferenceValue ({id: string}) from core, so it can be used anywhere core expects a node reference.
Literal
Represents an RDF literal value (string, number, date, etc.).
import {Literal, NamedNode} from '@_linked/rdf-mem-store';
// Plain string literal
const lit = new Literal('hello');
// Typed literal (with datatype)
import {xsd} from '@_linked/core/ontologies/xsd';
import {toNamedNode} from '@_linked/rdf-mem-store';
const intLit = new Literal('42', toNamedNode(xsd.integer));
const dateLit = new Literal('2024-01-01T00:00:00.000Z', toNamedNode(xsd.dateTime));
const boolLit = new Literal('true', toNamedNode(xsd.boolean));Quad
Represents an RDF triple/quad (subject-predicate-object-graph).
import {Quad, NamedNode, Literal, defaultGraph} from '@_linked/rdf-mem-store';
const subject = NamedNode.getOrCreate('https://example.org/alice');
const predicate = NamedNode.getOrCreate('https://schema.org/name');
const object = new Literal('Alice');
// Quads are also singletons
const quad = Quad.getOrCreate(subject, predicate, object, defaultGraph);Graph
Represents an RDF named graph.
import {Graph, defaultGraph} from '@_linked/rdf-mem-store';
const myGraph = Graph.getOrCreate('https://example.org/my-graph');
// defaultGraph is the default graph singletonWorking with properties
NamedNode provides methods for setting, getting, and removing property values.
Setting properties
const alice = NamedNode.getOrCreate('https://example.org/alice');
const name = NamedNode.getOrCreate('https://schema.org/name');
const knows = NamedNode.getOrCreate('https://schema.org/knows');
const bob = NamedNode.getOrCreate('https://example.org/bob');
// Set a literal value (creates a Literal and a Quad)
alice.setValue(name, 'Alice');
// Set an object property (node-to-node link)
alice.set(knows, bob);
// Set multiple values at once
const carol = NamedNode.getOrCreate('https://example.org/carol');
alice.mset(knows, [bob, carol]);
// Overwrite a property (removes existing values first)
alice.overwrite(name, new Literal('Alicia'));
// Overwrite with multiple values
alice.moverwrite(knows, [bob, carol]);Getting properties
// Get a single value
const oneKnown = alice.getOne(knows); // Node | undefined
// Get all values for a property
const allKnown = alice.getAll(knows); // NodeValuesSet (iterable)
// Get a string value directly
const nameStr = alice.getValue(name); // string
// Get all nodes that point to this node via a property
const whoKnowsAlice = alice.getAllInverse(knows); // NodeSet<NamedNode>
// Check if a property exists
const hasName = alice.hasProperty(name); // boolean
// Get quads for a property
const quads = alice.getQuads(knows); // QuadSetRemoving properties
// Remove a specific value
alice.unset(knows, bob);
// Remove all values for a property
alice.unsetAll(knows);
// Remove the node entirely (removes all quads where it is subject or object)
alice.remove();Setting up typed data (with Shapes)
When using core's Shape DSL, you define shapes and set up data using the RDF model layer. The query resolver traverses the global quad graph to resolve queries.
import {NamedNode, Literal, toNamedNode} from '@_linked/rdf-mem-store';
import {rdf} from '@_linked/core/ontologies/rdf';
import {InMemoryStore} from '@_linked/rdf-mem-store';
import {LinkedStorage} from '@_linked/core';
// Assume you have a Person shape with targetClass and properties defined via core
// (see @_linked/core README for Shape setup)
// Create typed entities
const personType = toNamedNode(Person.targetClass);
const rdfType = toNamedNode(rdf.type);
const nameProp = toNamedNode(name); // name from your shape's property path
const alice = NamedNode.getOrCreate('https://example.org/alice');
alice.set(rdfType, personType); // Set rdf:type so the resolver finds this instance
alice.setValue(nameProp, 'Alice'); // Set the name property
// Wire the store
const store = new InMemoryStore();
LinkedStorage.setDefaultStore(store);
// Now queries work
const results = await Person.select((p) => p.name);
// → [{id: 'https://example.org/alice', name: 'Alice'}]toNamedNode helper
Since core uses NodeReferenceValue ({id: string}) for ontology terms, property paths, and target classes, use toNamedNode to convert them to NamedNode instances when working with the RDF model layer:
import {toNamedNode} from '@_linked/rdf-mem-store';
import {rdf} from '@_linked/core/ontologies/rdf';
// rdf.type is {id: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'}
const rdfTypeNode = toNamedNode(rdf.type); // → NamedNode
// Works with any {id: string} object
const node = toNamedNode({id: 'https://example.org/foo'}); // → NamedNode
// Passes through NamedNode instances unchanged
const nn = NamedNode.getOrCreate('https://example.org/bar');
toNamedNode(nn) === nn; // trueInMemoryStore API
InMemoryStore implements IQuadStore from core (query methods) and provides additional quad-level methods:
const store = new InMemoryStore();
// Query methods (from IQuadStore)
await store.selectQuery(query); // Resolve a select query
await store.updateQuery(query); // Resolve an update query
await store.createQuery(query); // Resolve a create query
await store.deleteQuery(query); // Resolve a delete query
// Quad-level methods
await store.add(quad); // Add a single quad
await store.addMultiple(quadSet); // Add multiple quads
await store.delete(quad); // Remove a single quad
await store.deleteMultiple(quadSet); // Remove multiple quads
// Inspect contents
store.getContents(); // Returns the QuadSet of tracked quadsRDF collections
QuadSet— Set of Quad instancesQuadArray— Array of Quad instancesQuadMap— Map indexed by quadsNodeSet— Set of NamedNode instancesNodeMap— Map keyed by NamedNodeNodeURIMappings— URI-to-node mapping utilitiesSearchMap— Search-optimized map for quad lookupsNodeValuesSet— Set of values for a specific property on a node (returned bynode.getAll())
Related packages
@_linked/core— Query DSL, Shape classes, SHACL decorators, LinkedStorage@_linked/react— React bindings for Linked queries and shapes
Changelog
1.0.0 (from LINCD.js)
Initial extraction from the LINCD monolith. Moves all RDF model classes, the in-memory quad store, and the query resolver into a standalone package.
- RDF models (
NamedNode,Literal,BlankNode,Quad,Graph) and all RDF collections extracted fromlincd. InMemoryStoreimplementsIQuadStorefrom@_linked/core.LocalQueryResolverresolves core's query objects against the in-memory quad graph.toNamedNodehelper bridges core'sNodeReferenceValue({id: string}) toNamedNodeinstances.
