n3 1.21.0 → 1.21.2

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/lib/N3Store.js CHANGED
@@ -21,6 +21,32 @@ function merge(target, source, depth = 4) {
21
21
  return target;
22
22
  }
23
23
 
24
+ /**
25
+ * Determines the intersection of the `_graphs` index s1 and s2.
26
+ * s1 and s2 *must* belong to Stores that share an `_entityIndex`.
27
+ *
28
+ * False is returned when there is no intersection; this should
29
+ * *not* be set as the value for an index.
30
+ */
31
+ function intersect(s1, s2, depth = 4) {
32
+ let target = false;
33
+ for (const key in s1) {
34
+ if (key in s2) {
35
+ const intersection = depth === 0 ? null : intersect(s1[key], s2[key], depth - 1);
36
+ if (intersection !== false) {
37
+ target = target || Object.create(null);
38
+ target[key] = intersection;
39
+ }
40
+ // Depth 3 is the 'subjects', 'predicates' and 'objects' keys.
41
+ // If the 'subjects' index is empty, so will the 'predicates' and 'objects' index.
42
+ else if (depth === 3) {
43
+ return false;
44
+ }
45
+ }
46
+ }
47
+ return target;
48
+ }
49
+
24
50
  // ## Constructor
25
51
  class N3EntityIndex {
26
52
  constructor(options = {}) {
@@ -851,6 +877,17 @@ class N3Store {
851
877
  });
852
878
  store._graphs = merge(Object.create(null), this._graphs);
853
879
  store._size = this._size;
880
+ return store;
881
+ } else if (other instanceof N3Store && this._entityIndex === other._entityIndex) {
882
+ const store = new N3Store({
883
+ entityIndex: this._entityIndex
884
+ });
885
+ const graphs = intersect(other._graphs, this._graphs);
886
+ if (graphs) {
887
+ store._graphs = graphs;
888
+ store._size = null;
889
+ }
890
+ return store;
854
891
  }
855
892
  return this.filter(quad => other.has(quad));
856
893
  }
@@ -939,9 +976,33 @@ class N3Store {
939
976
  }
940
977
 
941
978
  /**
942
- * A class that implements both DatasetCore and Readable.
979
+ * Returns a subset of the `index` with that part of the index
980
+ * matching the `ids` array. `ids` contains 3 elements that are
981
+ * either numerical ids; or `null`.
982
+ *
983
+ * `false` is returned when there are no matching indices; this should
984
+ * *not* be set as the value for an index.
943
985
  */
944
986
  exports.default = N3Store;
987
+ function indexMatch(index, ids, depth = 0) {
988
+ const ind = ids[depth];
989
+ if (ind && !(ind in index)) return false;
990
+ let target = false;
991
+ for (const key in ind ? {
992
+ [ind]: index[ind]
993
+ } : index) {
994
+ const result = depth === 2 ? null : indexMatch(index[key], ids, depth + 1);
995
+ if (result !== false) {
996
+ target = target || Object.create(null);
997
+ target[key] = result;
998
+ }
999
+ }
1000
+ return target;
1001
+ }
1002
+
1003
+ /**
1004
+ * A class that implements both DatasetCore and Readable.
1005
+ */
945
1006
  class DatasetCoreAndReadableStream extends _readableStream.Readable {
946
1007
  constructor(n3Store, subject, predicate, object, graph, options) {
947
1008
  super({
@@ -969,7 +1030,22 @@ class DatasetCoreAndReadableStream extends _readableStream.Readable {
969
1030
  factory: n3Store._factory,
970
1031
  entityIndex: this.options.entityIndex
971
1032
  });
972
- for (const quad of n3Store.readQuads(subject, predicate, object, graph)) newStore.addQuad(quad);
1033
+ const graphs = n3Store._getGraphs(graph);
1034
+ let subjectId, predicateId, objectId;
1035
+
1036
+ // Translate IRIs to internal index keys.
1037
+ if (subject && !(subjectId = newStore._termToNumericId(subject)) || predicate && !(predicateId = newStore._termToNumericId(predicate)) || object && !(objectId = newStore._termToNumericId(object))) return newStore;
1038
+ for (const graph in graphs) {
1039
+ const subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId]);
1040
+ if (subjects) {
1041
+ newStore._graphs[graph] = {
1042
+ subjects,
1043
+ predicates: indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId]),
1044
+ objects: indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId])
1045
+ };
1046
+ }
1047
+ }
1048
+ newStore._size = null;
973
1049
  }
974
1050
  return this._filtered;
975
1051
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -34,9 +34,9 @@
34
34
  "@babel/preset-env": "^7.16.0",
35
35
  "@babel/register": "^7.16.0",
36
36
  "@rdfjs/data-model": "^1",
37
- "arrayify-stream": "^1.0.0",
37
+ "arrayify-stream": "^3.0.0",
38
38
  "browserify": "^17.0.0",
39
- "deep-taxonomy-benchmark": "^1.2.0",
39
+ "deep-taxonomy-benchmark": "^2.0.0",
40
40
  "docco": "^0.9.1",
41
41
  "eslint": "^8.57.0",
42
42
  "eslint-plugin-import": "^2.29.1",
package/src/N3Store.js CHANGED
@@ -17,6 +17,34 @@ function merge(target, source, depth = 4) {
17
17
  return target;
18
18
  }
19
19
 
20
+ /**
21
+ * Determines the intersection of the `_graphs` index s1 and s2.
22
+ * s1 and s2 *must* belong to Stores that share an `_entityIndex`.
23
+ *
24
+ * False is returned when there is no intersection; this should
25
+ * *not* be set as the value for an index.
26
+ */
27
+ function intersect(s1, s2, depth = 4) {
28
+ let target = false;
29
+
30
+ for (const key in s1) {
31
+ if (key in s2) {
32
+ const intersection = depth === 0 ? null : intersect(s1[key], s2[key], depth - 1);
33
+ if (intersection !== false) {
34
+ target = target || Object.create(null);
35
+ target[key] = intersection;
36
+ }
37
+ // Depth 3 is the 'subjects', 'predicates' and 'objects' keys.
38
+ // If the 'subjects' index is empty, so will the 'predicates' and 'objects' index.
39
+ else if (depth === 3) {
40
+ return false;
41
+ }
42
+ }
43
+ }
44
+
45
+ return target;
46
+ }
47
+
20
48
  // ## Constructor
21
49
  export class N3EntityIndex {
22
50
  constructor(options = {}) {
@@ -901,7 +929,18 @@ export default class N3Store {
901
929
  const store = new N3Store({ entityIndex: this._entityIndex });
902
930
  store._graphs = merge(Object.create(null), this._graphs);
903
931
  store._size = this._size;
932
+ return store;
933
+ }
934
+ else if ((other instanceof N3Store) && this._entityIndex === other._entityIndex) {
935
+ const store = new N3Store({ entityIndex: this._entityIndex });
936
+ const graphs = intersect(other._graphs, this._graphs);
937
+ if (graphs) {
938
+ store._graphs = graphs;
939
+ store._size = null;
940
+ }
941
+ return store;
904
942
  }
943
+
905
944
  return this.filter(quad => other.has(quad));
906
945
  }
907
946
 
@@ -987,6 +1026,31 @@ export default class N3Store {
987
1026
  }
988
1027
  }
989
1028
 
1029
+ /**
1030
+ * Returns a subset of the `index` with that part of the index
1031
+ * matching the `ids` array. `ids` contains 3 elements that are
1032
+ * either numerical ids; or `null`.
1033
+ *
1034
+ * `false` is returned when there are no matching indices; this should
1035
+ * *not* be set as the value for an index.
1036
+ */
1037
+ function indexMatch(index, ids, depth = 0) {
1038
+ const ind = ids[depth];
1039
+ if (ind && !(ind in index))
1040
+ return false;
1041
+
1042
+ let target = false;
1043
+ for (const key in (ind ? { [ind]: index[ind] } : index)) {
1044
+ const result = depth === 2 ? null : indexMatch(index[key], ids, depth + 1);
1045
+
1046
+ if (result !== false) {
1047
+ target = target || Object.create(null);
1048
+ target[key] = result;
1049
+ }
1050
+ }
1051
+ return target;
1052
+ }
1053
+
990
1054
  /**
991
1055
  * A class that implements both DatasetCore and Readable.
992
1056
  */
@@ -1000,8 +1064,27 @@ class DatasetCoreAndReadableStream extends Readable {
1000
1064
  if (!this._filtered) {
1001
1065
  const { n3Store, graph, object, predicate, subject } = this;
1002
1066
  const newStore = this._filtered = new N3Store({ factory: n3Store._factory, entityIndex: this.options.entityIndex });
1003
- for (const quad of n3Store.readQuads(subject, predicate, object, graph))
1004
- newStore.addQuad(quad);
1067
+ const graphs = n3Store._getGraphs(graph);
1068
+
1069
+ let subjectId, predicateId, objectId;
1070
+
1071
+ // Translate IRIs to internal index keys.
1072
+ if (subject && !(subjectId = newStore._termToNumericId(subject)) ||
1073
+ predicate && !(predicateId = newStore._termToNumericId(predicate)) ||
1074
+ object && !(objectId = newStore._termToNumericId(object)))
1075
+ return newStore;
1076
+
1077
+ for (const graph in graphs) {
1078
+ const subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId]);
1079
+ if (subjects) {
1080
+ newStore._graphs[graph] = {
1081
+ subjects,
1082
+ predicates: indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId]),
1083
+ objects: indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId]),
1084
+ };
1085
+ }
1086
+ }
1087
+ newStore._size = null;
1005
1088
  }
1006
1089
  return this._filtered;
1007
1090
  }