@faubulous/mentor-rdf 2.1.8 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4692,7 +4692,7 @@ var ReasonerBase = class {
4692
4692
  this.store = store;
4693
4693
  this.sourceGraph = this.getGraphNode(sourceGraph);
4694
4694
  this.targetGraph = this.getGraphNode(targetGraph);
4695
- for (let quad5 of store.match(null, null, null, this.targetGraph)) {
4695
+ for (const quad5 of Array.from(store.match(null, null, null, this.targetGraph))) {
4696
4696
  store.delete(quad5);
4697
4697
  }
4698
4698
  this.beforeInference();
@@ -9319,7 +9319,7 @@ var toRdflibTerm = (term) => {
9319
9319
  };
9320
9320
 
9321
9321
  // src/rdf/store.ts
9322
- import { TurtleLexer, TurtleParser, TurtleReader, NQuadsLexer, NQuadsParser, NQuadsReader, createFileBlankNodeIdGenerator } from "@faubulous/mentor-rdf-parsers";
9322
+ import { TurtleLexer, TurtleParser, TurtleReader, TurtleQuadReader, QuadReaderError, NQuadsLexer, NQuadsParser, NQuadsReader, createFileBlankNodeIdGenerator } from "@faubulous/mentor-rdf-parsers";
9323
9323
  var TripleNotFoundError = class extends Error {
9324
9324
  /**
9325
9325
  * Create a new instance of the error.
@@ -9337,14 +9337,17 @@ var Store = class {
9337
9337
  */
9338
9338
  constructor(reasoner) {
9339
9339
  /**
9340
- * The adapted RDF.js triple store implementation.
9341
- *
9342
- * Note: Please do not use this directly, but rather use the `_ds` property to access the dataset.
9340
+ * The adapted RDF.js triple store implementation. Replaced by {@link clear}.
9341
+ *
9342
+ * Reads go through `_store.readQuads`, a live iterator over the indexes. The dataset
9343
+ * view's `match` is never used for reading: rdf-stores implements it by copying every
9344
+ * matching quad into a new store first, which costs hundreds of megabytes and
9345
+ * seconds for a graph the size of a workspace vocabulary.
9343
9346
  */
9344
9347
  this._store = RdfStore2.createDefault();
9345
9348
  /**
9346
- * The RDF dataset containing the triples in the store, which should primarily be used
9347
- * for any operations so that the store can be swapped out with a different implementation.
9349
+ * The RDF dataset view of {@link _store}, used for the mutations and membership
9350
+ * checks of the `DatasetCore` interface.
9348
9351
  */
9349
9352
  this._ds = this._store.asDataset();
9350
9353
  /**
@@ -9437,13 +9440,29 @@ var Store = class {
9437
9440
  /**
9438
9441
  * Get the URIs of the graphs in the triple store.
9439
9442
  * @returns An array of graph URIs in no particular order.
9443
+ * @note Every mutation of the store records the graph it touched, so the graphs are the
9444
+ * recorded ones that still hold a triple. Matching all triples instead would copy the whole
9445
+ * store, which takes seconds for a store holding a large workspace.
9440
9446
  */
9441
9447
  getGraphs() {
9442
- const result = /* @__PURE__ */ new Set();
9443
- for (const q of this._ds.match(null, null, null, null)) {
9444
- result.add(q.graph.value);
9448
+ return Array.from(this._graphVersions.keys()).filter((graphUri) => this._hasTriples(graphUri));
9449
+ }
9450
+ /**
9451
+ * Indicates if a graph holds at least one triple, without reading more than one.
9452
+ * @param graph The graph term, or its URI with an empty string for the default graph.
9453
+ */
9454
+ _hasTriples(graph2) {
9455
+ return !this._store.readQuads(null, null, null, this._getGraphTerm(graph2)).next().done;
9456
+ }
9457
+ /**
9458
+ * Resolves a graph URI to its term; an empty string denotes the default graph.
9459
+ * @param graph The graph term or URI.
9460
+ */
9461
+ _getGraphTerm(graph2) {
9462
+ if (typeof graph2 !== "string") {
9463
+ return graph2;
9445
9464
  }
9446
- return Array.from(result);
9465
+ return graph2 === "" ? this.dataFactory.defaultGraph() : this.dataFactory.namedNode(graph2);
9447
9466
  }
9448
9467
  /**
9449
9468
  * Load a set of triples into the store.
@@ -9478,11 +9497,7 @@ var Store = class {
9478
9497
  _loadQuads(quads, graphUri, executeInference = true, clearGraph = true, onQuad) {
9479
9498
  const graph2 = this.dataFactory.namedNode(graphUri.replace("\\", "/"));
9480
9499
  if (clearGraph) {
9481
- this.deleteGraphs([graphUri]);
9482
- if (this.reasoner) {
9483
- const inferenceGraph = this.dataFactory.namedNode(this.reasoner.targetUriGenerator.getGraphUri(graphUri));
9484
- this.deleteGraphs([inferenceGraph.value]);
9485
- }
9500
+ this.deleteGraphs([graphUri], true);
9486
9501
  }
9487
9502
  for (let q of quads) {
9488
9503
  this._ds.add(this.dataFactory.quad(q.subject, q.predicate, q.object, graph2));
@@ -9492,10 +9507,21 @@ var Store = class {
9492
9507
  }
9493
9508
  this._touchGraph(graph2.value);
9494
9509
  if (this.reasoner && executeInference) {
9495
- this.reasoner.expand(this._ds, graphUri);
9496
- this._touchGraph(this.reasoner.targetUriGenerator.getGraphUri(graphUri));
9510
+ this._expand(graphUri);
9497
9511
  }
9498
9512
  }
9513
+ /**
9514
+ * Runs the reasoner over a graph. The reasoner is handed this store rather than the
9515
+ * dataset view, so its reads are live iterators and its writes bump the graph versions.
9516
+ * @param graphUri The URI of the source graph.
9517
+ */
9518
+ _expand(graphUri) {
9519
+ if (!this.reasoner) {
9520
+ return;
9521
+ }
9522
+ this.reasoner.expand(this, graphUri);
9523
+ this._touchGraph(this.reasoner.targetUriGenerator.getGraphUri(graphUri));
9524
+ }
9499
9525
  /**
9500
9526
  * Create an RDF store from Turtle, N3 or N-Triples data.
9501
9527
  * @param input Input string in Turtle, N3 or N-Triples format.
@@ -9507,11 +9533,29 @@ var Store = class {
9507
9533
  */
9508
9534
  loadTurtle(input, graphUri, executeInference = true, clearGraph = true, onQuad) {
9509
9535
  const tokens = new TurtleLexer(createFileBlankNodeIdGenerator(graphUri)).tokenize(input).tokens;
9510
- const cst = new TurtleParser().parse(tokens, false);
9511
- const quads = new TurtleReader().visit(cst);
9536
+ const quads = this._readTurtleQuads(tokens);
9512
9537
  this._loadQuads(quads, graphUri, executeInference, clearGraph, onQuad);
9513
9538
  return this;
9514
9539
  }
9540
+ /**
9541
+ * Reads the quads of a Turtle token stream. A valid document is read without a syntax
9542
+ * tree, which is the fast path. A document the quad reader rejects is parsed with error
9543
+ * recovery and read from its syntax tree, so that a partially valid document yields the
9544
+ * quads it did before.
9545
+ * @param tokens The tokens of the document.
9546
+ * @returns The quads of the document.
9547
+ */
9548
+ _readTurtleQuads(tokens) {
9549
+ try {
9550
+ return new TurtleQuadReader().read(tokens);
9551
+ } catch (error) {
9552
+ if (!(error instanceof QuadReaderError)) {
9553
+ throw error;
9554
+ }
9555
+ const cst = new TurtleParser().parse(tokens, false);
9556
+ return new TurtleReader().visit(cst);
9557
+ }
9558
+ }
9515
9559
  /**
9516
9560
  * Create an RDF store from N-Quads data.
9517
9561
  * @param input Input string in N-Quads format.
@@ -9572,7 +9616,7 @@ var Store = class {
9572
9616
  const targetGraph = targetGraphUri ? this.dataFactory.namedNode(targetGraphUri) : void 0;
9573
9617
  const store = graph();
9574
9618
  const g = targetGraph ? toRdflibTerm(targetGraph) : void 0;
9575
- for (const q of this._ds.match(null, null, null, sourceGraph)) {
9619
+ for (const q of this._store.readQuads(null, null, null, sourceGraph)) {
9576
9620
  const s = toRdflibTerm(q.subject);
9577
9621
  const p = toRdflibTerm(q.predicate);
9578
9622
  const o = toRdflibTerm(q.object);
@@ -9594,40 +9638,46 @@ var Store = class {
9594
9638
  * @returns `true` if the store contains triples in the graph URI, `false` otherwise.
9595
9639
  */
9596
9640
  hasGraph(graphUri) {
9597
- const uri = typeof graphUri === "string" ? this.dataFactory.namedNode(graphUri) : graphUri;
9598
- for (const _ of this._ds.match(null, null, null, uri)) {
9599
- return true;
9600
- }
9601
- return false;
9641
+ return this._hasTriples(graphUri);
9602
9642
  }
9603
9643
  /**
9604
9644
  * Apply inference to the given graph and store the triples in the associated inference graph.
9605
9645
  * @param graphUri A graph URI.
9606
9646
  */
9607
9647
  executeInference(graphUri) {
9608
- if (this.reasoner) {
9609
- this.reasoner.expand(this._ds, graphUri);
9610
- const uri = typeof graphUri === "string" ? graphUri : graphUri.value;
9611
- this._touchGraph(this.reasoner.targetUriGenerator.getGraphUri(uri));
9612
- }
9648
+ this._expand(typeof graphUri === "string" ? graphUri : graphUri.value);
9613
9649
  }
9614
9650
  /**
9615
9651
  * Delete named graphs from the store.
9616
- * @param graphUris URIs of the graphs to be deleted.
9617
- */
9618
- deleteGraphs(graphUris) {
9619
- for (const graphUri of graphUris) {
9620
- const graph2 = this.dataFactory.namedNode(graphUri);
9621
- let deleted = false;
9622
- for (const quad5 of this._ds.match(null, null, null, graph2)) {
9623
- this._ds.delete(quad5);
9624
- deleted = true;
9625
- }
9626
- if (deleted) {
9652
+ * @param graphUris URIs of the graphs to be deleted; an empty string denotes the default graph.
9653
+ * @param includeInferred Whether to also delete the inference graph of each graph, as
9654
+ * named by the reasoner's target URI generator. Ignored when the store has no reasoner.
9655
+ */
9656
+ deleteGraphs(graphUris, includeInferred = false) {
9657
+ const uris = includeInferred && this.reasoner ? graphUris.flatMap((uri) => [uri, this.reasoner.targetUriGenerator.getGraphUri(uri)]) : graphUris;
9658
+ for (const graphUri of uris) {
9659
+ const quads = this._store.getQuads(null, null, null, this._getGraphTerm(graphUri));
9660
+ for (const quad5 of quads) {
9661
+ this._store.removeQuad(quad5);
9662
+ }
9663
+ if (quads.length > 0) {
9627
9664
  this._touchGraph(graphUri);
9628
9665
  }
9629
9666
  }
9630
9667
  }
9668
+ /**
9669
+ * Removes every quad from the store and releases the memory of the underlying store,
9670
+ * including its term dictionary, which never shrinks when quads are deleted. The
9671
+ * version counters keep increasing so that cached views and validators notice the change.
9672
+ */
9673
+ clear() {
9674
+ this._store = RdfStore2.createDefault();
9675
+ this._ds = this._store.asDataset();
9676
+ for (const graphUri of this._graphVersions.keys()) {
9677
+ this._touchGraph(graphUri);
9678
+ }
9679
+ this._version++;
9680
+ }
9631
9681
  /**
9632
9682
  * Get the URIs of ordered list members in the store.
9633
9683
  * @param graphUris Optional graph URI or array of graph URIs to query.
@@ -9677,7 +9727,9 @@ var Store = class {
9677
9727
  /**
9678
9728
  * Returns a lazy, read-only dataset view of the quads matching the given pattern.
9679
9729
  * Implements the RDF/JS `DatasetCore.match` semantics: the result reflects the
9680
- * current contents of the store and does not copy any quads.
9730
+ * current contents of the store and does not copy any quads. Because the view
9731
+ * iterates the live indexes, do not add or delete quads while iterating it;
9732
+ * take a snapshot with `Array.from(...)` first.
9681
9733
  * @param subject The optional subject.
9682
9734
  * @param predicate The optional predicate.
9683
9735
  * @param object The optional object.
@@ -9694,14 +9746,15 @@ var Store = class {
9694
9746
  });
9695
9747
  }
9696
9748
  /**
9697
- * Synchronously iterate the quads matching a single pattern.
9749
+ * Synchronously iterate the quads matching a single pattern. The iterator is live:
9750
+ * do not add or delete quads while iterating; take a snapshot with `Array.from(...)` first.
9698
9751
  * @param subject The optional subject.
9699
9752
  * @param predicate The optional predicate.
9700
9753
  * @param object The optional object.
9701
9754
  * @param graph The optional graph.
9702
9755
  */
9703
9756
  *matchQuads(subject, predicate, object, graph2) {
9704
- yield* this._ds.match(subject, predicate, object, graph2);
9757
+ yield* this._store.readQuads(subject, predicate, object, graph2);
9705
9758
  }
9706
9759
  /**
9707
9760
  * Get an RDF/JS `Source` interface for the store that streams matching quads.
@@ -9715,6 +9768,8 @@ var Store = class {
9715
9768
  }
9716
9769
  /**
9717
9770
  * Query the store for triples matching the given pattern supporting multiple graphs.
9771
+ * The iterator is live: do not add or delete quads while iterating; take a snapshot
9772
+ * with `Array.from(...)` first.
9718
9773
  * @param graphUris Optional graph URI or array of graph URIs to query.
9719
9774
  * @param subject A subject URI or null to match any subject.
9720
9775
  * @param predicate A predicate URI or null to match any predicate.
@@ -9730,19 +9785,15 @@ var Store = class {
9730
9785
  if (graphUris !== void 0) {
9731
9786
  const graphs = Array.isArray(graphUris) ? graphUris : [graphUris];
9732
9787
  for (const graph2 of graphs.map((g) => this.dataFactory.namedNode(g))) {
9733
- for (const q of this._ds.match(s, p, o, graph2)) {
9734
- yield q;
9735
- }
9788
+ yield* this._store.readQuads(s, p, o, graph2);
9736
9789
  if (includeInferred !== false && this.reasoner) {
9737
9790
  const inferenceGraphUri = this.reasoner.targetUriGenerator.getGraphUri(graph2.value);
9738
9791
  const inferenceGraph = this.dataFactory.namedNode(inferenceGraphUri);
9739
- for (let q of this._ds.match(s, p, o, inferenceGraph)) {
9740
- yield q;
9741
- }
9792
+ yield* this._store.readQuads(s, p, o, inferenceGraph);
9742
9793
  }
9743
9794
  }
9744
9795
  } else {
9745
- yield* this._ds.match(s, p, o);
9796
+ yield* this._store.readQuads(s, p, o, null);
9746
9797
  }
9747
9798
  }
9748
9799
  /**