Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | 1x 1x 91x 91x 91x 91x 100x 25x 707479x 91x 1x 16x 260687x 260687x 4x 4x 4x 4x 4x 4x 4x 4x 258425x 258425x 258425x 1963x 1963x 1963x 4x 214x 230x 525x 1x 524x 1x 1x 87x 1x 1x 1x 8190x 4095x 161x 161x 161x 161x 622467x 622467x 6360x 161x 161x 116x 121x 121x 121x 162x 162x 162x 162x 162x 162x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4095x 1x 1x 4x 4x 4x 4x 4x 4x 4x 13257x 13257x 13257x 13257x 4x 4x 4x 4x 16x 51939x 25207x 5x 169x 126x 169x 295x 295x 17570x 295x 10x 4x 4x 4x 7x 4x 13x 35x 36x 1x 35x 35x 35x 35x 35x 35x 36x 12x 23x 23x 73x 30036x 30052x 1x 1x 57017x 1x 57014x 57014x 57014x 57014x 49554x 49745x 49664x 31246x 30433x 30433x 30433x 7460x 7447x 15187x 13477x 13x 10x 7x 7x 7x 1x 6x | import * as rdfjs from "@rdfjs/types";
import * as src from '../ontologies/src';
import { RdfStore } from "rdf-stores";
import { rdf, RDF } from '../ontologies';
import { _RDF, _RDFA, _RDFS, _OWL, _SH, _SKOS, _SPARQL, _XSD } from "../ontologies";
import { EventEmitter } from "stream";
import { Reasoner } from "./reasoners/reasoner";
import { RdfXmlParser } from "rdfxml-streaming-parser";
import { toRdflibTerm } from "./utils";
import { IToken, TurtleLexer, TurtleParser, TurtleReader, TurtleQuadReader, QuadReaderError, NQuadsLexer, NQuadsParser, NQuadsReader, createFileBlankNodeIdGenerator } from "@faubulous/mentor-rdf-parsers";
import { DatasetView } from "./dataset-view";
/**
* Indicates an error when a triple is not found in the store.
*/
export class TripleNotFoundError extends Error {
/**
* Create a new instance of the error.
* @param message The error message.
*/
constructor(subject: rdfjs.Quad_Subject | null, predicate: rdfjs.Quad_Predicate | null, object: rdfjs.Quad_Object | null) {
super(`No triple was found matching the pattern: ${subject} ${predicate} ${object}`);
this.name = "TripleNotFoundError";
}
}
/*
* A store for RDF triples with support for reasoning.
*/
export class Store implements rdfjs.DatasetCore<rdfjs.Quad> {
/**
* The adapted RDF.js triple store implementation. Replaced by {@link clear}.
*
* Reads go through `_store.readQuads`, a live iterator over the indexes. The dataset
* view's `match` is never used for reading: rdf-stores implements it by copying every
* matching quad into a new store first, which costs hundreds of megabytes and
* seconds for a graph the size of a workspace vocabulary.
*/
private _store = RdfStore.createDefault();
/**
* The RDF dataset view of {@link _store}, used for the mutations and membership
* checks of the `DatasetCore` interface.
*/
private _ds: rdfjs.DatasetCore = this._store.asDataset();
/**
* The reasoner to be used for inference.
*/
readonly reasoner?: Reasoner;
/**
* A monotonic counter that is incremented on every mutation of the store.
*/
private _version = 0;
/**
* Monotonic counters per graph URI, incremented on every mutation of the graph.
*/
private readonly _graphVersions = new Map<string, number>();
/**
* Get a monotonic counter that is incremented on every mutation of the store.
* Can be used to cheaply detect whether the store has changed.
*/
get version(): number {
return this._version;
}
/**
* Get the number of triples in all graphs of the store.
*/
get size(): number {
return this._ds.size;
}
/**
* Get the RDF.js DataFactory used by the store.
*/
get dataFactory(): rdfjs.DataFactory {
return this._store.dataFactory;
}
/**
* Create a new RDF triple store.
* @param reasoner The reasoner to be used for inference.
*/
constructor(reasoner?: Reasoner) {
this.reasoner = reasoner;
}
[Symbol.iterator](): Iterator<rdfjs.Quad, any, any> {
return this._ds[Symbol.iterator]();
}
/**
* Get a monotonic counter for a single graph, incremented on every mutation of the graph.
* Can be used to cheaply detect whether the contents of a graph have changed.
* @param graphUri A graph URI.
* @returns The current version of the graph; `0` if the graph was never modified.
*/
getGraphVersion(graphUri: string): number {
return this._graphVersions.get(graphUri) ?? 0;
}
private _touchGraph(graphUri: string): void {
this._version++;
this._graphVersions.set(graphUri, (this._graphVersions.get(graphUri) ?? 0) + 1);
}
/**
* Loads a set of W3C Standard ontologies into the store (RDF, RDFA, RDFS, OWL, SKOS, SHACL, XSD)
* and the SPARQL Syntax Vocabulary.
* @deprecated The ontology sources embedded in this package will be removed in the next major
* release. Import the published Turtle files instead (e.g. `@faubulous/mentor-rdf/ontologies/rdfs.ttl`)
* and load them with {@link loadTurtle}.
*/
async loadFrameworkOntologies(executeInference: boolean = true): Promise<void> {
this.loadTurtle(src.rdf, _RDF, executeInference);
this.loadTurtle(src.rdfa, _RDFA, executeInference);
this.loadTurtle(src.rdfs, _RDFS, executeInference);
this.loadTurtle(src.owl, _OWL, executeInference);
this.loadTurtle(src.sh, _SH, executeInference);
this.loadTurtle(src.skos, _SKOS, executeInference);
this.loadTurtle(src.sparql, _SPARQL, executeInference);
this.loadTurtle(src.xsd, _XSD, executeInference);
}
/**
* Add a quad to the store. Existing quads with the same subject, predicate, object, and graph will be ignored.
* @param quad The quad to be added.
* @returns The store instance.
*/
add(quad: rdfjs.Quad): this {
this._ds.add(quad);
this._touchGraph(quad.graph.value);
return this;
}
/**
* Delete a quad from the store.
* @param quad The quad to be deleted.
* @returns The store instance.
*/
delete(quad: rdfjs.Quad): this {
this._ds.delete(quad);
this._touchGraph(quad.graph.value);
return this;
}
/**
* Indicates if the store contains a specific quad.
* @param quad The quad to be checked.
* @returns `true` if the quad is found in the store, `false` otherwise.
*/
has(quad: rdfjs.Quad): boolean {
return this._ds.has(quad);
}
/**
* Get the URIs of the graphs in the triple store.
* @returns An array of graph URIs in no particular order.
* @note Every mutation of the store records the graph it touched, so the graphs are the
* recorded ones that still hold a triple. Matching all triples instead would copy the whole
* store, which takes seconds for a store holding a large workspace.
*/
getGraphs(): string[] {
return Array.from(this._graphVersions.keys()).filter(graphUri => this._hasTriples(graphUri));
}
/**
* Indicates if a graph holds at least one triple, without reading more than one.
* @param graph The graph term, or its URI with an empty string for the default graph.
*/
private _hasTriples(graph: rdfjs.Quad_Graph | string): boolean {
return !this._store.readQuads(null, null, null, this._getGraphTerm(graph)).next().done;
}
/**
* Resolves a graph URI to its term; an empty string denotes the default graph.
* @param graph The graph term or URI.
*/
private _getGraphTerm(graph: rdfjs.Quad_Graph | string): rdfjs.Quad_Graph {
if (typeof graph !== 'string') {
return graph;
}
return graph === '' ? this.dataFactory.defaultGraph() : this.dataFactory.namedNode(graph);
}
/**
* Load a set of triples into the store.
* @param quads An array of quads to be loaded into the store.
* @param graphUri The target graph URI.
* @param executeInference Indicates if inference should be executed after loading the triples.
* @param clearGraph Indicates if the graph should be cleared before loading.
* @param onQuad A callback function that will be called for each parsed triple.
*/
private _remapBlankNodes(quads: rdfjs.Quad[], graphUri: string): rdfjs.Quad[] {
let h = 5381;
for (let i = 0; i < graphUri.length; i++) {
h = (h * 33 ^ graphUri.charCodeAt(i)) | 0;
}
const prefix = (h >>> 0).toString(36);
const idMap = new Map<string, string>();
const remap = (term: rdfjs.Term): rdfjs.Term => {
Eif (term.termType !== 'BlankNode') return term;
const key = term.value;
if (!idMap.has(key)) {
idMap.set(key, `${prefix}_${key}`);
}
return this.dataFactory.blankNode(idMap.get(key)!);
};
return quads.map(q => this.dataFactory.quad(
remap(q.subject) as rdfjs.Quad_Subject,
q.predicate,
remap(q.object) as rdfjs.Quad_Object,
q.graph
));
}
private _loadQuads(quads: rdfjs.Quad[], graphUri: string, executeInference: boolean = true, clearGraph: boolean = true, onQuad?: (quad: rdfjs.Quad) => void) {
const graph = this.dataFactory.namedNode(graphUri.replace('\\', '\/'));
// Only clear the graph once if there had been no errors.
Eif (clearGraph) {
this.deleteGraphs([graphUri], true);
}
for (let q of quads) {
this._ds.add(this.dataFactory.quad(q.subject, q.predicate, q.object, graph));
if (onQuad) {
onQuad(q);
}
}
this._touchGraph(graph.value);
if (this.reasoner && executeInference) {
this._expand(graphUri);
}
}
/**
* Runs the reasoner over a graph. The reasoner is handed this store rather than the
* dataset view, so its reads are live iterators and its writes bump the graph versions.
* @param graphUri The URI of the source graph.
*/
private _expand(graphUri: string): void {
Iif (!this.reasoner) {
return;
}
this.reasoner.expand(this, graphUri);
this._touchGraph(this.reasoner.targetUriGenerator.getGraphUri(graphUri));
}
/**
* Create an RDF store from Turtle, N3 or N-Triples data.
* @param input Input string in Turtle, N3 or N-Triples format.
* @param graphUri URI of the graph to in which the triples will be created.
* @param executeInference Indicates if inference should be executed after loading the triples.
* @param clearGraph Indicates if the graph should be cleared before loading.
* @param onQuad Callback function that will be called for each parsed triple.
* @returns A promise that resolves to an RDF store.
*/
loadTurtle(input: string, graphUri: string, executeInference: boolean = true, clearGraph: boolean = true, onQuad?: (quad: rdfjs.Quad) => void): Store {
const tokens = new TurtleLexer(createFileBlankNodeIdGenerator(graphUri)).tokenize(input).tokens;
const quads = this._readTurtleQuads(tokens);
this._loadQuads(quads, graphUri, executeInference, clearGraph, onQuad);
return this;
}
/**
* Reads the quads of a Turtle token stream. A valid document is read without a syntax
* tree, which is the fast path. A document the quad reader rejects is parsed with error
* recovery and read from its syntax tree, so that a partially valid document yields the
* quads it did before.
* @param tokens The tokens of the document.
* @returns The quads of the document.
*/
private _readTurtleQuads(tokens: IToken[]): rdfjs.Quad[] {
try {
return new TurtleQuadReader().read(tokens);
} catch (error) {
Iif (!(error instanceof QuadReaderError)) {
throw error;
}
const cst = new TurtleParser().parse(tokens, false);
return new TurtleReader().visit(cst) as rdfjs.Quad[];
}
}
/**
* Create an RDF store from N-Quads data.
* @param input Input string in N-Quads format.
* @param graphUri URI of the default graph to use when quads have no graph component.
* @param executeInference Indicates if inference should be executed after loading the triples.
* @param clearGraph Indicates if the graph should be cleared before loading.
* @param onQuad Callback function that will be called for each parsed triple.
* @returns The store instance.
*/
loadNQuads(input: string, graphUri: string, executeInference: boolean = true, clearGraph: boolean = true, onQuad?: (quad: rdfjs.Quad) => void): Store {
const tokens = new NQuadsLexer(createFileBlankNodeIdGenerator(graphUri)).tokenize(input).tokens;
const cst = new NQuadsParser().parse(tokens, false);
const quads = new NQuadsReader().visit(cst) as rdfjs.Quad[];
this._loadQuads(quads, graphUri, executeInference, clearGraph, onQuad);
return this;
}
/**
* Create an RDF store from RDF/XML data.
* @param input Input data or stream format to be parsed.
* @param graphUri URI of the graph to in which the triples will be created.
* @param executeInference Indicates if inference should be executed after loading the triples.
* @param clearGraph Indicates if the graph should be cleared before loading.
* @param onQuad Callback function that will be called for each parsed triple.
* @returns A promise that resolves to an RDF store.
*/
async loadFromXmlStream(input: string | EventEmitter, graphUri: string, executeInference: boolean = true, clearGraph: boolean = true, onQuad?: (quad: rdfjs.Quad) => void): Promise<Store> {
return new Promise((resolve, reject) => {
let quads: rdfjs.Quad[] = [];
const parser = new RdfXmlParser();
Iif (typeof input === 'string') {
parser.on('error', (error) => reject(error));
parser.on('data', (quad) => quads.push(quad));
parser.on('end', () => {
this._loadQuads(this._remapBlankNodes(quads, graphUri), graphUri, executeInference, clearGraph, onQuad);
resolve(this);
});
parser.write(input);
parser.end();
} else {
parser.import(input)
.on('error', (error) => reject(error))
.on('data', (quad) => quads.push(quad))
.on('end', () => {
this._loadQuads(this._remapBlankNodes(quads, graphUri), graphUri, executeInference, clearGraph, onQuad);
resolve(this);
});
}
});
}
/**
* Write the triples in the store into a string in Turtle format.
* @param sourceGraphUri A graph URI.
* @param targetFormat Optional mime type of the serialization format (e.g., 'text/turtle').
* @param targetGraphUri Optional target graph URI. If not provided, the source graph URI will be used for serialization formats that support quads.
* @param prefixes Optional prefixes to be used in the serialization.
* @returns A string serialization of the triples in the graph in the specified format.
*/
async serializeGraph(sourceGraphUri: string, targetFormat: string = 'text/turtle', targetGraphUri?: string, prefixes?: Record<string, string>): Promise<string> {
// rdflib is only used here. Loading it on demand keeps its module evaluation
// out of the start-up of every application that imports this package.
const rdflib = await import("rdflib");
return new Promise((resolve, reject) => {
const sourceGraph = this.dataFactory.namedNode(sourceGraphUri);
const targetGraph = targetGraphUri ? this.dataFactory.namedNode(targetGraphUri) : undefined;
const store = rdflib.graph();
// Unfortunately the termType values of RDFJS terms are not directly compatible with rdflib.
// For serialization, rdflib expectes a compareTerm function to sort blank nodes which does not
// exist in the RDFJS interface or n3.Terms.
const g = targetGraph ? toRdflibTerm(targetGraph, rdflib) as any : undefined;
for (const q of this._store.readQuads(null, null, null, sourceGraph)) {
const s = toRdflibTerm(q.subject, rdflib) as any;
const p = toRdflibTerm(q.predicate, rdflib) as any;
const o = toRdflibTerm(q.object, rdflib) as any;
store.add(s, p, o, g);
}
const callback = (error: any, result?: string) => {
Iif (error) {
reject(error);
} else {
resolve(result ?? '');
}
};
rdflib.serialize(null, store as any, null, targetFormat, callback, prefixes);
});
}
/**
* Indicates if the store contains triples in a given graph.
* @param graphUri A graph URI.
* @returns `true` if the store contains triples in the graph URI, `false` otherwise.
*/
hasGraph(graphUri: rdfjs.Quad_Graph | string): boolean {
return this._hasTriples(graphUri);
}
/**
* Indicates whether a graph holds the triples the reasoner inferred from another graph.
* @param graph A graph term or URI.
* @returns `true` if the graph is an inference graph of the reasoner of this store, `false` otherwise or without a reasoner.
*/
isInferenceGraph(graph: rdfjs.Quad_Graph | string): boolean {
return this.reasoner !== undefined && this.reasoner.targetUriGenerator.isInferenceGraphUri(graph);
}
/**
* Indicates whether a quad was inferred by the reasoner, i.e. whether it is stored in an inference
* graph. A triple that is asserted and inferred exists as two quads; only the quad in the inference
* graph is inferred.
* @param quad A quad.
* @returns `true` if the quad is stored in an inference graph, `false` otherwise.
*/
isInferred(quad: rdfjs.Quad): boolean {
return this.isInferenceGraph(quad.graph);
}
/**
* Apply inference to the given graph and store the triples in the associated inference graph.
* @param graphUri A graph URI.
*/
executeInference(graphUri: rdfjs.Quad_Graph | string) {
this._expand(typeof graphUri === 'string' ? graphUri : graphUri.value);
}
/**
* Delete named graphs from the store.
* @param graphUris URIs of the graphs to be deleted; an empty string denotes the default graph.
* @param includeInferred Whether to also delete the inference graph of each graph, as
* named by the reasoner's target URI generator. Ignored when the store has no reasoner.
*/
deleteGraphs(graphUris: string[], includeInferred: boolean = false) {
const uris = includeInferred && this.reasoner
? graphUris.flatMap(uri => [uri, this.reasoner!.targetUriGenerator.getGraphUri(uri)])
: graphUris;
for (const graphUri of uris) {
// Snapshot the quads first: the indexes must not change underneath the iterator.
const quads = this._store.getQuads(null, null, null, this._getGraphTerm(graphUri));
for (const quad of quads) {
this._store.removeQuad(quad);
}
if (quads.length > 0) {
this._touchGraph(graphUri);
}
}
}
/**
* Removes every quad from the store and releases the memory of the underlying store,
* including its term dictionary, which never shrinks when quads are deleted. The
* version counters keep increasing so that cached views and validators notice the change.
*/
clear(): void {
this._store = RdfStore.createDefault();
this._ds = this._store.asDataset();
for (const graphUri of this._graphVersions.keys()) {
this._touchGraph(graphUri);
}
this._version++;
}
/**
* Get the URIs of ordered list members in the store.
* @param graphUris Optional graph URI or array of graph URIs to query.
* @param listUri URI of the list to get the items from.
* @returns An array of URIs of the items in the list.
*/
getListItems(graphUris: string | string[] | undefined, listUri: string): string[] {
// To do: Fix #10
const list = listUri.includes(':') ?
this.dataFactory.namedNode(listUri) :
this.dataFactory.blankNode(listUri);
return this._getListItems(graphUris, list).map(t => t.value);
}
/**
* Recursively collect the items of an ordered list.
* @param graphUris Optional graph URI or array of graph URIs to query.
* @param subject The list node to collect the items from.
* @param visited Set of list nodes that have already been visited.
* @returns An array of the items in the list.
*/
private _getListItems(graphUris: string | string[] | undefined, subject: rdfjs.Quad_Subject, visited: Set<string> = new Set<string>()): rdfjs.Quad_Subject[] {
// Guard against cyclic lists, which would otherwise cause infinite recursion.
if (visited.has(subject.value)) {
return [];
}
visited.add(subject.value);
const first = Array.from(this.matchAll(graphUris, subject, rdf.first, null));
Iif (!first.length) {
return [];
}
const rest = Array.from(this.matchAll(graphUris, subject, rdf.rest, null));
const firstItem = first[0].object as rdfjs.Quad_Subject;
const restList = rest[0]?.object as rdfjs.Quad_Subject | undefined;
// A list node without a rdf:rest property is treated as the last node of the list.
if (!restList || restList.value === RDF.nil) {
return [firstItem];
} else {
const restItems = this._getListItems(graphUris, restList, visited);
return [firstItem, ...restItems];
}
}
/**
* Returns the exact cardinality of the quads matching the pattern.
* @param subject The optional subject.
* @param predicate The optional predicate.
* @param object The optional object.
* @param graph The optional graph.
*/
countQuads(subject?: rdfjs.Term | null, predicate?: rdfjs.Term | null, object?: rdfjs.Term | null, graph?: rdfjs.Term | null): number {
return this._store.countQuads(subject, predicate, object, graph);
}
/**
* Returns a lazy, read-only dataset view of the quads matching the given pattern.
* Implements the RDF/JS `DatasetCore.match` semantics: a graph names exactly that
* graph and no graph means every graph of the store, inference graphs included.
* The result reflects the current contents of the store and does not copy any
* quads. Because the view iterates the live indexes, do not add or delete quads
* while iterating it; take a snapshot with `Array.from(...)` first.
* @param subject The optional subject.
* @param predicate The optional predicate.
* @param object The optional object.
* @param graph The optional graph.
* @returns A read-only dataset view of the matching quads.
*/
match(subject?: rdfjs.Term | null, predicate?: rdfjs.Term | null, object?: rdfjs.Term | null, graph?: rdfjs.Term | null): DatasetView {
return new DatasetView(this, {
subject: subject ?? null,
predicate: predicate ?? null,
object: object ?? null,
graphs: graph != null ? [graph as rdfjs.Quad_Graph] : undefined,
includeInferred: graph != null ? false : undefined
});
}
/**
* Synchronously iterate the quads matching a single pattern. The iterator is live:
* do not add or delete quads while iterating; take a snapshot with `Array.from(...)` first.
* @param subject The optional subject.
* @param predicate The optional predicate.
* @param object The optional object.
* @param graph The optional graph.
*/
*matchQuads(subject?: rdfjs.Term | null, predicate?: rdfjs.Term | null, object?: rdfjs.Term | null, graph?: rdfjs.Term | null): Generator<rdfjs.Quad> {
yield* this._store.readQuads(subject, predicate, object, graph);
}
/**
* Get an RDF/JS `Source` interface for the store that streams matching quads.
* Primarily intended for query engines such as Comunica that operate on quad streams.
* @returns A source that returns a stream of quads for a given pattern.
*/
asSource(): rdfjs.Source<rdfjs.Quad> {
return {
match: (subject?: rdfjs.Term | null, predicate?: rdfjs.Term | null, object?: rdfjs.Term | null, graph?: rdfjs.Term | null) =>
this._store.match(subject, predicate, object, graph)
};
}
/**
* Query the store for triples matching the given pattern supporting multiple graphs.
* The iterator is live: do not add or delete quads while iterating; take a snapshot
* with `Array.from(...)` first.
* @param graphUris Optional graph URI or array of graph URIs to query.
* @param subject A subject URI or null to match any subject.
* @param predicate A predicate URI or null to match any predicate.
* @param object An object URI or null to match any object.
* @param includeInferred Whether to read the inference graphs. With graphs given, `undefined` and
* `true` add the inference graph of each graph when a reasoner is available and `false` reads only
* the given graphs. Without graphs, `undefined` and `true` read every graph of the store and `false`
* reads every graph except the inference graphs. `true` without a reasoner throws.
*/
*matchAll(graphUris: string | string[] | undefined, subject: rdfjs.Quad_Subject | null, predicate: rdfjs.Quad_Predicate | null, object: rdfjs.Quad_Object | null, includeInferred?: boolean) {
if (includeInferred && !this.reasoner) {
throw new Error('Reasoner is not available to include inferred triples.');
}
const s = subject as rdfjs.Term | null;
const p = predicate as rdfjs.Term | null;
const o = object as rdfjs.Term | null;
if (graphUris !== undefined) {
const graphs = Array.isArray(graphUris) ? graphUris : [graphUris];
for (const graph of graphs.map(g => this.dataFactory.namedNode(g))) {
yield* this._store.readQuads(s, p, o, graph);
if (includeInferred !== false && this.reasoner) {
const inferenceGraphUri = this.reasoner.targetUriGenerator.getGraphUri(graph.value);
const inferenceGraph = this.dataFactory.namedNode(inferenceGraphUri);
yield* this._store.readQuads(s, p, o, inferenceGraph);
}
}
} else if (includeInferred === false && this.reasoner) {
for (const quad of this._store.readQuads(s, p, o, null)) {
if (!this.isInferenceGraph(quad.graph)) {
yield quad;
}
}
} else {
yield* this._store.readQuads(s, p, o, null);
}
}
/**
* Indicate if there are triples matching the given pattern in the store.
* @param graphUris Optional graph URI or array of graph URIs to query.
* @param subject A subject URI or null to match any subject.
* @param predicate A predicate URI or null to match any predicate.
* @param object An object URI or null to match any object.
* @returns `true` if there are triples matching the pattern, `false` otherwise.
*/
any(graphUris: string | string[] | undefined, subject: rdfjs.Quad_Subject | null, predicate: rdfjs.Quad_Predicate | null, object: rdfjs.Quad_Object | null, includeInferred?: boolean): boolean {
return this.matchAll(graphUris, subject, predicate, object, includeInferred).next().done === false;
}
/**
* Get a read-only DatasetCore view of all quads in the specified graphs.
* The view is lazy and live: it reflects the current contents of the store without
* copying any quads. If you need an immutable snapshot, copy the view into a new
* dataset, e.g. `RdfStore.createDefault().asDataset()`.
* @param graphUris Optional graph URI or array of graph URIs. If undefined, all graphs are included.
* @param includeInferred Whether to include inferred triples. If undefined, inferred triples
* are included when a reasoner is available. If `false`, the inference graphs of the given
* graphs are left out, or, without graphs, every inference graph of the store. If `true`
* without a reasoner, an error is thrown.
* @returns A read-only dataset view of the matching quads.
*/
getDataset(graphUris?: string | string[], includeInferred?: boolean): DatasetView {
return new DatasetView(this, {
graphUris: graphUris === undefined ? undefined : Array.isArray(graphUris) ? graphUris : [graphUris],
includeInferred
});
}
/**
* Get the first triple matching the given pattern in the store.
* @param graphUris Optional graph URI or array of graph URIs to query.
* @param subject A subject URI or null to match any subject.
* @param predicate A predicate URI or null to match any predicate.
* @param object An object URI or null to match any object.
* @returns The first triple that matches the pattern.
* @throws {TripleNotFoundError} If no triple is found matching the pattern.
*/
first(graphUris: string | string[] | undefined, subject: rdfjs.Quad_Subject | null, predicate: rdfjs.Quad_Predicate | null, object: rdfjs.Quad_Object | null, includeInferred?: boolean) {
const result = this.matchAll(graphUris, subject, predicate, object, includeInferred).next().value;
if (!result) {
throw new TripleNotFoundError(subject, predicate, object);
}
return result;
}
} |