@_linked/rdf-mem-store 0.0.1

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.
Files changed (137) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +285 -0
  3. package/lib/cjs/Datafactory.d.ts +29 -0
  4. package/lib/cjs/Datafactory.js +101 -0
  5. package/lib/cjs/Datafactory.js.map +1 -0
  6. package/lib/cjs/InMemoryStore.d.ts +35 -0
  7. package/lib/cjs/InMemoryStore.js +98 -0
  8. package/lib/cjs/InMemoryStore.js.map +1 -0
  9. package/lib/cjs/collections/NodeMap.d.ts +35 -0
  10. package/lib/cjs/collections/NodeMap.js +244 -0
  11. package/lib/cjs/collections/NodeMap.js.map +1 -0
  12. package/lib/cjs/collections/NodeSet.d.ts +55 -0
  13. package/lib/cjs/collections/NodeSet.js +296 -0
  14. package/lib/cjs/collections/NodeSet.js.map +1 -0
  15. package/lib/cjs/collections/NodeURIMappings.d.ts +20 -0
  16. package/lib/cjs/collections/NodeURIMappings.js +65 -0
  17. package/lib/cjs/collections/NodeURIMappings.js.map +1 -0
  18. package/lib/cjs/collections/NodeValuesSet.d.ts +63 -0
  19. package/lib/cjs/collections/NodeValuesSet.js +100 -0
  20. package/lib/cjs/collections/NodeValuesSet.js.map +1 -0
  21. package/lib/cjs/collections/QuadArray.d.ts +17 -0
  22. package/lib/cjs/collections/QuadArray.js +67 -0
  23. package/lib/cjs/collections/QuadArray.js.map +1 -0
  24. package/lib/cjs/collections/QuadMap.d.ts +64 -0
  25. package/lib/cjs/collections/QuadMap.js +155 -0
  26. package/lib/cjs/collections/QuadMap.js.map +1 -0
  27. package/lib/cjs/collections/QuadSet.d.ts +22 -0
  28. package/lib/cjs/collections/QuadSet.js +106 -0
  29. package/lib/cjs/collections/QuadSet.js.map +1 -0
  30. package/lib/cjs/collections/SearchMap.d.ts +5 -0
  31. package/lib/cjs/collections/SearchMap.js +13 -0
  32. package/lib/cjs/collections/SearchMap.js.map +1 -0
  33. package/lib/cjs/events/EventBatcher.d.ts +20 -0
  34. package/lib/cjs/events/EventBatcher.js +97 -0
  35. package/lib/cjs/events/EventBatcher.js.map +1 -0
  36. package/lib/cjs/events/EventEmitter.d.ts +15 -0
  37. package/lib/cjs/events/EventEmitter.js +102 -0
  38. package/lib/cjs/events/EventEmitter.js.map +1 -0
  39. package/lib/cjs/index.d.ts +14 -0
  40. package/lib/cjs/index.js +48 -0
  41. package/lib/cjs/index.js.map +1 -0
  42. package/lib/cjs/interfaces/IGraphObject.d.ts +29 -0
  43. package/lib/cjs/interfaces/IGraphObject.js +3 -0
  44. package/lib/cjs/interfaces/IGraphObject.js.map +1 -0
  45. package/lib/cjs/interfaces/IGraphObjectSet.d.ts +24 -0
  46. package/lib/cjs/interfaces/IGraphObjectSet.js +3 -0
  47. package/lib/cjs/interfaces/IGraphObjectSet.js.map +1 -0
  48. package/lib/cjs/interfaces/IShape.d.ts +22 -0
  49. package/lib/cjs/interfaces/IShape.js +3 -0
  50. package/lib/cjs/interfaces/IShape.js.map +1 -0
  51. package/lib/cjs/interfaces/ISingleGraphObject.d.ts +3 -0
  52. package/lib/cjs/interfaces/ISingleGraphObject.js +3 -0
  53. package/lib/cjs/interfaces/ISingleGraphObject.js.map +1 -0
  54. package/lib/cjs/models.d.ts +1167 -0
  55. package/lib/cjs/models.js +2668 -0
  56. package/lib/cjs/models.js.map +1 -0
  57. package/lib/cjs/package.json +3 -0
  58. package/lib/cjs/utils/Debug.d.ts +3 -0
  59. package/lib/cjs/utils/Debug.js +46 -0
  60. package/lib/cjs/utils/Debug.js.map +1 -0
  61. package/lib/cjs/utils/LocalQueryResolver.d.ts +21 -0
  62. package/lib/cjs/utils/LocalQueryResolver.js +1442 -0
  63. package/lib/cjs/utils/LocalQueryResolver.js.map +1 -0
  64. package/lib/cjs/utils/URI.d.ts +18 -0
  65. package/lib/cjs/utils/URI.js +42 -0
  66. package/lib/cjs/utils/URI.js.map +1 -0
  67. package/lib/cjs/utils/toNamedNode.d.ts +8 -0
  68. package/lib/cjs/utils/toNamedNode.js +15 -0
  69. package/lib/cjs/utils/toNamedNode.js.map +1 -0
  70. package/lib/esm/Datafactory.d.ts +29 -0
  71. package/lib/esm/Datafactory.js +97 -0
  72. package/lib/esm/Datafactory.js.map +1 -0
  73. package/lib/esm/InMemoryStore.d.ts +35 -0
  74. package/lib/esm/InMemoryStore.js +94 -0
  75. package/lib/esm/InMemoryStore.js.map +1 -0
  76. package/lib/esm/collections/NodeMap.d.ts +35 -0
  77. package/lib/esm/collections/NodeMap.js +240 -0
  78. package/lib/esm/collections/NodeMap.js.map +1 -0
  79. package/lib/esm/collections/NodeSet.d.ts +55 -0
  80. package/lib/esm/collections/NodeSet.js +292 -0
  81. package/lib/esm/collections/NodeSet.js.map +1 -0
  82. package/lib/esm/collections/NodeURIMappings.d.ts +20 -0
  83. package/lib/esm/collections/NodeURIMappings.js +61 -0
  84. package/lib/esm/collections/NodeURIMappings.js.map +1 -0
  85. package/lib/esm/collections/NodeValuesSet.d.ts +63 -0
  86. package/lib/esm/collections/NodeValuesSet.js +96 -0
  87. package/lib/esm/collections/NodeValuesSet.js.map +1 -0
  88. package/lib/esm/collections/QuadArray.d.ts +17 -0
  89. package/lib/esm/collections/QuadArray.js +63 -0
  90. package/lib/esm/collections/QuadArray.js.map +1 -0
  91. package/lib/esm/collections/QuadMap.d.ts +64 -0
  92. package/lib/esm/collections/QuadMap.js +151 -0
  93. package/lib/esm/collections/QuadMap.js.map +1 -0
  94. package/lib/esm/collections/QuadSet.d.ts +22 -0
  95. package/lib/esm/collections/QuadSet.js +102 -0
  96. package/lib/esm/collections/QuadSet.js.map +1 -0
  97. package/lib/esm/collections/SearchMap.d.ts +5 -0
  98. package/lib/esm/collections/SearchMap.js +9 -0
  99. package/lib/esm/collections/SearchMap.js.map +1 -0
  100. package/lib/esm/events/EventBatcher.d.ts +20 -0
  101. package/lib/esm/events/EventBatcher.js +90 -0
  102. package/lib/esm/events/EventBatcher.js.map +1 -0
  103. package/lib/esm/events/EventEmitter.d.ts +15 -0
  104. package/lib/esm/events/EventEmitter.js +98 -0
  105. package/lib/esm/events/EventEmitter.js.map +1 -0
  106. package/lib/esm/index.d.ts +14 -0
  107. package/lib/esm/index.js +22 -0
  108. package/lib/esm/index.js.map +1 -0
  109. package/lib/esm/interfaces/IGraphObject.d.ts +29 -0
  110. package/lib/esm/interfaces/IGraphObject.js +2 -0
  111. package/lib/esm/interfaces/IGraphObject.js.map +1 -0
  112. package/lib/esm/interfaces/IGraphObjectSet.d.ts +24 -0
  113. package/lib/esm/interfaces/IGraphObjectSet.js +2 -0
  114. package/lib/esm/interfaces/IGraphObjectSet.js.map +1 -0
  115. package/lib/esm/interfaces/IShape.d.ts +22 -0
  116. package/lib/esm/interfaces/IShape.js +2 -0
  117. package/lib/esm/interfaces/IShape.js.map +1 -0
  118. package/lib/esm/interfaces/ISingleGraphObject.d.ts +3 -0
  119. package/lib/esm/interfaces/ISingleGraphObject.js +2 -0
  120. package/lib/esm/interfaces/ISingleGraphObject.js.map +1 -0
  121. package/lib/esm/models.d.ts +1167 -0
  122. package/lib/esm/models.js +2659 -0
  123. package/lib/esm/models.js.map +1 -0
  124. package/lib/esm/package.json +3 -0
  125. package/lib/esm/utils/Debug.d.ts +3 -0
  126. package/lib/esm/utils/Debug.js +42 -0
  127. package/lib/esm/utils/Debug.js.map +1 -0
  128. package/lib/esm/utils/LocalQueryResolver.d.ts +21 -0
  129. package/lib/esm/utils/LocalQueryResolver.js +1434 -0
  130. package/lib/esm/utils/LocalQueryResolver.js.map +1 -0
  131. package/lib/esm/utils/URI.d.ts +18 -0
  132. package/lib/esm/utils/URI.js +38 -0
  133. package/lib/esm/utils/URI.js.map +1 -0
  134. package/lib/esm/utils/toNamedNode.d.ts +8 -0
  135. package/lib/esm/utils/toNamedNode.js +12 -0
  136. package/lib/esm/utils/toNamedNode.js.map +1 -0
  137. package/package.json +57 -0
@@ -0,0 +1,2668 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Quad = exports.defaultGraph = exports.Graph = exports.Literal = exports.BlankNode = exports.NamedNode = exports.Node = void 0;
4
+ const types_js_1 = require("rdflib/lib/types.js");
5
+ const default_graph_uri_js_1 = require("rdflib/lib/utils/default-graph-uri.js");
6
+ const QuadSet_js_1 = require("./collections/QuadSet.js");
7
+ const CoreMap_1 = require("@_linked/core/collections/CoreMap");
8
+ const QuadMap_js_1 = require("./collections/QuadMap.js");
9
+ const QuadArray_js_1 = require("./collections/QuadArray.js");
10
+ const NodeSet_js_1 = require("./collections/NodeSet.js");
11
+ const NodeValuesSet_js_1 = require("./collections/NodeValuesSet.js");
12
+ const EventBatcher_js_1 = require("./events/EventBatcher.js");
13
+ const EventEmitter_js_1 = require("./events/EventEmitter.js");
14
+ const NodeMap_js_1 = require("./collections/NodeMap.js");
15
+ const NodeURIMappings_js_1 = require("./collections/NodeURIMappings.js");
16
+ const CoreSet_1 = require("@_linked/core/collections/CoreSet");
17
+ const Prefix_1 = require("@_linked/core/utils/Prefix");
18
+ class Node extends EventEmitter_js_1.EventEmitter {
19
+ constructor(_value) {
20
+ super();
21
+ this._value = _value;
22
+ }
23
+ get value() {
24
+ return this._value;
25
+ }
26
+ set value(val) {
27
+ this._value = val;
28
+ }
29
+ /**
30
+ * Create an instance of the given class (or one of its subclasses) as a presentation of this node.
31
+ * NOTE: this node MUST have the static.type of the given class as its rdf:type property
32
+ * @param type - a class that extends Shape and thus who's instances represent a node as an instance of one specific type.
33
+ */
34
+ getAs(type) {
35
+ return type.getOf(this);
36
+ }
37
+ /**
38
+ * Create an instance of the given class as a presentation of this node.
39
+ * Other than getAs this 'strict' message will ONLY return an exact instance of the given class, not one of its subclasses
40
+ * rdf.type properties of the node are IGNORED. This method can therefore also come in handy in circumstances when you don't have the node it's rdf.type properties at hand.
41
+ * Do not misuse this method though, the main use case is if you don't want to allow any subclass instances. If that's not neccecarily the case and it would make also sense to have the properties loaded, make sure to load them and use getAs.
42
+ * OR use getAsAsync automatically ensures the data of the node is fully loaded before creating an instance.
43
+ * @param type - a class that extends Shape and thus who's instances represent a node as an instance of one specific type.
44
+ */
45
+ getStrictlyAs(type) {
46
+ return type.getStrictlyOf(this);
47
+ }
48
+ /**
49
+ * Compares whether the two nodes are equal
50
+ * @param other The other node
51
+ */
52
+ equals(other) {
53
+ if (!other) {
54
+ return false;
55
+ }
56
+ return this.termType === other.termType && this.value === other.value;
57
+ }
58
+ set(property, value) {
59
+ return false;
60
+ }
61
+ setValue(property, value) {
62
+ return false;
63
+ }
64
+ has(property, value) {
65
+ return false;
66
+ }
67
+ hasValue(property, value) {
68
+ return false;
69
+ }
70
+ hasExplicit(property, value) {
71
+ return false;
72
+ }
73
+ hasExact(property, value) {
74
+ return false;
75
+ }
76
+ hasProperty(property) {
77
+ return false;
78
+ }
79
+ hasInverseProperty(property) {
80
+ return false;
81
+ }
82
+ hasInverse(property, value) {
83
+ return false;
84
+ }
85
+ mset(property, values) {
86
+ return false;
87
+ }
88
+ getProperties(includeFromIncomingArcs = false) {
89
+ return new NodeSet_js_1.NodeSet();
90
+ }
91
+ getInverseProperties() {
92
+ return new NodeSet_js_1.NodeSet();
93
+ }
94
+ getOne(property) {
95
+ return undefined;
96
+ }
97
+ getAll(property) {
98
+ return new NodeValuesSet_js_1.NodeValuesSet(this, property);
99
+ }
100
+ getValue(property) {
101
+ return undefined;
102
+ }
103
+ getDeep(property, maxDepth = -1, partialResult = new NodeSet_js_1.NodeSet()) {
104
+ return partialResult;
105
+ }
106
+ getOneInverse(property) {
107
+ return undefined;
108
+ }
109
+ getOneWhere(property, filterProperty, filterValue) {
110
+ return undefined;
111
+ }
112
+ getOneWhereEquivalent(property, filterProperty, filterValue, caseSensitive) {
113
+ return undefined;
114
+ }
115
+ getAllExplicit(property) {
116
+ return undefined;
117
+ }
118
+ getAllInverse(property) {
119
+ return undefined;
120
+ }
121
+ getMultiple(properties) {
122
+ return new NodeSet_js_1.NodeSet();
123
+ }
124
+ hasPath(properties) {
125
+ return false;
126
+ }
127
+ hasPathTo(properties, value) {
128
+ return false;
129
+ }
130
+ hasPathToSomeInSet(properties, endPoints) {
131
+ return false;
132
+ }
133
+ getOneFromPath(...properties) {
134
+ return undefined;
135
+ }
136
+ getAllFromPath(...properties) {
137
+ return new NodeSet_js_1.NodeSet();
138
+ }
139
+ getQuads(property, value) {
140
+ return new QuadSet_js_1.QuadSet();
141
+ }
142
+ getInverseQuad(property, subject) {
143
+ return undefined;
144
+ }
145
+ getInverseQuads(property) {
146
+ return new QuadSet_js_1.QuadSet();
147
+ }
148
+ getAllInverseQuads(includeImplicit) {
149
+ return new QuadArray_js_1.QuadArray();
150
+ }
151
+ getAllQuads(includeAsObject = false, includeImplicit = false) {
152
+ return null;
153
+ }
154
+ overwrite(property, value) {
155
+ return false;
156
+ }
157
+ moverwrite(property, value) {
158
+ return false;
159
+ }
160
+ unset(property, value) {
161
+ return false;
162
+ }
163
+ unsetAll(property) {
164
+ return false;
165
+ }
166
+ isLoaded(includingIncomingProperties) {
167
+ return false;
168
+ }
169
+ promiseLoaded(loadInverseProperties) {
170
+ return null;
171
+ }
172
+ getMultipleInverse(properties) {
173
+ return new NodeSet_js_1.NodeSet();
174
+ }
175
+ /**
176
+ * @internal
177
+ * @param quad
178
+ */
179
+ unregisterInverseProperty(quad, alteration, emitEvents) { }
180
+ /**
181
+ * registers the use of a quad. Since a quad can only be used in 1 quad
182
+ * this method makes a clone of the Literal if it's used a second time,
183
+ * and returns that new Literal so it will be used by the quad
184
+ * @internal
185
+ * @param quad
186
+ */
187
+ registerInverseProperty(quad, alteration, emitEvents) {
188
+ return null;
189
+ }
190
+ clone() {
191
+ return null;
192
+ }
193
+ print() {
194
+ return '';
195
+ }
196
+ }
197
+ exports.Node = Node;
198
+ /**
199
+ * A Named Node in the graph is a node that has outgoing edges to other nodes.
200
+ *
201
+ * In RDF specifications, a Named Node is a URI Node.
202
+ * You can manage this by setting and getting 'properties' of this node, which will reflect in which nodes this node is connected with.
203
+ * A Named Node is one of the two types of nodes in a graph in the semantic web / RDF.
204
+ * The other one being Literal
205
+ * @see https://www.w3.org/TR/rdf-concepts/#section-Graph-URIref
206
+ *
207
+ * @example
208
+ *
209
+ * Use NamedNode.getOrCreate() if you have a URI
210
+ * Use NamedNode.create() to create a new NamedNode without specifying a URI
211
+ * Do NOT use the constructor
212
+ *
213
+ * ```
214
+ * let node = NamedNode.create();
215
+ * let node = NamedNode.getOrCreate("http://url.of.some/node")
216
+ * ```
217
+ */
218
+ class NamedNode extends Node {
219
+ /**
220
+ * WARNING: Do not directly create a Node, instead use NamedNode.getOrCreate(uri)
221
+ * This ensures the same node is used for the same uri system wide
222
+ * @param uri - the URI (more generic form of a URL) of the NamedNode
223
+ * @param _isTemporaryNode - set to true if this node is only temporarily available in the local environment
224
+ */
225
+ constructor(uri = '', _isTemporaryNode = false) {
226
+ super(uri);
227
+ this._isTemporaryNode = _isTemporaryNode;
228
+ /**
229
+ * map of QuadMaps indexed by property (where this node occurs as subject)
230
+ * NOTE: 'properties' serves only to increase lookup speed but also costs memory
231
+ * since reverse lookup (where this node occurs as object) will be much less frequent
232
+ * the inverse of 'properties' is not kept, so all results for reverse lookup will be created from 'asObject'
233
+ * @internal
234
+ */
235
+ this.properties = new CoreMap_1.CoreMap();
236
+ // private static termType: string = 'NamedNode';
237
+ this.termType = 'NamedNode';
238
+ /**
239
+ * map of QuadMaps indexed by property where this node occurs as subject
240
+ * NOTE: we use QuadMap here because in ES5 a quadMap is much faster than a quadSet, because we can check by key with uri directly if the quad exists instead of having to look in an array with indexOf (ES5 does not support objects as keys)
241
+ * @internal
242
+ */
243
+ this.asSubject = new Map();
244
+ if (this._isTemporaryNode) {
245
+ //created locally, so we know everything about it there is to know
246
+ // this.allPropertiesLoaded = {promise: Promise.resolve(this), done: true};
247
+ }
248
+ }
249
+ get isStoring() {
250
+ return this._isStoring && true;
251
+ }
252
+ set isStoring(storing) {
253
+ //when storing
254
+ if (storing) {
255
+ //create a deferred promise and store it as _isStoring
256
+ this._isStoring = {};
257
+ this._isStoring.promise = new Promise((resolve, reject) => {
258
+ this._isStoring.resolve = resolve;
259
+ this._isStoring.reject = reject;
260
+ });
261
+ }
262
+ else {
263
+ //when done storing, resolve the promise
264
+ this._isStoring.resolve();
265
+ delete this._isStoring;
266
+ }
267
+ }
268
+ /**
269
+ * JSLib.js documentation states: "Alias for value, favored by Tim" ... LINCD author René agrees with Tim
270
+ * @see https://github.com/linkeddata/rdflib.js/blob/bbf456390afe7743020e0c8c4db20b10cfb808c7/src/named-node.ts#L88
271
+ */
272
+ get uri() {
273
+ return this._value;
274
+ }
275
+ set uri(uri) {
276
+ this.value = uri;
277
+ }
278
+ /**
279
+ * Alias for uri, so NamedNode satisfies NodeReferenceValue ({id: string}) from core.
280
+ */
281
+ get id() {
282
+ return this._value;
283
+ }
284
+ /**
285
+ * Returns true if this node has a temporary URI and only exists in the local environment.
286
+ * e.g. this is usually true if you create a new NamedNode without having specified a URI yet
287
+ */
288
+ get isTemporaryNode() {
289
+ return this._isTemporaryNode;
290
+ }
291
+ set isTemporaryNode(val) {
292
+ this._isTemporaryNode = val;
293
+ }
294
+ get value() {
295
+ return this._value;
296
+ }
297
+ set value(newUri) {
298
+ if (NamedNode.namedNodes.has(newUri)) {
299
+ throw new Error('Cannot update URI. A node with this URI already exists: ' +
300
+ newUri +
301
+ '. You tried to update the URI of ' +
302
+ this._value);
303
+ }
304
+ var oldUri = this._value;
305
+ NamedNode.namedNodes.delete(this._value);
306
+ this._value = newUri;
307
+ NamedNode.namedNodes.set(this._value, this);
308
+ // //if this node had a temporary URI
309
+ // if (this._isTemporaryNode) {
310
+ // //it now has an explicit URI, so it's no longer temporary
311
+ // this._isTemporaryNode = false;
312
+ // }
313
+ this.emit(NamedNode.URI_UPDATED, this, oldUri, newUri);
314
+ EventBatcher_js_1.eventBatcher.register(NamedNode);
315
+ NamedNode.nodesURIUpdated.set(this, [oldUri, newUri]);
316
+ }
317
+ /**
318
+ * Emits the batched (property) events of the NamedNode CLASS (meaning events that relate to all nodes)
319
+ * Used internally by the framework to batch and emit change events
320
+ * @internal
321
+ */
322
+ static emitBatchedEvents(resolve, reject) {
323
+ if (this.nodesToRemove.size) {
324
+ this.emitter.emit(NamedNode.REMOVE_NODES, this.nodesToRemove);
325
+ this.nodesToRemove = new CoreSet_1.CoreSet();
326
+ }
327
+ if (this.nodesToSave.size) {
328
+ this.emitter.emit(NamedNode.STORE_NODES, this.nodesToSave);
329
+ this.nodesToSave = new NodeSet_js_1.NodeSet();
330
+ }
331
+ if (this.nodesToLoad.size || this.nodesToLoadFully.size) {
332
+ this.emitter.emit(NamedNode.LOAD_NODES, this.nodesToLoad, this.nodesToLoadFully);
333
+ this.nodesToLoad = new NodeSet_js_1.NodeSet();
334
+ this.nodesToLoadFully = new NodeSet_js_1.NodeSet();
335
+ }
336
+ if (this.nodesURIUpdated.size) {
337
+ this.emitter.emit(NamedNode.URI_UPDATED, this.nodesURIUpdated);
338
+ this.nodesURIUpdated = new CoreMap_1.CoreMap();
339
+ }
340
+ if (this.clearedProperties.size) {
341
+ this.emitter.emit(NamedNode.CLEARED_PROPERTIES, this.clearedProperties);
342
+ this.clearedProperties = new CoreMap_1.CoreMap();
343
+ }
344
+ }
345
+ /**
346
+ * Returns true if this node has any batched events waiting to be emitted
347
+ * Used internally by the framework to batch and emit change events
348
+ * @internal
349
+ */
350
+ static hasBatchedEvents() {
351
+ return (this.nodesToRemove.size > 0 ||
352
+ this.nodesToSave.size > 0 ||
353
+ this.nodesToLoad.size ||
354
+ this.nodesToLoadFully.size > 0 ||
355
+ this.nodesURIUpdated.size > 0 ||
356
+ this.clearedProperties.size > 0);
357
+ }
358
+ /**
359
+ * Converts the string '<http://some.uri>' into a NamedNode
360
+ * @param uriString the string representation of a NamedNode, consisting of its URI surrounded by brackets: '<' URI '>'
361
+ */
362
+ static fromString(uriString) {
363
+ var firstChar = uriString.substr(0, 1);
364
+ if (firstChar == '<') {
365
+ return this.getOrCreate(uriString.substr(1, uriString.length - 2));
366
+ }
367
+ else {
368
+ throw new Error('fromString expects a URI wrapped in brackets, like <http://www.example.com>');
369
+ }
370
+ }
371
+ /**
372
+ * Resets the map of nodes that is known in this local environment
373
+ * Mostly used for test functionality
374
+ */
375
+ static reset() {
376
+ this.tempCounter = 0;
377
+ this.namedNodes = new NodeMap_js_1.NodeMap();
378
+ }
379
+ /**
380
+ * Create a new local NamedNode. A temporary URI will be generated for its URI.
381
+ * This node will not exist in the graph database (persistent storage) until you call `node.save()`
382
+ * Until saved, `node.isTemporaryNode()` will return true.
383
+ */
384
+ static create() {
385
+ let tmpURI = this.createNewTempUri();
386
+ while (this.getNamedNode(tmpURI)) {
387
+ this.tempCounter++;
388
+ tmpURI = this.createNewTempUri();
389
+ }
390
+ return this._create(tmpURI, true);
391
+ }
392
+ /**
393
+ * Registers a NamedNode to the locally known list of nodes
394
+ * @internal
395
+ * @param node
396
+ */
397
+ static register(node) {
398
+ if (this.namedNodes.has(node.uri)) {
399
+ throw new Error('A node with this URI already exists: "' +
400
+ node.uri +
401
+ '". You should probably use NamedNode.getOrCreate instead of NamedNode.create (' +
402
+ node.uri +
403
+ ')');
404
+ }
405
+ this.namedNodes.set(node.uri, node);
406
+ }
407
+ /**
408
+ * Unregisters a NamedNode from the locally known list of nodes
409
+ * @internal
410
+ * @param node
411
+ */
412
+ static unregister(node) {
413
+ if (!this.namedNodes.has(node.uri)) {
414
+ throw new Error('This node has already been removed from the registry: ' + node.uri);
415
+ }
416
+ this.namedNodes.delete(node.uri);
417
+ }
418
+ /**
419
+ * Returns a map of all locally known nodes.
420
+ * The map will have URI's as keys and NamedNodes as values
421
+ * @param node
422
+ */
423
+ static getAllNamedNodes() {
424
+ return this.namedNodes;
425
+ }
426
+ /**
427
+ * Returns a map of all locally known nodes.
428
+ * The map will have URI's as keys and NamedNodes as values
429
+ * @param node
430
+ */
431
+ static createNewTempUri() {
432
+ return this.TEMP_URI_BASE + this.tempCounter++; //+'/';+Date.now()+Math.random();
433
+ }
434
+ static getCounter() {
435
+ return this.tempCounter;
436
+ }
437
+ /**
438
+ * ##########################################################################
439
+ * ############# PUBLIC METHODS FOR REGULAR USE #############
440
+ * ##########################################################################
441
+ */
442
+ /**
443
+ * The proper way to obtain a node from a URI.
444
+ * If requested before, this returns the existing NamedNode for the given URI.
445
+ * Or, if this is the first request for this URI, it creates a new NamedNode first, and returns that
446
+ * Using this method over `new NamedNode()` makes sure all nodes are registered, and no duplicates will exist.
447
+ * `new NamedNode()` should therefore never be used.
448
+ * @param uri
449
+ */
450
+ static getOrCreate(uri, isTemporaryNode = false) {
451
+ return this.getNamedNode(uri) || this._create(uri, isTemporaryNode);
452
+ }
453
+ /**
454
+ * Returns the NamedNode with the given URI, IF it exists.
455
+ * DOES NOT create a new NamedNode if it didn't exist yet, instead it returns undefined.
456
+ * You can therefore use this method to see if a NamedNode already exists locally.
457
+ * Use `getOrCreate()` if you want to simply get a NamedNode for a certain URI
458
+ * @param uri
459
+ */
460
+ static getNamedNode(uri) {
461
+ return this.namedNodes.get(uri);
462
+ }
463
+ static emitClearedProperty(node, property) {
464
+ //if not a local node we will emit events for storage controllers to be picked up
465
+ if (!node.isTemporaryNode) {
466
+ //regardless of how many values are known 'locally', we want to emit this event so that the source of data can eventually properly clear all values
467
+ if (!NamedNode.clearedProperties.has(node)) {
468
+ NamedNode.clearedProperties.set(node, []);
469
+ EventBatcher_js_1.eventBatcher.register(NamedNode);
470
+ }
471
+ //we save the property that was cleared AND the quads that were cleared
472
+ NamedNode.clearedProperties
473
+ .get(node)
474
+ .push([
475
+ property,
476
+ node.asSubject.has(property)
477
+ ? new QuadArray_js_1.QuadArray(...node.asSubject.get(property).getQuadSet())
478
+ : null,
479
+ ]);
480
+ }
481
+ }
482
+ static _create(uri, isLocalNode = false) {
483
+ var node = new NamedNode(uri, isLocalNode);
484
+ this.register(node);
485
+ return node;
486
+ }
487
+ /**
488
+ * Used by Quads to signal their subject about a new property
489
+ * @internal
490
+ * @param quad
491
+ * @param alteration
492
+ * @param emitEvents
493
+ */
494
+ registerProperty(quad, alteration = false, emitEvents = true) {
495
+ var predicate = quad.predicate;
496
+ //first make sure we have a QuadMap value for key=predicate
497
+ if (!this.asSubject.has(predicate)) {
498
+ this.asSubject.set(predicate, new QuadMap_js_1.QuadMap());
499
+ this.properties.set(predicate, new NodeValuesSet_js_1.NodeValuesSet(this, predicate));
500
+ }
501
+ //Add the quad to the QuadMap (see implementation for more details)
502
+ let quadMap = this.asSubject.get(predicate);
503
+ //make sure we have a QuadSet ready for the object of this quad
504
+ quadMap.__set(quad.object, quad);
505
+ //Now for the property index (which gives direct access to the object values of a certain predicate)
506
+ //Because multiple graphs can hold the same subj-pred-obj triple, we want to avoid adding literal values
507
+ //that have the exact same literal value, so we need to test for equality here before adding it
508
+ if (!this.properties
509
+ .get(predicate)
510
+ .some((object) => object.equals(quad.object))) {
511
+ this.properties.get(predicate).__add(quad.object);
512
+ }
513
+ //add this quad to the map of events to send on the next tick
514
+ if (emitEvents) {
515
+ if (!this.changedProperties)
516
+ this.changedProperties = new CoreMap_1.CoreMap();
517
+ if (alteration && !this.alteredProperties)
518
+ this.alteredProperties = new CoreMap_1.CoreMap();
519
+ //register this change as alteration (user input) or as normal (automatic, data based) property change
520
+ this.registerPropertyChange(quad, alteration
521
+ ? [this.changedProperties, this.alteredProperties]
522
+ : [this.changedProperties]);
523
+ }
524
+ }
525
+ /**
526
+ * Inverse property can be thought of as "this node is the value (object) of another nodes' property"
527
+ * This method is used by the class Quad to communicate its existence to the quads object
528
+ * @internal
529
+ * @param quad
530
+ * @param alteration
531
+ * @param emitEvents
532
+ */
533
+ registerInverseProperty(quad, alteration = false, emitEvents = true) {
534
+ //asObject is not always initialised - to save some memory on nodes without incoming properties (only used as subject)
535
+ if (!this.asObject) {
536
+ this.asObject = new CoreMap_1.CoreMap();
537
+ }
538
+ var index = quad.predicate;
539
+ if (!this.asObject.has(index)) {
540
+ this.asObject.set(index, new QuadMap_js_1.QuadMap());
541
+ }
542
+ this.asObject.get(index).__set(quad.subject, quad);
543
+ //add this quad to the map of events to send on the next tick
544
+ if (emitEvents) {
545
+ if (!this.changedInverseProperties)
546
+ this.changedInverseProperties = new CoreMap_1.CoreMap();
547
+ if (alteration && !this.alteredInverseProperties)
548
+ this.alteredInverseProperties = new CoreMap_1.CoreMap();
549
+ this.registerPropertyChange(quad, alteration
550
+ ? [this.changedInverseProperties, this.alteredInverseProperties]
551
+ : [this.changedInverseProperties]);
552
+ }
553
+ //need to return this, see Literal
554
+ return this;
555
+ }
556
+ /**
557
+ * Called when this node occurs as predicate in a quad
558
+ * @internal
559
+ */
560
+ // registerAsPredicate(
561
+ // quad: Quad,
562
+ // alteration: boolean = false,
563
+ // emitEvents: boolean = true,
564
+ // ) {
565
+ // //asPredicate is not always initialised because only properties can occur as predicate
566
+ // if (!this.asPredicate) {
567
+ // this.asPredicate = new QuadArray();
568
+ // }
569
+ // this.asPredicate.push(quad);
570
+ //
571
+ // if (emitEvents) {
572
+ // this.registerPredicateChange(quad, alteration);
573
+ // }
574
+ // }
575
+ /**
576
+ * This method is used by the class Quad to communicate with its nodes
577
+ * @internal
578
+ * @param quad
579
+ * @param alteration
580
+ */
581
+ registerValueChange(quad, alteration = false) {
582
+ if (!this.changedProperties)
583
+ this.changedProperties = new CoreMap_1.CoreMap();
584
+ if (alteration) {
585
+ if (!this.alteredProperties)
586
+ this.alteredProperties = new CoreMap_1.CoreMap();
587
+ }
588
+ this.registerPropertyChange(quad, alteration
589
+ ? [this.changedProperties, this.alteredProperties]
590
+ : [this.changedProperties]);
591
+ }
592
+ /**
593
+ * This method is used by the class Quad to communicate with its nodes
594
+ * @internal
595
+ */
596
+ unregisterProperty(quad, alteration = false, emitEvents = true) {
597
+ var predicate = quad.predicate;
598
+ //start by looking through the QuadMap (it is more complete than the quick & easy properties index, as it accounts for multiple quads per object value in different graphs)
599
+ var quadMap = this.asSubject.get(predicate);
600
+ if (quadMap) {
601
+ let valueQuads = quadMap.get(quad.object);
602
+ if (!valueQuads)
603
+ return;
604
+ valueQuads.delete(quad);
605
+ //if we no longer hold any quads for this object
606
+ if (valueQuads.size == 0) {
607
+ //remove the key
608
+ quadMap.__delete(quad.object);
609
+ //for this.properties we just keep ONE value for identical literals (in case multiple graphs hold the same subject-pred-obj triple)
610
+ //so here we check if any other object that is still registered equals the current object
611
+ if (![...quadMap.keys()].some((object) => quad.object.equals(object))) {
612
+ //if that's not the case, then also remove this object from the propertySet index (the index should exist)
613
+ //Note: in some cases, for example when a quad moved between graphs, the object registered here as property value might not be the same as the as the object of the quad that is still registered,
614
+ // therefor we also check & remove equivalent values in case regular removal didnt work
615
+ //TODO: we could improve this by making sure that this.properties stays up to date with the actual quads
616
+ this.properties.get(predicate).__delete(quad.object) ||
617
+ this.properties
618
+ .get(predicate)
619
+ .__delete(this.properties
620
+ .get(predicate)
621
+ .find((object) => object.equals(quad.object)));
622
+ }
623
+ //if we now also no longer hold any values for this predicate
624
+ //NOTE: this was turned off because NodeValuesSets are reused, recreating a new one when a new value
625
+ // is added then does not add the value to the old one.
626
+ // if (quadMap.size === 0) {
627
+ // //delete both indices for this predicate
628
+ // this.asSubject.delete(predicate);
629
+ // this.properties.delete(predicate);
630
+ // }
631
+ }
632
+ }
633
+ //NOTE: also when removing property values (therefore unregistering the property), we add the removed quad to the SAME list of changed properties
634
+ //event listeners will have to filter out which quad was added or removed
635
+ if (emitEvents) {
636
+ if (!this.changedProperties)
637
+ this.changedProperties = new CoreMap_1.CoreMap();
638
+ if (alteration && !this.alteredProperties)
639
+ this.alteredProperties = new CoreMap_1.CoreMap();
640
+ this.registerPropertyChange(quad, alteration
641
+ ? [this.changedProperties, this.alteredProperties]
642
+ : [this.changedProperties]);
643
+ }
644
+ }
645
+ /**
646
+ * This method is used by the class Quad to communicate with its nodes
647
+ * @internal
648
+ */
649
+ // unregisterAsPredicate(
650
+ // quad: Quad,
651
+ // alteration: boolean = false,
652
+ // emitEvents: boolean = true,
653
+ // ) {
654
+ // this.asPredicate.splice(this.asPredicate.indexOf(quad), 1);
655
+ //
656
+ // if (emitEvents) {
657
+ // this.registerPredicateChange(quad, alteration);
658
+ // }
659
+ // }
660
+ //
661
+ // /**
662
+ // * Returns a list of quads in which this node is now used as predicate
663
+ // * BEFORE these changes are sent as events in the normal event flow
664
+ // * Currently used by Reasoner to allow for immediate application of reasoning
665
+ // */
666
+ // getPendingPredicateChanges(): QuadArray {
667
+ // return this.changedAsPredicate;
668
+ // }
669
+ /**
670
+ * This method is used by the class Quad to communicate with its nodes
671
+ * @internal
672
+ */
673
+ unregisterInverseProperty(quad, alteration = false, emitEvents = true) {
674
+ //start by looking through the QuadMap (it is more complete than the quick & easy properties index, as it accounts for identical sub-pred-obj triples that occur in different graphs)
675
+ //here we get a map of all the quads for the given predicate, grouped by subject (each map contains identical triples, but with different graphs)
676
+ var quadMap = this.asObject.get(quad.predicate);
677
+ if (quadMap) {
678
+ let quadSet = quadMap.get(quad.subject);
679
+ if (!quadSet)
680
+ return;
681
+ //remove this quad
682
+ quadSet.delete(quad);
683
+ //if we no longer hold any quads for this subject
684
+ if (quadSet.size === 0) {
685
+ quadMap.__delete(quad.subject);
686
+ }
687
+ if (quadMap.size == 0) {
688
+ this.asObject.delete(quad.predicate);
689
+ }
690
+ }
691
+ //also when removing the property do wee add the removed quad to the list of changed properties
692
+ //event listeners will have to filter out which quad was added or removed
693
+ if (emitEvents) {
694
+ if (!this.changedInverseProperties)
695
+ this.changedInverseProperties = new CoreMap_1.CoreMap();
696
+ if (alteration && !this.alteredInverseProperties)
697
+ this.alteredInverseProperties = new CoreMap_1.CoreMap();
698
+ this.registerPropertyChange(quad, alteration
699
+ ? [this.changedInverseProperties, this.alteredInverseProperties]
700
+ : [this.changedInverseProperties]);
701
+ }
702
+ }
703
+ /**
704
+ * Returns a list of quads in which this node is now used as object
705
+ * BEFORE these changes are sent as events in the normal event flow
706
+ * Currently used by Reasoner to allow for immediate application of reasoning
707
+ */
708
+ getPendingInverseChanges(property) {
709
+ return this.changedInverseProperties
710
+ ? this.changedInverseProperties.get(property)
711
+ : new QuadSet_js_1.QuadSet();
712
+ }
713
+ /**
714
+ * Returns a list of quads in which this node is now used as subject
715
+ * BEFORE these changes are sent as events in the normal event flow
716
+ * Currently used by Reasoner to allow for immediate application of reasoning
717
+ */
718
+ getPendingChanges(property) {
719
+ return this.changedProperties.get(property);
720
+ }
721
+ /**
722
+ * Set the a single property value
723
+ * Creates a single connection between two nodes in the graph: from this node, to the node given as value, with the property as the connecting 'edge' between them
724
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
725
+ * @param value - the node that this new graph-edge points to. The object of the quad to be created.
726
+ */
727
+ set(property, value) {
728
+ if (!value) {
729
+ throw Error('No value provided to set!');
730
+ }
731
+ //if there is already a quad with exactly this prop-value pair
732
+ if (this.has(property, value)) {
733
+ //make all quads with this pair explicit if they were not yet
734
+ this.getQuads(property, value).makeExplicit();
735
+ //yet return false because nothing was changes in the propreties
736
+ return false;
737
+ }
738
+ //if this pair didn't exist yet, create a new quad (the graph is undefined for now, Storage will pick this up and place it in the right graph)
739
+ //note that the sixth parameter is true, this indicates that this is an alteration (as in new data that triggers change events instead of a quad created for already existing data)
740
+ new Quad(this, property, value, undefined, false, true);
741
+ return true;
742
+ }
743
+ /**
744
+ * Same as set() except this method allows you to pass a string as value and converts it to a Literal for you
745
+ * @param property
746
+ * @param value
747
+ */
748
+ setValue(property, value) {
749
+ return this.set(property, new Literal(value));
750
+ }
751
+ /**
752
+ * Set multiple values at once for a single property.
753
+ * You can use this for example to state that this node (a person) has a 'hasFriend' connection to multiple people (friends) in 1 statement
754
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
755
+ * @param values - an array or set of nodes. Can be NamedNodes or Literals
756
+ */
757
+ mset(property, values) {
758
+ //if(save) dacore.system.storageQueueStart(this);
759
+ var res = false;
760
+ for (var value of values) {
761
+ res = this.set(property, value) || res;
762
+ }
763
+ return res;
764
+ }
765
+ /**
766
+ * Returns true if this node has the given value as the value of the given property
767
+ * NOTE: returns true when a literal node is provided that is EQUIVALENT to any of the values that this node has for this property (whilst not neccecarilly being the exact same object in memory)
768
+ * See also: Literal.equals
769
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
770
+ * @param value - a single node. Can be a NamedNode or Literal
771
+ */
772
+ has(property, value) {
773
+ if (!value) {
774
+ throw new Error('No value provided to NamedNode.has(). Did you mean `hasProperty`?');
775
+ }
776
+ var properties = this.properties.get(property);
777
+ return (properties &&
778
+ (properties.has(value) ||
779
+ properties.some((object) => object.equals(value))));
780
+ }
781
+ /**
782
+ * Returns true if this node has the given value for the given property in an EXPLICIT quad.
783
+ * That is, this property-value has been explicitly set, and is NOT generated by the Reasoner.
784
+ * See the documentation for more information about implicit vs explicit
785
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
786
+ * @param value - a single node. Can be a NamedNode or Literal
787
+ */
788
+ hasExplicit(property, value) {
789
+ if (!this.asSubject.has(property))
790
+ return false;
791
+ return this.getQuadsByValue(property, value).some((quad) => !quad.implicit);
792
+ }
793
+ /**
794
+ * Returns true if this node has ANY explicit quad with the given property
795
+ * See the documentation for more information about implicit vs explicit
796
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
797
+ */
798
+ hasExplicitProperty(property) {
799
+ if (!this.asSubject.has(property))
800
+ return false;
801
+ return this.getQuads(property).some((quad) => !quad.implicit);
802
+ }
803
+ /**
804
+ * Returns true if this node has a Literal as value of the given property who's literal-value (a string) matches the given value
805
+ * So works the same as `has()` except you can provide a string as value, and will obviously not match any NamedNode values
806
+ * And unlike has() this method will NOT check for the Literal its datatype. Instead only checking the literal-value
807
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
808
+ * @param value - the string value we want to check for
809
+ */
810
+ hasValue(property, value) {
811
+ var properties = this.properties.get(property);
812
+ return (properties &&
813
+ properties.some((object) => 'value' in object && object['value'] === value));
814
+ }
815
+ /**
816
+ * Returns true if this node has the given value as the value of the given property with an EXACT match (meaning the same object in memory)
817
+ * So works the same as has() except for Literals this only returns true if the value of the property is exactly the same object as the given value
818
+ * UNLIKE `has()` which checks if the literal value, datatype and language tag of two literal nodes are equivalent
819
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
820
+ * @param value - a single node. Can be a NamedNode or Literal
821
+ */
822
+ hasExact(property, value) {
823
+ var properties = this.properties.get(property);
824
+ return properties && properties.has(value);
825
+ }
826
+ /**
827
+ * Returns true if this node has ANY value set for the given property.
828
+ * That is, if any quad exists that has this node as the subject and the given property as predicate
829
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
830
+ */
831
+ hasProperty(property) {
832
+ //properties can be empty sets, so we need to check if there are any values in the set
833
+ return (this.properties.has(property) && this.properties.get(property).size > 0);
834
+ }
835
+ /**
836
+ * Returns true if the given end point can be reached by following the given properties in order
837
+ * Example: hasPathTo([foaf.hasFriend,rdf.type],foaf.Person) will return true if any of the friends of this node (this person in this example) is of the type foaf:Person
838
+ * @param properties an array of NamedNodes
839
+ * @param endPoint the node to reach, a Literal or a NamedNode
840
+ */
841
+ hasPathTo(properties, endPoint) {
842
+ //we just need to find one matching path, so we do a depth-first algorithm which will be more performant, so:
843
+ //take first property
844
+ var property = properties.shift();
845
+ //if more properties left
846
+ if (properties.length > 0) {
847
+ var res;
848
+ //check if any of the values of that property for this node
849
+ //has a path to the rest of the properties, and if so return the found value
850
+ for (var value of this.getAll(property)) {
851
+ if ((res = value.hasPathTo([...properties], endPoint))) {
852
+ return res;
853
+ }
854
+ }
855
+ return false;
856
+ }
857
+ else {
858
+ //if last property
859
+ //see if we can reach the value if a value was given
860
+ //else: see if any value (any path) exists
861
+ if (endPoint) {
862
+ return this.has(property, endPoint);
863
+ }
864
+ else {
865
+ return this.hasProperty(property);
866
+ }
867
+ }
868
+ }
869
+ getAs(type) {
870
+ return type.getOf(this);
871
+ }
872
+ /**
873
+ * returns true if ANY of the given end points can be reached by following the given properties in the given order
874
+ * Example: hasPathTo([foaf.hasFriend,foaf.hasFriend],[mike,jenny]) will return true if this node (person) has a friend that has mike or jenny as a friend
875
+ * @param properties an array of NamedNodes
876
+ * @param endPoint the node to reach, a Literal or a NamedNode
877
+ */
878
+ hasPathToSomeInSet(properties, endPoints) {
879
+ //we just need to find one matching path, so we do a depth-first algorithm which will be more performant, so:
880
+ //take first property
881
+ var property = properties.shift();
882
+ //if more properties left
883
+ if (properties.length > 0) {
884
+ var res;
885
+ //check if any of the values of that property for this node
886
+ //has a path to the rest of the properties, and if so return the found value
887
+ for (var value of this.getAll(property)) {
888
+ if ((res = value.hasPathToSomeInSet([...properties], endPoints))) {
889
+ return res;
890
+ }
891
+ }
892
+ return false;
893
+ }
894
+ else {
895
+ //if last property
896
+ //see if we can reach the value if a value was given
897
+ //else: see if any value (any path) exists
898
+ return endPoints.some((endPoint) => this.has(property, endPoint));
899
+ }
900
+ }
901
+ /**
902
+ * returns true if ANY end point (node) can be reached by following the given properties in order
903
+ * @param properties an array of NamedNodes
904
+ */
905
+ hasPath(properties) {
906
+ //we just need to find one matching path, so we do a depth-first algorithm which will be more performant, so:
907
+ //take first property
908
+ var property = properties.shift();
909
+ //if more properties left
910
+ if (properties.length > 0) {
911
+ var res;
912
+ //check if any of the values of that property for this node
913
+ //has a path to the rest of the properties, and if so return the found value
914
+ for (var value of this.getAll(property)) {
915
+ if ((res = value.hasPath([...properties]))) {
916
+ return res;
917
+ }
918
+ }
919
+ return false;
920
+ }
921
+ else {
922
+ //if last property
923
+ //see if we can reach the value if a value was given
924
+ //else: see if any value (any path) exists
925
+ return this.hasProperty(property);
926
+ }
927
+ }
928
+ /**
929
+ * Returns a set of all the properties this node has.
930
+ * That is, all unique predicates of quads where this node is the subject
931
+ * @param includeFromIncomingArcs if true, also includes predicates (properties) of quads where this node is the VALUE of another nodes' property. Default: false
932
+ */
933
+ getProperties(includeFromIncomingArcs = false) {
934
+ if (includeFromIncomingArcs) {
935
+ return new NodeSet_js_1.NodeSet((this.asObject
936
+ ? [...this.asSubject.keys(), ...this.asObject.keys()]
937
+ : this.asSubject.keys()));
938
+ }
939
+ else {
940
+ return new NodeSet_js_1.NodeSet(this.asSubject.keys());
941
+ }
942
+ }
943
+ /**
944
+ * Returns a set of all the properties used by this node in EXPLICIT facts (quads)
945
+ * See the documentation for more information about implicit vs explicit facts
946
+ * @param includeFromIncomingArcs if true, also includes predicates (properties) of quads where this node is the VALUE of another nodes' property. Default: false
947
+ */
948
+ getExplicitProperties(includeFromIncomingArcs = false) {
949
+ return new NodeSet_js_1.NodeSet([
950
+ ...this.getAllQuads(includeFromIncomingArcs)
951
+ .filter((t) => !t.implicit)
952
+ .map((t) => t.predicate),
953
+ ]);
954
+ }
955
+ /**
956
+ * Returns a set of all the properties used by other nodes where this node is the VALUE of that property
957
+ * For example if this node is Jenny and the following is true: Mike foaf:hasFriend Jenny, calling this method on Jenny will return hasFriend
958
+ */
959
+ getInverseProperties() {
960
+ return this.asObject
961
+ ? new NodeSet_js_1.NodeSet(this.asObject.keys())
962
+ : new NodeSet_js_1.NodeSet();
963
+ }
964
+ /**
965
+ * If this node has values for the given property, the first value is returned
966
+ * NOTE: the order of multiple values CANNOT be guaranteed. Therefore use this value if it DOESN'T matter to you which of multiple possible values for this property you'll get OR if you're certain there will be only 1 value.
967
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
968
+ */
969
+ getOne(property) {
970
+ return this.properties.has(property)
971
+ ? this.properties.get(property).first()
972
+ : undefined;
973
+ }
974
+ /**
975
+ * If this node has EXPLICIT values for the given property, the first value is returned
976
+ * Same as `getOne()` except only explicit quads / facts are considered
977
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
978
+ */
979
+ getOneExplicit(property) {
980
+ for (let quad of this.getQuads(property)) {
981
+ if (!quad.implicit) {
982
+ return quad.object;
983
+ }
984
+ }
985
+ }
986
+ /**
987
+ * Returns all values this node has for the given property
988
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
989
+ */
990
+ getAll(property) {
991
+ //we usually just index all the existing properties
992
+ //but to have consistent behaviour with PropertyValueSets, when you request a property that has no values
993
+ //we need to create an index for the empty result set
994
+ if (!this.properties.has(property)) {
995
+ this.asSubject.set(property, new QuadMap_js_1.QuadMap());
996
+ this.properties.set(property, new NodeValuesSet_js_1.NodeValuesSet(this, property));
997
+ }
998
+ return this.properties.get(property);
999
+ // return this.properties.has(property)
1000
+ // ? this.properties.get(property)
1001
+ // : new PropertyValueSet(this,property);
1002
+ }
1003
+ /**
1004
+ * Returns all values this node EXPLICITLY has for the given property
1005
+ * So, same as `getAll()` except only explicit facts are considered.
1006
+ * See the documentation for more information about implicit vs explicit
1007
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1008
+ */
1009
+ getAllExplicit(property) {
1010
+ return this.getExplicitQuads(property).getObjects();
1011
+ }
1012
+ /**
1013
+ * Returns the literal value of the first Literal value for the given property
1014
+ * Only returns a results in the disired language if specified.
1015
+ * For example if `this rdfs:label "my name" then this.getValue(rdfs.label) will return "my name".
1016
+ * So, works the same as getOne() except it will return the literal (string) value of the first found Literal
1017
+ * NOTE: the order of multiple values CANNOT be guaranteed. Therefore use this value if it DOESN'T matter to you which of multiple possible values for this property you'll get OR if you're certain there will be only one value.
1018
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1019
+ */
1020
+ //NOTE: we have to overload getValue without parameters here to be compatible with Literal
1021
+ getValue(property, language) {
1022
+ //going over all property values
1023
+ for (var valueObject of this.getAll(property)) {
1024
+ //see if its a Literal
1025
+ //we do this by checking if value exists in the valueObject.
1026
+ //And we do that like this because we dont want to explicitly import Literal here.
1027
+ //@TODO: Possibly create an interface to avoid this 'hacky' workaround
1028
+ if (valueObject['value'] &&
1029
+ (!language || valueObject['isOfLanguage'](language))) {
1030
+ return valueObject.value;
1031
+ }
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Returns the literal values (strings) of all Literals this this node has a value for the given property
1036
+ * For example if `this rdfs:label "my name" and `this rdfs:label "my other name" it will return ["my name","my other name"].
1037
+ * So, works the same as getAll() except it will return an array of strings
1038
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1039
+ */
1040
+ getValues(property) {
1041
+ var valueObjects = this.getAll(property);
1042
+ var res = [];
1043
+ valueObjects.forEach((valueObject) => {
1044
+ if ('value' in valueObject) {
1045
+ res.push(valueObject['value']);
1046
+ }
1047
+ });
1048
+ return res;
1049
+ }
1050
+ /**
1051
+ * Returns any value (node, node) that is connected to this node with one or more connections of the given property.
1052
+ * For example getDeep(hasFriend) will return all the people that are my friends or friends of friends
1053
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1054
+ * @param maxDepth - the maximum number of connections that resulting nodes are removed from this node. In the example above maxDepth=2 would return only friends and friends of friends
1055
+ */
1056
+ getDeep(property, maxDepth = Infinity) {
1057
+ var result = new NodeSet_js_1.NodeSet();
1058
+ var stack = new NodeSet_js_1.NodeSet([this]);
1059
+ while (stack.size > 0 && maxDepth > 0) {
1060
+ var nextLevelStack = new NodeSet_js_1.NodeSet();
1061
+ for (let node of stack) {
1062
+ for (var value of node.getAll(property)) {
1063
+ if (!result.has(value)) {
1064
+ result.add(value);
1065
+ nextLevelStack.add(value);
1066
+ }
1067
+ }
1068
+ }
1069
+ stack = nextLevelStack;
1070
+ maxDepth--;
1071
+ }
1072
+ return result;
1073
+ }
1074
+ /**
1075
+ * Returns the first found value following the given properties in the given order.
1076
+ * For example: getOneFromPath([hasFriend,hasFather]) would return the first found father out of the set 'fathers of my friends'
1077
+ * @param properties - an array of NamedNodes. Which are nodes with rdf:type rdf:Property, the edges in the graph, the predicates of quads.
1078
+ */
1079
+ getOneFromPath(...properties) {
1080
+ //we just need one, so we do a depth-first algorithm which will be more performant, so:
1081
+ //take first property
1082
+ var property = properties.shift();
1083
+ //if more properties left
1084
+ if (properties.length > 0) {
1085
+ var res;
1086
+ //check if any of the values of that property for this node
1087
+ //has a path to the rest of the properties, and if so return the found value
1088
+ for (var value of this.getAll(property)) {
1089
+ if ((res = value.getOneFromPath(...properties))) {
1090
+ return res;
1091
+ }
1092
+ }
1093
+ }
1094
+ else {
1095
+ //return the first value possible
1096
+ return this.getOne(property);
1097
+ }
1098
+ }
1099
+ /**
1100
+ * Returns all values that can be reached by following the given properties in order.
1101
+ * For example getAllFromPath([hasFriend,hasFather]) will return all fathers of all my (direct) friends
1102
+ * @param properties - an array of NamedNodes. Which are nodes with rdf:type rdf:Property, the edges in the graph, the predicates of quads.
1103
+ */
1104
+ getAllFromPath(...properties) {
1105
+ //we just need all paths, so we can do a breadth first implementation
1106
+ //take first property
1107
+ var property = properties.shift();
1108
+ if (properties.length > 0) {
1109
+ //and ask the whole set of values to return all values of the rest of the path
1110
+ return this.getAll(property).getAllFromPath(...properties);
1111
+ }
1112
+ else {
1113
+ return this.getAll(property);
1114
+ }
1115
+ }
1116
+ /**
1117
+ * Same as getDeep() but for inverse properties.
1118
+ * Best understood with an example: if this is a person. this.getInverseDeep(hasChild) would return all this persons ancestors (which had children that eventually had this person as their child)
1119
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1120
+ * @param maxDepth - the maximum number of connections that resulting nodes are removed from this node. In the example above maxDepth=2 would return only the parents and grand parents
1121
+ */
1122
+ getInverseDeep(property, maxDepth = Infinity) {
1123
+ var result = new NodeSet_js_1.NodeSet();
1124
+ var stack = new NodeSet_js_1.NodeSet([this]);
1125
+ while (stack.size > 0 && maxDepth > 0) {
1126
+ var nextLevelStack = new NodeSet_js_1.NodeSet();
1127
+ for (let node of stack) {
1128
+ for (var value of node.getAllInverse(property)) {
1129
+ if (!result.has(value)) {
1130
+ result.add(value);
1131
+ nextLevelStack.add(value);
1132
+ }
1133
+ }
1134
+ }
1135
+ stack = nextLevelStack;
1136
+ maxDepth--;
1137
+ }
1138
+ return result;
1139
+ }
1140
+ /**
1141
+ * Returns true if the given value can be reached with one or more connections of the given property
1142
+ * Example: if this is a person. this.hasDeep(hasFriend,Mike) returns true if this person has Mike as a friend, or if any this persons friends or friends of friends have Mike as a friend.
1143
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1144
+ * @param maxDepth - the maximum number of connections that resulting nodes are removed from this node. In the example above maxDepth=2 would return true only if Mike is the persons friend, or friend of a friend
1145
+ */
1146
+ hasDeep(property, value, maxDepth = Infinity) {
1147
+ var checked = new NodeSet_js_1.NodeSet();
1148
+ var stack = new NodeSet_js_1.NodeSet([this]);
1149
+ while (stack.size > 0 && maxDepth > 0) {
1150
+ var nextLevelStack = new NodeSet_js_1.NodeSet();
1151
+ for (let node of stack) {
1152
+ for (var propertyValue of node.getAll(property)) {
1153
+ if (propertyValue === value) {
1154
+ return true;
1155
+ }
1156
+ if (!checked.has(propertyValue)) {
1157
+ checked.add(propertyValue);
1158
+ nextLevelStack.add(propertyValue);
1159
+ }
1160
+ }
1161
+ }
1162
+ stack = nextLevelStack;
1163
+ maxDepth--;
1164
+ }
1165
+ return false;
1166
+ }
1167
+ /**
1168
+ * Returns the first node that has this node as the valu eof the given property.
1169
+ * Same as getOne() but for 'inverse properties'. Meaning nodes that have this node as their value.
1170
+ * Example: if this is a person. this.getOneInverse(hasChild) returns one of the persons parents
1171
+ * NOTE: the order of multiple (inverse) values CANNOT be guaranteed. Therefore use this value if it DOESN'T matter to you which of multiple possible inverse values for this property you'll get OR if you're certain there will be only one value.
1172
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1173
+ */
1174
+ getOneInverse(property) {
1175
+ if (!this.asObject)
1176
+ return undefined;
1177
+ var quads = this.asObject.get(property);
1178
+ return quads ? quads.keys().next().value : undefined;
1179
+ }
1180
+ /**
1181
+ * Returns all the nodes that have this node as the value of the given property.
1182
+ * Same as getAll() but for 'inverse properties'. Meaning nodes that have this node as their value.
1183
+ * Example: if this is a person. this.getAllInverse(hasChild) returns all the persons parents
1184
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1185
+ */
1186
+ getAllInverse(property) {
1187
+ if (!this.asObject || !this.asObject.has(property))
1188
+ return new NodeSet_js_1.NodeSet();
1189
+ return this.asObject.get(property).getSubjects();
1190
+ }
1191
+ /**
1192
+ * Returns all the nodes that have this node as the EXPLICIT value of the given property.
1193
+ * Same as getAll() but only considers explicit facts (excluding implicit facts generated by the reasoner)
1194
+ * Example: if this is a person. this.getAllInverse(hasChild) returns all the persons parents, as long as the fact that these are this persons parents is explicitly stated
1195
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1196
+ */
1197
+ getAllInverseExplicit(property) {
1198
+ return this.getExplicitInverseQuads(property).getSubjects();
1199
+ }
1200
+ /**
1201
+ * Get all the values of multiple properties at once
1202
+ * Same as getAll() but for multiple properties at once
1203
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1204
+ */
1205
+ getMultiple(properties) {
1206
+ var res = new NodeSet_js_1.NodeSet();
1207
+ for (var property of properties) {
1208
+ res = res.concat(this.getAll(property));
1209
+ }
1210
+ return res;
1211
+ }
1212
+ /**
1213
+ * Get all the nodes that have this node as their value for any of the given properties
1214
+ * Same as getMultiple() but for the opposite direction
1215
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1216
+ */
1217
+ getMultipleInverse(properties) {
1218
+ var res = new NodeSet_js_1.NodeSet();
1219
+ for (var property of properties) {
1220
+ res = res.concat(this.getAllInverse(property));
1221
+ }
1222
+ return res;
1223
+ }
1224
+ /**
1225
+ * Get the quad that represent the connection from this node to the given value, connected by the given property
1226
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1227
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1228
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1229
+ * @param value - the node that this new graph-edge points to. The object of the quad to be created.
1230
+ */
1231
+ getQuads(property, value) {
1232
+ if (!this.asSubject.has(property))
1233
+ return new QuadSet_js_1.QuadSet();
1234
+ if (value) {
1235
+ return this.getQuadsByValue(property, value);
1236
+ }
1237
+ else {
1238
+ return this.asSubject.get(property).getQuadSet();
1239
+ }
1240
+ }
1241
+ /**
1242
+ * Get all the quads that represent EXPLICIT connections from this node to another node, connected by the given property
1243
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1244
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1245
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1246
+ */
1247
+ getExplicitQuads(property) {
1248
+ return this.getQuads(property).filter((quad) => !quad.implicit);
1249
+ }
1250
+ /**
1251
+ * Get all the quads that represent EXPLICIT connections from another node that has this node as its value for the given property
1252
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1253
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1254
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1255
+ */
1256
+ getExplicitInverseQuads(property) {
1257
+ return this.getInverseQuads(property).filter((quad) => !quad.implicit);
1258
+ }
1259
+ /**
1260
+ * Get all quads that represent connections from another node that has this node as its value for the given property
1261
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1262
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1263
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1264
+ */
1265
+ getInverseQuads(property) {
1266
+ if (!this.asObject.has(property))
1267
+ return undefined;
1268
+ return this.asObject.get(property).getQuadSet();
1269
+ // return this.asObject && this.asObject.has(property)
1270
+ // ? this.asObject.get(property)
1271
+ // : new QuadMap();
1272
+ }
1273
+ /**
1274
+ * Get all (by default explicit) quads that represent connections from another node that has this node as its value for ANY property
1275
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1276
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1277
+ * @param includeImplicit if true, includes both implicit and explicit quads. By default false, so will only return explicit quads
1278
+ */
1279
+ getAllInverseQuads(includeImplicit = false) {
1280
+ var res = new QuadArray_js_1.QuadArray();
1281
+ if (this.asObject) {
1282
+ this.asObject.forEach((quadSet) => {
1283
+ quadSet.forEach((quad) => {
1284
+ if (!includeImplicit && quad.implicit)
1285
+ return;
1286
+ res.push(quad);
1287
+ });
1288
+ });
1289
+ }
1290
+ return res;
1291
+ }
1292
+ /**
1293
+ * Get all (by default explicit) quads that represent connections for all values of this node (so quads where this node is the subject)
1294
+ * NOTE: accessing quads is a very low level functionality required for the framework itself
1295
+ * and SHOULD GENERALLY NOT BE USED. Use methods to get/set properties instead
1296
+ * @param includeAsObject if true, includes quads from both directions (so also inverse properties where this node is the object of the quad)
1297
+ * @param includeImplicit if true, includes both implicit and explicit quads. By default false, so will only return explicit quads
1298
+ */
1299
+ getAllQuads(includeAsObject = false, includeImplicit = false) {
1300
+ var res = new QuadArray_js_1.QuadArray();
1301
+ this.asSubject.forEach((quadMap) => {
1302
+ quadMap.forEach((quad) => {
1303
+ if (!includeImplicit && quad.implicit)
1304
+ return;
1305
+ res.push(quad);
1306
+ });
1307
+ });
1308
+ if (includeAsObject && this.asObject) {
1309
+ this.asObject.forEach((quadMap) => {
1310
+ quadMap.forEach((quad) => {
1311
+ //we manually filter duplicates from the result set here so that we can keep using QuadArray, which is much faster in ES5
1312
+ //and the only duplicates will be a node with itself as subject AND object, so we filter the second occurrence here
1313
+ if (!includeImplicit && quad.implicit)
1314
+ return;
1315
+ if (quad.subject === this)
1316
+ return;
1317
+ res.push(quad);
1318
+ });
1319
+ });
1320
+ }
1321
+ return res;
1322
+ }
1323
+ /**
1324
+ * #######################################################################
1325
+ * ######################## EVENT METHODS / LISTENERS ####################
1326
+ * #######################################################################
1327
+ **/
1328
+ /**
1329
+ * Update a certain property so that only the given value is a value of this property.
1330
+ * Overwrites (and thus removes) any previously set values
1331
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1332
+ * @param value - a single node. Can be a NamedNode or Literal
1333
+ */
1334
+ overwrite(property, value) {
1335
+ //don't do anything if the current value is already equivalent to the new value
1336
+ if (this.getAll(property).size == 1 && value && this.has(property, value))
1337
+ return false;
1338
+ //clear all values and set new value
1339
+ this.unsetAll(property);
1340
+ if (value) {
1341
+ return this.set(property, value);
1342
+ }
1343
+ }
1344
+ /**
1345
+ * Update a certain property so that only the given values are the values of this property.
1346
+ * Overwrites (and thus removes) any previously set values
1347
+ * Same as overwrite() except this allows you to replace the previous values with MULTIPLE new values
1348
+ * @param property
1349
+ * @param values
1350
+ */
1351
+ moverwrite(property, values) {
1352
+ //don't update if the new set of values is the same (or equivalent) as the old set of values
1353
+ if (this.getAll(property).size === (values.size || values.length) &&
1354
+ values.every((value) => this.has(property, value))) {
1355
+ return false;
1356
+ }
1357
+ this.unsetAll(property);
1358
+ return this.mset(property, values);
1359
+ }
1360
+ /**
1361
+ * Removes this node from the graph, locally and remotely, in all connected QuadStores.
1362
+ * All properties will be unset, both where this node is the subject or the object.
1363
+ * Emits an event from the node itself and from the NamedNode class
1364
+ */
1365
+ remove() {
1366
+ //collect all the quads that are about to be removed
1367
+ let removedQuads = this.getAllQuads(true);
1368
+ //remove all quads locally
1369
+ this.asSubject.forEach((quads) => quads.removeAll(true));
1370
+ if (this.asObject)
1371
+ this.asObject.forEach((quads) => quads.removeAll(true));
1372
+ //emit event from this node itself, with all the quads that were removed
1373
+ this.emit(NamedNode.NODE_REMOVED, this, removedQuads);
1374
+ //clean up anything connected to this node
1375
+ this.removeAllListeners();
1376
+ //remove form list
1377
+ NamedNode.unregister(this);
1378
+ //make sure a global event is emitted that nodes are moved (picked up by storage)
1379
+ EventBatcher_js_1.eventBatcher.register(NamedNode);
1380
+ NamedNode.nodesToRemove.add([this, removedQuads]);
1381
+ }
1382
+ /**
1383
+ * UNSET (remove) a single property value connection.
1384
+ * Remove a single connection between two nodes in the graph: from this node, to the node given as value, with the property as the connecting 'edge' between them
1385
+ * In the graph, this will remove the edge between two nodes.
1386
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1387
+ * @param value - the node that this new graph-edge points to. The object of the quad to be created.
1388
+ */
1389
+ unset(property, value) {
1390
+ if (this.has(property, value)) {
1391
+ this.getQuads(property, value).removeAll(true);
1392
+ return true;
1393
+ }
1394
+ return false;
1395
+ }
1396
+ /**
1397
+ * unset (remove) all values of a certain property.
1398
+ * Removes all connections (edges) in the graph between this node and other nodes, where the given property is used as the connecting 'edge' between them
1399
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1400
+ */
1401
+ unsetAll(property) {
1402
+ NamedNode.emitClearedProperty(this, property);
1403
+ if (this.hasProperty(property)) {
1404
+ //false as parameter because we don't need alteration events for each single quad, but rather manage this with clearedProperties events
1405
+ this.asSubject.get(property).removeAll(false);
1406
+ return true;
1407
+ }
1408
+ return false;
1409
+ }
1410
+ /**
1411
+ * returns true if ANY node has this node as the value of the given property
1412
+ * Example: if 'this' is a person, this.hasInverseProperty(hasChild) returns true if any facts stating `someParent hasChild thisPerson` are known
1413
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1414
+ */
1415
+ hasInverseProperty(property) {
1416
+ return this.asObject && this.asObject.has(property);
1417
+ }
1418
+ /**
1419
+ * returns true if the given inverse 'value' has this node as the (real) value of the given property
1420
+ * Example: if 'this' is a person, this.hasInverseProperty(hasChild,someParent) returns true if someParent indeed has this person as a child
1421
+ * @param property - a NamedNode with rdf:type rdf:Property, the edge in the graph, the predicate of a quad
1422
+ * @param value - a single node. Can be a NamedNode or Literal
1423
+ */
1424
+ hasInverse(property, value) {
1425
+ var _a;
1426
+ return (this.asObject &&
1427
+ ((_a = this.asObject.get(property)) === null || _a === void 0 ? void 0 : _a.some((quad) => quad.subject.equals(value))));
1428
+ }
1429
+ /**
1430
+ * returns true if this node is equivaluent to the given node.
1431
+ * For NamedNodes it simply returns true if this === the given object. So if its the same object in memory.
1432
+ * It exists mainly for comparing Literals, where two different objects can still be equivalent
1433
+ * @param other another node
1434
+ */
1435
+ equals(other) {
1436
+ return other === this;
1437
+ }
1438
+ /**
1439
+ * Save this node into the graph database.
1440
+ * Newly created nodes will exist only in local memory until you call this function
1441
+ * @returns a promise that resolves when the node has received a permanent URI
1442
+ */
1443
+ save() {
1444
+ if (this.isTemporaryNode) {
1445
+ if (!this._isStoring) {
1446
+ //this creates a promise that will resolve when the node is stored
1447
+ this.isStoring = true;
1448
+ NamedNode.nodesToSave.add(this);
1449
+ EventBatcher_js_1.eventBatcher.register(NamedNode);
1450
+ }
1451
+ //always return a promise
1452
+ return this._isStoring.promise;
1453
+ }
1454
+ }
1455
+ /**
1456
+ * Create a new URI Node with the same properties as the current node
1457
+ * NOTE: does NOT clone the inverse properties (where this node is the value of another node its properties)
1458
+ */
1459
+ clone() {
1460
+ var node = NamedNode.create();
1461
+ this.getAllQuads().forEach((quad) => {
1462
+ node.set(quad.predicate, quad.object);
1463
+ });
1464
+ return node;
1465
+ }
1466
+ /**
1467
+ * Returns a string representation of this node.
1468
+ * Returns the URI for a NamedNode
1469
+ */
1470
+ toString() {
1471
+ return this.uri;
1472
+ }
1473
+ print(includeIncomingProperties = true) {
1474
+ var print = '';
1475
+ this.getAsSubjectQuads().forEach((quadMap) => {
1476
+ BlankNode.includeBlankNodes(quadMap.getQuadSet()).forEach((quad) => (print += '\t' + quad.print() + '.\n'));
1477
+ });
1478
+ if (this.asObject && includeIncomingProperties) {
1479
+ print += '<----\n';
1480
+ this.asObject.forEach((quadMap) => {
1481
+ BlankNode.includeBlankNodes(quadMap.getQuadSet(), false, true).forEach((quad) => (print += '\t' + quad.print() + '.\n'));
1482
+ });
1483
+ }
1484
+ return print;
1485
+ }
1486
+ /**
1487
+ * Fires the given call back when ANY property of this node changes.
1488
+ * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters
1489
+ * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context
1490
+ */
1491
+ onChangeAny(callback, context) {
1492
+ this.on(NamedNode.PROPERTY_CHANGED, callback, context);
1493
+ }
1494
+ /**
1495
+ * Fires the given call back when this node become the value or is no longer the value of another node
1496
+ * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters
1497
+ * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context
1498
+ */
1499
+ onChangeAnyInverse(callback, context) {
1500
+ this.on(NamedNode.INVERSE_PROPERTY_CHANGED, callback, context);
1501
+ }
1502
+ /**
1503
+ * Fires the given call back when this node changes the values of the given property
1504
+ * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters
1505
+ * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context
1506
+ */
1507
+ onChange(property, callback, context) {
1508
+ this.on(NamedNode.PROPERTY_CHANGED + property.uri, callback, context);
1509
+ }
1510
+ /**
1511
+ * Fires the given callback when this node become the value or is no longer the value of the given property of another node
1512
+ * Example: if someGroup hasParticipant thisResource, and the group removes this node from its participants, it will trigger onChangeInverse for this node
1513
+ * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters
1514
+ * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context
1515
+ */
1516
+ onChangeInverse(property, callback, context) {
1517
+ this.on(NamedNode.INVERSE_PROPERTY_CHANGED + property.uri, callback, context);
1518
+ }
1519
+ /**
1520
+ * Call this when you want to stop listening for onChangeAny events. Make sure to provide the exact same BOUND instance of a method to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener.
1521
+ * @param callback the exact same method you supplied to onChangeAny
1522
+ * @param context the same context you supplied to onChangeAny
1523
+ */
1524
+ removeOnChangeAny(callback, context) {
1525
+ this.off(NamedNode.PROPERTY_CHANGED, callback, context);
1526
+ }
1527
+ /**
1528
+ * Call this when you want to stop listening for onChangeAnyInverse events. Make sure to provide the exact same BOUND instance of a method to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener.
1529
+ * @param callback the exact same method you supplied to onChangeAnyInverse
1530
+ * @param context the same context you supplied to onChangeAnyInverse
1531
+ */
1532
+ removeOnChangeAnyInverse(callback, context) {
1533
+ this.off(NamedNode.INVERSE_PROPERTY_CHANGED, callback, context);
1534
+ }
1535
+ /**
1536
+ * Call this when you want to stop listening for onChange events. Make sure to provide the exact same BOUND instance of a method as callback to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener.
1537
+ * @param callback the exact same method you supplied to onChange
1538
+ * @param context the same context you supplied to onChange
1539
+ */
1540
+ removeOnChange(property, callback, context) {
1541
+ this.off(NamedNode.PROPERTY_CHANGED + property.uri, callback, context);
1542
+ }
1543
+ /* #######################################################################
1544
+ * ######################### STATIC METHODS ##############################
1545
+ * #######################################################################
1546
+ */
1547
+ /**
1548
+ * Call this when you want to stop listening for onChangeInverse events. Make sure to provide the exact same BOUND instance of a method as callback to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener.
1549
+ * @param callback the exact same method you supplied to onChangeInverse
1550
+ * @param context the same context you supplied to onChangeInverse
1551
+ */
1552
+ removeOnChangeInverse(property, callback, context) {
1553
+ this.off(NamedNode.INVERSE_PROPERTY_CHANGED + property.uri, callback, context);
1554
+ }
1555
+ /**
1556
+ * Call this when you want to stop listening for onChangeAny events. Other then removeOnChangeAny you only have to supply the context.
1557
+ * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeAny
1558
+ * @param context the same context you supplied to onChangeAny
1559
+ */
1560
+ clearOnChangeAny(context) {
1561
+ this.removeListenerByContext(NamedNode.PROPERTY_CHANGED, context);
1562
+ }
1563
+ /**
1564
+ * Call this when you want to stop listening for onChangeAnyInverse events. Other then removeOnChangeAnyInverse you only have to supply the context.
1565
+ * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeAnyInverse
1566
+ * @param context the same context you supplied to onChangeAnyInverse
1567
+ */
1568
+ clearOnChangeAnyInverse(context) {
1569
+ this.removeListenerByContext(NamedNode.INVERSE_PROPERTY_CHANGED, context);
1570
+ }
1571
+ /**
1572
+ * Call this when you want to stop listening for onChange events. Other then removeOnChange you only have to supply the context.
1573
+ * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChange
1574
+ * @param context the same context you supplied to onChange
1575
+ */
1576
+ clearOnChange(property, context) {
1577
+ this.removeListenerByContext(NamedNode.PROPERTY_CHANGED + property.uri, context);
1578
+ }
1579
+ /**
1580
+ * Call this when you want to stop listening for onChangeInverse events. Other then removeOnChangeInverse you only have to supply the context.
1581
+ * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeInverse
1582
+ * @param context the same context you supplied to onChangeAny
1583
+ */
1584
+ clearOnChangeInverse(property, context) {
1585
+ this.removeListenerByContext(NamedNode.INVERSE_PROPERTY_CHANGED + property.uri, context);
1586
+ }
1587
+ /**
1588
+ * Call this when you want to stop listening for onPredicateChange events
1589
+ * @param context the same context you supplied to onPredicateChange
1590
+ */
1591
+ clearOnPredicateChange(context) {
1592
+ this.removeListenerByContext(NamedNode.AS_PREDICATE_CHANGED, context);
1593
+ }
1594
+ /**
1595
+ * Emits the batched (property) events of a NamedNode INSTANCE (meaning for this specific node)
1596
+ * Used internally by the framework to manage emitting change events
1597
+ * @internal
1598
+ */
1599
+ emitBatchedEvents() {
1600
+ //for each type of property change (and the map of batched changes for that type of change)
1601
+ [
1602
+ [this.changedProperties, NamedNode.PROPERTY_CHANGED],
1603
+ [this.changedInverseProperties, NamedNode.INVERSE_PROPERTY_CHANGED],
1604
+ [this.alteredProperties, NamedNode.PROPERTY_ALTERED],
1605
+ [this.alteredInverseProperties, NamedNode.INVERSE_PROPERTY_ALTERED],
1606
+ ].forEach(([map, event]) => {
1607
+ if (!map)
1608
+ return;
1609
+ //for each individual change that was made
1610
+ map.forEach((quads, property) => {
1611
+ //emit the specific event that THIS property has changed
1612
+ this.emit(event + property.uri, quads, property);
1613
+ });
1614
+ if (map.size > 0) {
1615
+ //emit the general event that A property has changed/altered
1616
+ this.emit(event, map);
1617
+ }
1618
+ map.clear();
1619
+ });
1620
+ // if (this.changedAsPredicate) {
1621
+ // this.emit(NamedNode.AS_PREDICATE_CHANGED, this.changedAsPredicate, this);
1622
+ // this.changedAsPredicate = null;
1623
+ // }
1624
+ // if (this.alteredAsPredicate) {
1625
+ // this.emit(NamedNode.AS_PREDICATE_ALTERED, this.alteredAsPredicate, this);
1626
+ // this.alteredAsPredicate = null;
1627
+ // }
1628
+ }
1629
+ getAsSubjectQuads() {
1630
+ return this.asSubject;
1631
+ }
1632
+ getAsObjectQuads() {
1633
+ return this.asObject;
1634
+ }
1635
+ // getAsPredicateQuads() {
1636
+ // return this.asPredicate;
1637
+ // }
1638
+ createPromise() {
1639
+ var resolve, reject;
1640
+ var promise = new Promise((res, rej) => {
1641
+ resolve = res;
1642
+ reject = rej;
1643
+ });
1644
+ return { promise, resolve, reject };
1645
+ }
1646
+ /**
1647
+ * Adds the quad to all given maps
1648
+ * @param quad
1649
+ * @param maps
1650
+ * @private
1651
+ */
1652
+ registerPropertyChange(quad, maps) {
1653
+ //register that this class has some events to emit
1654
+ EventBatcher_js_1.eventBatcher.register(this);
1655
+ //for each given map
1656
+ maps.forEach((map) => {
1657
+ //add this quad under the predicate as key
1658
+ if (!map.has(quad.predicate)) {
1659
+ map.set(quad.predicate, new QuadSet_js_1.QuadSet());
1660
+ }
1661
+ map.get(quad.predicate).add(quad);
1662
+ });
1663
+ }
1664
+ // private registerPredicateChange(quad: Quad, alteration: boolean) {
1665
+ // eventBatcher.register(this);
1666
+ // if (!this.changedAsPredicate) {
1667
+ // this.changedAsPredicate = new QuadArray();
1668
+ // }
1669
+ // this.changedAsPredicate.push(quad);
1670
+ // if (alteration) {
1671
+ // if (!this.alteredAsPredicate) {
1672
+ // this.alteredAsPredicate = new QuadArray();
1673
+ // }
1674
+ // this.alteredAsPredicate.push(quad);
1675
+ // }
1676
+ // }
1677
+ getQuadsByValue(property, value) {
1678
+ return value instanceof NamedNode
1679
+ ? this.asSubject.get(property).has(value)
1680
+ ? this.asSubject.get(property).get(value)
1681
+ : new QuadSet_js_1.QuadSet()
1682
+ : this.asSubject
1683
+ .get(property)
1684
+ .filter((quad) => quad.object.equals(value), QuadSet_js_1.QuadSet);
1685
+ }
1686
+ }
1687
+ exports.NamedNode = NamedNode;
1688
+ /**
1689
+ * The base of temporary URI's
1690
+ * @internal
1691
+ */
1692
+ NamedNode.TEMP_URI_BASE = 'lin://tmp/';
1693
+ /**
1694
+ * Emitter used by the class itself by static methods emitting events.
1695
+ * Anyone wanting to listen to that should therefore add a listener with NamedNode.emitter.on(...)
1696
+ * @internal
1697
+ */
1698
+ NamedNode.emitter = new EventEmitter_js_1.EventEmitter();
1699
+ /**
1700
+ * event emitted when nodes need to be stored
1701
+ * @internal
1702
+ */
1703
+ NamedNode.STORE_NODES = 'STORE_NODES';
1704
+ /**
1705
+ * Event emitted when previous values have been overwritten (for example with update or moverwrite)
1706
+ * NOTE: Locally we may not know all the properties, but the intend of update / moverwrite is to overwrite ANY existing properties. So event handlers listening to this event should clear any previous property values they can find.
1707
+ * @internal
1708
+ */
1709
+ NamedNode.CLEARED_PROPERTIES = 'CLEARED_PROPERTIES';
1710
+ /**
1711
+ * event emitted when nodes need to be removed
1712
+ * @internal
1713
+ */
1714
+ NamedNode.REMOVE_NODES = 'REMOVE_NODES';
1715
+ /**
1716
+ * event emitted when the URI of a node has been updated
1717
+ */
1718
+ NamedNode.URI_UPDATED = 'URI_UPDATED';
1719
+ /**
1720
+ * event emitted when nodes need to be loaded
1721
+ * @internal
1722
+ */
1723
+ NamedNode.LOAD_NODES = 'LOAD_NODES';
1724
+ /**
1725
+ * event emitted by a single node when its properties have changed
1726
+ * @internal
1727
+ */
1728
+ NamedNode.PROPERTY_CHANGED = 'PROPERTY_CHANGED';
1729
+ /**
1730
+ * event emitted by a single node when its properties have been altered
1731
+ * NOTE: we use 'altered' for changes made by user interaction vs 'changed' for changes that
1732
+ * could for example be due to new data being loaded
1733
+ * @internal
1734
+ */
1735
+ NamedNode.PROPERTY_ALTERED = 'PROPERTY_ALTERED';
1736
+ /**
1737
+ * event emitted by a single node when its inverse properties have been changed
1738
+ * @internal
1739
+ */
1740
+ NamedNode.INVERSE_PROPERTY_CHANGED = 'INVERSE_PROPERTY_CHANGED';
1741
+ //### event types ###
1742
+ /**
1743
+ * event emitted by a single node when its inverse properties have been altered
1744
+ * NOTE: we use 'altered' for changes made by user interaction vs 'changed' for changes that
1745
+ * could for example be due to new data being loaded
1746
+ * @internal
1747
+ */
1748
+ NamedNode.INVERSE_PROPERTY_ALTERED = 'INVERSE_PROPERTY_ALTERED';
1749
+ /**
1750
+ * event emitted by a single node when its used or not used anymore as a predicate
1751
+ * @internal
1752
+ */
1753
+ NamedNode.AS_PREDICATE_CHANGED = 'AS_PREDICATE_CHANGED';
1754
+ /**
1755
+ * event emitted by a single node when its used or not used anymore as a predicate due to user requested alterations
1756
+ * @internal
1757
+ */
1758
+ NamedNode.AS_PREDICATE_ALTERED = 'AS_PREDICATE_ALTERED';
1759
+ /**
1760
+ * event emitted by a single node when it's been removed
1761
+ */
1762
+ NamedNode.NODE_REMOVED = 'NODE_REMOVED';
1763
+ NamedNode.namedNodes = new NodeMap_js_1.NodeMap();
1764
+ NamedNode.tempCounter = 0;
1765
+ NamedNode.nodesToSave = new NodeSet_js_1.NodeSet();
1766
+ NamedNode.nodesToLoad = new NodeSet_js_1.NodeSet();
1767
+ NamedNode.nodesToLoadFully = new NodeSet_js_1.NodeSet();
1768
+ NamedNode.nodesToRemove = new CoreSet_1.CoreSet();
1769
+ NamedNode.nodesURIUpdated = new CoreMap_1.CoreMap();
1770
+ NamedNode.clearedProperties = new CoreMap_1.CoreMap();
1771
+ //cannot import from xsd ontology here without creating circular dependencies
1772
+ var rdfLangString = NamedNode.getOrCreate('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString');
1773
+ var xsdString = NamedNode.getOrCreate('http://www.w3.org/2001/XMLSchema#string');
1774
+ class BlankNode extends NamedNode {
1775
+ constructor(uri, isTemporaryNode = false) {
1776
+ super(uri || BlankNode.createUri(), isTemporaryNode);
1777
+ this.termType = 'BlankNode';
1778
+ NamedNode.register(this);
1779
+ }
1780
+ get uri() {
1781
+ return this._value;
1782
+ }
1783
+ set uri(uri) {
1784
+ throw new Error('You should not set the URI of a BlankNode. Make sure the node is created as a NamedNode. BlankNode data:\n' +
1785
+ BlankNode.includeBlankNodes(this.getAllQuads()).toString());
1786
+ }
1787
+ static create(isTemporaryNode = false) {
1788
+ return new BlankNode(null, isTemporaryNode);
1789
+ }
1790
+ static createUri() {
1791
+ return '_:' + this.counter++;
1792
+ }
1793
+ static includeBlankNodes(quads, includeObjectBlankNodes = true, includeSubjectBlankNodes = false, blankNodes = new NodeURIMappings_js_1.NodeURIMappings()) {
1794
+ let add = quads instanceof Set ? quads.add.bind(quads) : quads.push.bind(quads);
1795
+ quads.forEach((quad) => {
1796
+ if (includeObjectBlankNodes && quad.object instanceof BlankNode) {
1797
+ this.addBlankNodeQuads(quad.object, add, blankNodes);
1798
+ }
1799
+ if (includeSubjectBlankNodes && quad.subject instanceof BlankNode) {
1800
+ //also add quads of subjects that are blank nodes, iteratively, but don't include the blank node objects of those quads
1801
+ this.addBlankNodeQuads(quad.subject, add, blankNodes, true);
1802
+ }
1803
+ });
1804
+ return quads;
1805
+ }
1806
+ static addBlankNodeQuads(blankNode, add, blankNodes, inverseIteration = false) {
1807
+ // console.log('adding quads of ' + blankNode.uri);
1808
+ blankNodes.set(blankNode.uri, blankNode);
1809
+ blankNode.getAllQuads().forEach((quad) => {
1810
+ if (!(quad instanceof Quad)) {
1811
+ throw new Error('Not a quad');
1812
+ }
1813
+ add(quad);
1814
+ //also, iteratively include quads of blank-node values of blank-nodes
1815
+ if (!inverseIteration && quad.object instanceof BlankNode) {
1816
+ //if we've not seen this blank node yet during this collection (avoiding loops from circular references between blank nodes)
1817
+ if (!blankNodes.has(quad.object.uri)) {
1818
+ this.addBlankNodeQuads(quad.object, add, blankNodes);
1819
+ }
1820
+ }
1821
+ if (inverseIteration && quad.subject instanceof BlankNode) {
1822
+ //if we've not seen this blank node yet during this collection (avoiding loops from circular references between blank nodes)
1823
+ if (!blankNodes.has(quad.subject.uri)) {
1824
+ this.addBlankNodeQuads(quad.subject, add, blankNodes, true);
1825
+ }
1826
+ }
1827
+ });
1828
+ }
1829
+ }
1830
+ exports.BlankNode = BlankNode;
1831
+ BlankNode.counter = 0;
1832
+ /**
1833
+ * One of the two main classes of nodes (nodes) in the graph.
1834
+ * Literals are endpoints. They do NOT have outgoing connections (edges) to other nodes in the graph.
1835
+ * Though a NamedNode can point to a Literal.
1836
+ * Each literal node has a literal value, like a string.
1837
+ * Besides that is can also have a language tag or a data type.
1838
+ * Literals are often saved as a single string, for example '"yes"@en' (yes in english) or '"true"^^xsd:boolean (the value true with datatype english)
1839
+ * This class represents those properties.
1840
+ * See also: https://www.w3.org/TR/rdf-concepts/#section-Graph-Literal
1841
+ */
1842
+ class Literal extends Node {
1843
+ /**
1844
+ * Other than with NamedNodes, its fine to do `new Literal("my string value")`
1845
+ * Datatype and language tags are optional
1846
+ * @param value
1847
+ * @param datatype
1848
+ * @param language
1849
+ */
1850
+ constructor(value, _datatype = null, _language = '') {
1851
+ super(value);
1852
+ this._datatype = _datatype;
1853
+ this._language = _language;
1854
+ this.termType = 'Literal';
1855
+ if (typeof value !== 'string') {
1856
+ throw new Error('Literal value must be a string. Given value was a ' +
1857
+ typeof value +
1858
+ ' (' +
1859
+ value +
1860
+ ')');
1861
+ }
1862
+ }
1863
+ /**
1864
+ * get the language tag of this literal which states which language this literal is written in
1865
+ * See also: http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
1866
+ */
1867
+ get language() {
1868
+ //list of language tags: http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
1869
+ return this._language;
1870
+ }
1871
+ /**
1872
+ * update the language tag of this literal
1873
+ */
1874
+ set language(lang) {
1875
+ this._language = lang;
1876
+ //the datatype of any literal with a language tag is rdf:langString
1877
+ this._datatype = rdfLangString;
1878
+ }
1879
+ /**
1880
+ * returns the datatype of this literal
1881
+ * Note that datatypes are NamedNodes themselves, who always have rdf:type rdf:Datatype
1882
+ * If no datatype is set, the default datatype xsd:string will be returned
1883
+ * If a language tag is set, the returned datatype will be rdf:langString
1884
+ */
1885
+ get datatype() {
1886
+ if (this._datatype) {
1887
+ return this._datatype;
1888
+ }
1889
+ //default datatype is xsd:string, if language is set this.datatype should be langString already
1890
+ return xsdString;
1891
+ }
1892
+ /**
1893
+ * Update the datatype of this literal
1894
+ * @param datatype
1895
+ */
1896
+ set datatype(datatype) {
1897
+ this._datatype = datatype;
1898
+ }
1899
+ /**
1900
+ * Return the value of this literal
1901
+ * @param datatype
1902
+ */
1903
+ get value() {
1904
+ return this._value;
1905
+ }
1906
+ /**
1907
+ * update the literal value of this literal
1908
+ * @param datatype
1909
+ */
1910
+ set value(value) {
1911
+ let previousValue;
1912
+ //if this literal is being used in a quad
1913
+ if (this.referenceQuad) {
1914
+ //remember the previous value for the events below
1915
+ previousValue = this.clone();
1916
+ }
1917
+ //update the value
1918
+ this._value = value;
1919
+ if (this.referenceQuad) {
1920
+ //register change for subject node (for node.onChange(prop) listeners)
1921
+ this.referenceQuad.subject.registerValueChange(this.referenceQuad, true);
1922
+ //notify the graph of a change (will mimic a removed and added quad)
1923
+ // this.referenceQuad.graph.registerQuadValueChange(previousValue,this.referenceQuad);
1924
+ //notify the quad that the value of it's object has changed (will mimic a removed and added quad)
1925
+ this.referenceQuad.onValueChanged(previousValue);
1926
+ }
1927
+ }
1928
+ /**
1929
+ * Returns the literal value of the first Literal that occurs as object for the given subject and property and optionally also matches the given language
1930
+ * @param subject
1931
+ * @param property
1932
+ * @param language
1933
+ * @deprecated
1934
+ * @returns {string|undefined}
1935
+ */
1936
+ static getValue(subject, property, language = '') {
1937
+ for (var value of subject.getAll(property)) {
1938
+ if (value instanceof Literal &&
1939
+ (!language || value.isOfLanguage(language))) {
1940
+ return value.value;
1941
+ }
1942
+ }
1943
+ return undefined;
1944
+ }
1945
+ /**
1946
+ * Returns all literal values of the Literals that occur as object for the given subject and property and optionally also match the given language
1947
+ * @param subject
1948
+ * @param property
1949
+ * @param language
1950
+ * @returns {string[]}
1951
+ */
1952
+ static getValues(subject, property, language = '') {
1953
+ var res = [];
1954
+ for (var value of subject.getAll(property)) {
1955
+ if (value instanceof Literal &&
1956
+ (!language || value.isOfLanguage(language))) {
1957
+ res.push(value.value);
1958
+ }
1959
+ }
1960
+ return res;
1961
+ }
1962
+ static isLiteralString(literalString) {
1963
+ var regex = new RegExp('(\\"[^\\"^\\n]*\\")(@[a-z]{1,3}|\\^\\^[a-zA-Z]+\\:[a-zA-Z0-9_-]+|\\<https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)\\>)?');
1964
+ return regex.test(literalString);
1965
+ }
1966
+ static fromString(literalString) {
1967
+ //self made regex thatL
1968
+ // match anything between quotes or quad quotes (the quotes are group 1 and 3)
1969
+ // except escaped quotes (2)
1970
+ //and everything behind it (4) for language or datatype
1971
+ //..with a little help on the escaped quotes from here
1972
+ //https://stackoverflow.com/questions/38563414/javascript-regex-to-select-quoted-string-but-not-escape-quotes
1973
+ let match = literalString.match(/("|""")([^"\\]*(?:\\.[^"\\]*)*)("|""")(.*)/);
1974
+ //NOTE: if \n replacement turns out to be not correct here it should at least be moved to JSONLDParser, see https://github.com/digitalbazaar/jsonld.js/issues/242
1975
+ let literal = (match[2] ? match[2] : '')
1976
+ .replace(/\\"/g, '"')
1977
+ .replace(/\\n/g, '\n');
1978
+ let suffix = match[4];
1979
+ if (!suffix) {
1980
+ return new Literal(literal);
1981
+ }
1982
+ if (suffix[0] == '@') {
1983
+ return new Literal(literal, null, suffix.substr(1));
1984
+ }
1985
+ else if (suffix[0] == '^') {
1986
+ var datatype = NamedNode.fromString(suffix.substr(2));
1987
+ return new Literal(literal, datatype);
1988
+ }
1989
+ else {
1990
+ throw new Error('Invalid literal string format: ' + literalString);
1991
+ }
1992
+ }
1993
+ getAs(type) {
1994
+ return type.getOf(this);
1995
+ }
1996
+ /**
1997
+ * @internal
1998
+ * @param quad
1999
+ */
2000
+ registerProperty(quad) {
2001
+ throw new Error('Literal nodes should not be used as subjects');
2002
+ }
2003
+ /**
2004
+ * registers the use of a quad. Since a quad can only be used in 1 quad
2005
+ * this method makes a clone of the Literal if it's used a second time,
2006
+ * and returns that new Literal so it will be used by the quad
2007
+ * @internal
2008
+ * @param quad
2009
+ */
2010
+ registerInverseProperty(quad) {
2011
+ //if this Literal is already being used in another quad
2012
+ if (this.referenceQuad) {
2013
+ //then return a clone
2014
+ //(this allows things like a.set(label,b.getOne(label)))
2015
+ return this.clone().registerInverseProperty(quad);
2016
+ }
2017
+ this.referenceQuad = quad;
2018
+ return this;
2019
+ }
2020
+ /**
2021
+ * @internal
2022
+ * @param quad
2023
+ */
2024
+ unregisterProperty(quad) {
2025
+ throw new Error('Literal nodes should not be used as subjects');
2026
+ }
2027
+ /**
2028
+ * @internal
2029
+ * @param quad
2030
+ */
2031
+ unregisterInverseProperty(quad) {
2032
+ this.referenceQuad = null;
2033
+ }
2034
+ /**
2035
+ * returns true if this literal node has a language tag
2036
+ */
2037
+ hasLanguage() {
2038
+ return this._language != '';
2039
+ }
2040
+ /**
2041
+ * returns true if the language tag of this literal matches the given language
2042
+ */
2043
+ isOfLanguage(language) {
2044
+ return this._language === language;
2045
+ }
2046
+ /**
2047
+ * returns true if this literal has a datatype
2048
+ */
2049
+ hasDatatype() {
2050
+ //checks for null and undefined
2051
+ return this._datatype != null;
2052
+ }
2053
+ /**
2054
+ * Returns true if both are literal nodes, with equal literal values, equal language tags and equal data types
2055
+ * Other than NamedNodes, two different literal node instances can be deemed equivalent if all their properties are the same
2056
+ * @param other
2057
+ * @param caseSensitive
2058
+ */
2059
+ equals(other) {
2060
+ return this._equals(other);
2061
+ }
2062
+ /**
2063
+ * Returns true if both are literal nodes, with equal literal values (CASE INSENSITIVE CHECK), equal language tags and equal data types
2064
+ * Other than NamedNodes, two different literal node instances can be deemed equivalent if all their properties are the same
2065
+ * @param other
2066
+ */
2067
+ equalsCaseInsensitive(other) {
2068
+ return this._equals(other, false);
2069
+ }
2070
+ /**
2071
+ * Creates a new Literal with exact the same properties (value,datatype and language)
2072
+ */
2073
+ clone() {
2074
+ return new Literal(this._value, this.datatype, this.language);
2075
+ }
2076
+ getReferenceQuad() {
2077
+ return this.referenceQuad;
2078
+ }
2079
+ hasInverseProperty(property) {
2080
+ return this.referenceQuad && this.referenceQuad.predicate === property;
2081
+ }
2082
+ hasInverse(property, value) {
2083
+ return (this.referenceQuad &&
2084
+ this.referenceQuad.predicate === property &&
2085
+ this.referenceQuad.subject === value);
2086
+ }
2087
+ getOneInverse(property) {
2088
+ return this.referenceQuad && this.referenceQuad.predicate === property
2089
+ ? this.referenceQuad.subject
2090
+ : undefined;
2091
+ }
2092
+ getMultipleInverse(properties) {
2093
+ if (properties.find((p) => p === this.referenceQuad.predicate)) {
2094
+ return new NodeSet_js_1.NodeSet([this.referenceQuad.subject]);
2095
+ }
2096
+ return new NodeSet_js_1.NodeSet();
2097
+ }
2098
+ getAllInverseQuads(includeImplicit) {
2099
+ return !includeImplicit || !this.referenceQuad.implicit
2100
+ ? new QuadArray_js_1.QuadArray(this.referenceQuad)
2101
+ : new QuadArray_js_1.QuadArray();
2102
+ }
2103
+ getAllQuads(includeAsObject = false, includeImplicit = false) {
2104
+ return includeAsObject && (!includeImplicit || !this.referenceQuad.implicit)
2105
+ ? new QuadArray_js_1.QuadArray(this.referenceQuad)
2106
+ : new QuadArray_js_1.QuadArray();
2107
+ }
2108
+ promiseLoaded(loadInverseProperties = false) {
2109
+ return Promise.resolve(true);
2110
+ }
2111
+ isLoaded(includingInverseProperties = false) {
2112
+ return true;
2113
+ }
2114
+ toString() {
2115
+ //quotes are needed to differentiate the literal "http://test.com" from the URI http://test.com, so the literal value is always surrounded by quotes
2116
+ //quad quotes are needed in case of newlines
2117
+ // let quotes = this._value.indexOf("\n") != -1 ? '"""' : '"';
2118
+ let quotes = '"';
2119
+ let suffix = '';
2120
+ if (this.hasLanguage()) {
2121
+ suffix = '@' + this.language;
2122
+ }
2123
+ else if (this.hasDatatype()) {
2124
+ suffix = '^^<' + this.datatype.uri + '>';
2125
+ }
2126
+ //quotes in the value need to be escaped
2127
+ return (quotes +
2128
+ this._value.replace(/\"/g, '\\"').replace(/\n/g, '\\n') +
2129
+ quotes +
2130
+ suffix);
2131
+ }
2132
+ print(includeIncomingProperties = true) {
2133
+ return this.toString();
2134
+ }
2135
+ _equals(other, caseSensitive = true) {
2136
+ if (other === this)
2137
+ return true;
2138
+ var valueToMatch;
2139
+ var languageToMatch;
2140
+ var datatypeToMatch;
2141
+ if (other instanceof Literal) {
2142
+ valueToMatch = other.value;
2143
+ languageToMatch = other.language;
2144
+ datatypeToMatch = other.datatype; //direct access to avoid default, alternatively build a boolean parameter 'returnDefault=true' into getDataType()
2145
+ }
2146
+ else {
2147
+ var type = typeof other;
2148
+ if (type == 'string' || type == 'number' || type == 'boolean') {
2149
+ //if you don't specify a datatype we accept all
2150
+ valueToMatch = other.toString();
2151
+ languageToMatch = '';
2152
+ datatypeToMatch = null;
2153
+ }
2154
+ else {
2155
+ return false;
2156
+ }
2157
+ }
2158
+ //do the actual matching
2159
+ var valueMatch;
2160
+ if (caseSensitive) {
2161
+ valueMatch = this._value === valueToMatch;
2162
+ }
2163
+ else {
2164
+ valueMatch =
2165
+ this._value.toLocaleLowerCase() == valueToMatch.toLocaleLowerCase();
2166
+ }
2167
+ //if values match
2168
+ if (valueMatch) {
2169
+ //if there is a language
2170
+ if (this.hasLanguage()) {
2171
+ //then only the languages need to match
2172
+ return this.language == languageToMatch;
2173
+ }
2174
+ else {
2175
+ //no language = datatypes need to match
2176
+ //we check with this.datatype, not this.datatype which can return the default xsd:String
2177
+ //a literal without datatypespecified is however considered different from a a literal with a explicit xsd:String datatype
2178
+ //that is, like some SPARQL quad stores, you should be able to create two otherwise identical (sub&pred) quads for those two literals
2179
+ return this.datatype === datatypeToMatch;
2180
+ }
2181
+ }
2182
+ return false;
2183
+ }
2184
+ }
2185
+ exports.Literal = Literal;
2186
+ class Graph {
2187
+ constructor(value, quads) {
2188
+ this.value = value;
2189
+ // private static addedQuads: Map<Graph,QuadArray> = new Map();
2190
+ // private static removedQuads: Map<Graph,QuadArray> = new Map();
2191
+ // private static addedQuadsAlterations: Map<Graph,QuadArray> = new Map();
2192
+ this.termType = 'NamedNode';
2193
+ // super();
2194
+ this._node = NamedNode.getOrCreate(value);
2195
+ this.quads = quads ? quads : new QuadSet_js_1.QuadSet();
2196
+ }
2197
+ get node() {
2198
+ return this._node;
2199
+ }
2200
+ //Static methods
2201
+ /**
2202
+ * Resets the map of nodes that is known in this environment
2203
+ */
2204
+ static reset() {
2205
+ this.graphs = new CoreMap_1.CoreMap();
2206
+ }
2207
+ static create(quads) {
2208
+ var uri = NamedNode.createNewTempUri();
2209
+ return this._create(uri, quads);
2210
+ }
2211
+ /**
2212
+ * @internal
2213
+ * @param graph
2214
+ */
2215
+ static register(graph) {
2216
+ if (this.graphs.has(graph.node.uri)) {
2217
+ throw new Error('A graph with this URI already exists. You should probably use Graph.getOrCreate instead of Graph.create (' +
2218
+ graph.node.uri +
2219
+ ')');
2220
+ }
2221
+ this.graphs.set(graph.node.uri, graph);
2222
+ // super.register(graph);
2223
+ }
2224
+ /**
2225
+ * @internal
2226
+ * @param graph
2227
+ */
2228
+ static unregister(graph) {
2229
+ if (!this.graphs.has(graph.node.uri)) {
2230
+ throw new Error('This node has already been removed from the registry: ' +
2231
+ graph.node.uri);
2232
+ }
2233
+ this.graphs.delete(graph.node.uri);
2234
+ }
2235
+ /**
2236
+ * Adds the quad to all given maps
2237
+ * @param quad
2238
+ * @param maps
2239
+ * @private
2240
+ */
2241
+ /*private static registerGraphEvent(graph: Graph, quad:Quad, maps: Map<Graph, QuadArray>[]) {
2242
+ //register that this class has some events to emit
2243
+ eventBatcher.register(Graph);
2244
+ //for each given map
2245
+ maps.forEach((map) => {
2246
+ //add this quad under the predicate as key
2247
+ if (!map.has(graph)) {
2248
+ map.set(graph, new QuadArray());
2249
+ }
2250
+ map.get(graph).push(quad);
2251
+ });
2252
+ }*/
2253
+ /*static emitBatchedEvents(resolve?: any, reject?: any) {
2254
+ if(this.addedQuads.size > 0 || this.removedQuads.size > 0)
2255
+ {
2256
+ this.emitter.emit(Graph.CONTENTS_CHANGED,this.addedQuads,this.removedQuads);
2257
+ this.addedQuads = new Map();
2258
+ this.removedQuads = new Map()
2259
+ }
2260
+ if(this.addedQuadsAlterations.size > 0 || this.removedQuadsAlterations.size > 0)
2261
+ {
2262
+ this.emitter.emit(Graph.CONTENTS_ALTERED,this.addedQuadsAlterations,this.removedQuadsAlterations);
2263
+ this.addedQuadsAlterations = new Map();
2264
+ this.removedQuadsAlterations = new Map()
2265
+ }
2266
+ }*/
2267
+ static getOrCreate(uri) {
2268
+ return this.getGraph(uri) || this._create(uri);
2269
+ }
2270
+ static getGraph(uri, mustExist = false) {
2271
+ //look it up in known full uri node map
2272
+ if (this.graphs.has(uri)) {
2273
+ return this.graphs.get(uri);
2274
+ }
2275
+ if (mustExist) {
2276
+ throw Error('Could not find graph for: ' + uri);
2277
+ }
2278
+ return null;
2279
+ }
2280
+ static updateUri(graph, uri) {
2281
+ graph.node.uri = uri;
2282
+ }
2283
+ static getAll() {
2284
+ return this.graphs;
2285
+ }
2286
+ static _create(uri, quads) {
2287
+ var graph = new Graph(uri, quads);
2288
+ this.register(graph);
2289
+ return graph;
2290
+ }
2291
+ equals(other) {
2292
+ return other === this;
2293
+ }
2294
+ /**
2295
+ * @internal
2296
+ * @param quad
2297
+ */
2298
+ registerQuad(quad, alteration = false, emitEvents = true) {
2299
+ this.quads.add(quad);
2300
+ // if(emitEvents)
2301
+ // {
2302
+ // Graph.registerGraphEvent(this,quad,alteration ? [Graph.addedQuads] : [Graph.addedQuads,Graph.addedQuadsAlterations]);
2303
+ // }
2304
+ }
2305
+ /**
2306
+ * @internal
2307
+ * @param quad
2308
+ */
2309
+ unregisterQuad(quad, alteration = false, emitEvents = true) {
2310
+ this.quads.delete(quad);
2311
+ // if(emitEvents)
2312
+ // {
2313
+ // Graph.registerGraphEvent(this,quad,alteration ? [Graph.removedQuads] : [Graph.removedQuads,Graph.removedQuadsAlterations])
2314
+ // }
2315
+ }
2316
+ hasQuad(quad) {
2317
+ return this.quads.has(quad);
2318
+ }
2319
+ //Note: cannot name this getQuads, because NamedNode already uses that for getting all quads of all its properties
2320
+ getContents() {
2321
+ return this.quads;
2322
+ }
2323
+ setContents(quads) {
2324
+ this.quads = quads;
2325
+ }
2326
+ toString() {
2327
+ return ('Graph: [' +
2328
+ this.node.uri.toString() +
2329
+ ' - ' +
2330
+ this.quads.size +
2331
+ ' quads]');
2332
+ }
2333
+ }
2334
+ exports.Graph = Graph;
2335
+ // private static removedQuadsAlterations: Map<Graph,QuadArray> = new Map();
2336
+ /**
2337
+ * Emitted when changes have been made to this graph. Only emitted when data has actually changed, not just when data is loaded
2338
+ */
2339
+ Graph.CONTENTS_ALTERED = 'CONTENTS_ALTERED';
2340
+ /**
2341
+ * Emitted when the contents of this graph have changed. Can also be due to loading data
2342
+ */
2343
+ Graph.CONTENTS_CHANGED = 'CONTENTS_ALTERED';
2344
+ Graph.graphs = new CoreMap_1.CoreMap();
2345
+ class DefaultGraph extends Graph {
2346
+ constructor() {
2347
+ //empty string for default graph URI (part of the standard)
2348
+ //https://rdf.js.org/data-model-spec/#defaultgraph-interface
2349
+ super('');
2350
+ this.value = '';
2351
+ this.termType = types_js_1.DefaultGraphTermType;
2352
+ this.uri = default_graph_uri_js_1.defaultGraphURI;
2353
+ }
2354
+ toString() {
2355
+ return 'DefaultGraph';
2356
+ }
2357
+ }
2358
+ exports.defaultGraph = new DefaultGraph();
2359
+ class Quad extends EventEmitter_js_1.EventEmitter {
2360
+ /**
2361
+ * Creates the quad
2362
+ * @param subject - the subject of the quad
2363
+ * @param predicate
2364
+ * @param object
2365
+ */
2366
+ constructor(subject, predicate, object, _graph = exports.defaultGraph, implicit = false, alteration = false, emitEvents = true) {
2367
+ super();
2368
+ this.subject = subject;
2369
+ this.predicate = predicate;
2370
+ this.object = object;
2371
+ this._graph = _graph;
2372
+ this.implicit = implicit;
2373
+ this.setup(alteration, emitEvents);
2374
+ }
2375
+ get graph() {
2376
+ return this._graph;
2377
+ }
2378
+ /**
2379
+ * Returns true if this quad still exists as an object in memory, but is no longer actively used in the graph
2380
+ */
2381
+ get isRemoved() {
2382
+ return this._removed;
2383
+ }
2384
+ /**
2385
+ * @internal
2386
+ * Returns true if events of newly created quads or removed quads are currently batched and waiting to be emitted
2387
+ */
2388
+ static hasBatchedEvents() {
2389
+ return this.createdQuads.size > 0 || this.removedQuads.size > 0;
2390
+ }
2391
+ /*set graph(newGraph: Graph) {
2392
+ if(newGraph !== this._graph)
2393
+ {
2394
+ //NOTE: we could have gone a different way with Quad.moveToGraph(quad,newGraph) / quad.moveto(newGraph), which removes the old one and returns a new quad
2395
+ //if there is any issues with this implementation, go that way.
2396
+ //for now, this implementation keeps the same Quad object but mimics the adding / removing of quads
2397
+
2398
+ //create a clone of this quad as it is now, without sending alteration events
2399
+ let oldQuad = new Quad(this.subject,this.predicate,this.object,this._graph,this.implicit,false,false);
2400
+
2401
+ //make sure this cloned quad is not even registered
2402
+ oldQuad.turnOff();
2403
+
2404
+ //remove this quad from the old graph
2405
+ this._graph.unregisterQuad(this,true);
2406
+
2407
+ //update the graph
2408
+ this._graph = newGraph;
2409
+
2410
+ //register this quad in the new graph
2411
+ this._graph.registerQuad(this,true);
2412
+
2413
+ this.mimicEventsOnUpdate(oldQuad);
2414
+ }
2415
+ }*/
2416
+ /**
2417
+ * @internal
2418
+ */
2419
+ static emitBatchedEvents() {
2420
+ if (this.createdQuads.size > 0 && this.removedQuads.size > 0) {
2421
+ //if both created and removed quads are batched then we remove the quad from both sets
2422
+ this.createdQuads.forEach((quad) => {
2423
+ if (this.removedQuads.has(quad)) {
2424
+ this.createdQuads.delete(quad);
2425
+ this.removedQuads.delete(quad);
2426
+ }
2427
+ });
2428
+ }
2429
+ if (this.createdQuads.size > 0) {
2430
+ this.emitter.emit(Quad.QUADS_CREATED, this.createdQuads);
2431
+ this.createdQuads = new QuadSet_js_1.QuadSet();
2432
+ }
2433
+ if (this.removedQuads.size > 0) {
2434
+ this.emitter.emit(Quad.QUADS_REMOVED, this.removedQuads);
2435
+ this.removedQuads = new QuadSet_js_1.QuadSet();
2436
+ }
2437
+ if (this.createdQuadsAltered.size > 0 ||
2438
+ this.removedQuadsAltered.size > 0) {
2439
+ this.emitter.emit(Quad.QUADS_ALTERED, this.createdQuadsAltered, this.removedQuadsAltered);
2440
+ this.createdQuadsAltered = new QuadSet_js_1.QuadSet();
2441
+ this.removedQuadsAltered = new QuadSet_js_1.QuadSet();
2442
+ }
2443
+ }
2444
+ /**
2445
+ * Get the existing quad for the given subject,predicate and object, or create it if it didn't exists yet.
2446
+ * @param subject
2447
+ * @param predicate
2448
+ * @param object
2449
+ * @param implicit
2450
+ * @param alteration - states whether this quad has been created by a user interaction (true) or simply because of updated data has been loaded
2451
+ */
2452
+ static getOrCreate(subject, predicate, object, graph = exports.defaultGraph, implicit = false, alteration = false, emitEvents = true) {
2453
+ return (this.get(subject, predicate, object, graph) ||
2454
+ new Quad(subject, predicate, object, graph, implicit, alteration, emitEvents));
2455
+ }
2456
+ /**
2457
+ * Gets the existing quad for the given subject,predicate and object.
2458
+ * Will return any quad with an equivalent object. See Literal.isEquivalentTo() and NamedNode.isEquivalentTo() for more information.
2459
+ * @param subject
2460
+ * @param predicate
2461
+ * @param object
2462
+ */
2463
+ static get(subject, predicate, object, graph) {
2464
+ if (!subject || !predicate || !object)
2465
+ return null;
2466
+ return subject.getQuads(predicate, object).find((q) => q._graph === graph);
2467
+ }
2468
+ static moveQuadsToGraph(quads, graph, alteration = false) {
2469
+ let result = new (Object.getPrototypeOf(quads).constructor)();
2470
+ quads.forEach((quad) => {
2471
+ result.push(quad.moveToGraph(graph, alteration));
2472
+ });
2473
+ return result;
2474
+ }
2475
+ static emitRemovedQuad(quad, alteration = false) {
2476
+ //removed quad events are batched together and emitted on the next tick
2477
+ //so here we make sure the Quad class will emit its batched events on the next tick
2478
+ EventBatcher_js_1.eventBatcher.register(Quad);
2479
+ //and here we save this quad to a set of removedQuads which is a static property of the Quad class
2480
+ Quad.removedQuads.add(quad);
2481
+ if (alteration && !quad.implicit) {
2482
+ Quad.removedQuadsAltered.add(quad);
2483
+ }
2484
+ //we need to let this quad emit this event straight away because for example the reasoner needs to listen to this exact quad to retract
2485
+ quad.emit(Quad.QUAD_REMOVED);
2486
+ }
2487
+ static emitCreatedQuad(quad, alteration = false) {
2488
+ //new quad events are batched together and emitted on the next tick
2489
+ //so here we make sure the Quad class will emit its batched events on the next tick
2490
+ EventBatcher_js_1.eventBatcher.register(Quad);
2491
+ //and here we save this quad to a set of newQuads which is a static property of the Quad class
2492
+ Quad.createdQuads.add(quad);
2493
+ //only if it's an alteration AND it's relevant to storage controllers do we emit the QUADS_ALTERED event for this quad
2494
+ if (alteration && !quad.implicit) {
2495
+ Quad.createdQuadsAltered.add(quad);
2496
+ }
2497
+ }
2498
+ /**
2499
+ * Removes this quad and creates a new quad with the same subject,predicate,object, but a new graph.
2500
+ * Returns the new quad
2501
+ * @param newGraph
2502
+ */
2503
+ moveToGraph(newGraph, alteration = true) {
2504
+ if (newGraph === this._graph) {
2505
+ return this;
2506
+ }
2507
+ let newQuad = Quad.getOrCreate(this.subject, this.predicate, this.object, newGraph, this.implicit, alteration);
2508
+ this.remove(alteration);
2509
+ return newQuad;
2510
+ }
2511
+ /**
2512
+ * Turns off a quad. Meaning it will no longer be active in the graph.
2513
+ * Comes in handy in very specific use cases when for example quads have already been created, but you want to check what the state was before these quads were created
2514
+ */
2515
+ turnOff() {
2516
+ this.subject.unregisterProperty(this, false, false);
2517
+ // this.predicate.unregisterAsPredicate(this, false, false);
2518
+ this.object.unregisterInverseProperty(this, false, false);
2519
+ this.graph.unregisterQuad(this, false, false);
2520
+ }
2521
+ /**
2522
+ * Turns on a quad. Meaning it will be active (again) in the graph.
2523
+ * Only use this if you've had to turn quads off first.
2524
+ */
2525
+ turnOn() {
2526
+ this.subject.registerProperty(this, false, false);
2527
+ // this.predicate.registerAsPredicate(this, false, false);
2528
+ this.object.registerInverseProperty(this, false, false);
2529
+ this.graph.registerQuad(this, false, false);
2530
+ }
2531
+ /**
2532
+ * Turn an implicit quad into an explicit quad (because an explicit user action generated it as an independent explicit fact now)
2533
+ */
2534
+ makeExplicit() {
2535
+ if (this.implicit) {
2536
+ //unregister and make explicit
2537
+ this.turnOff();
2538
+ this.implicit = false;
2539
+ //re-register and make it an 'alteration' so it will be picked up by the storage
2540
+ this.setup(true);
2541
+ }
2542
+ }
2543
+ /**
2544
+ * Remove this quad from the graph
2545
+ * Will be removed both locally and from the graph database
2546
+ * @param alteration
2547
+ */
2548
+ remove(alteration = false, emitEvents = true) {
2549
+ if (this._removed)
2550
+ return;
2551
+ //first set removed is true so event handlers can detect the difference between added or removed values
2552
+ this._removed = true;
2553
+ this.subject.unregisterProperty(this);
2554
+ // this.predicate.unregisterAsPredicate(this);
2555
+ this.object.unregisterInverseProperty(this);
2556
+ this.graph.unregisterQuad(this, alteration);
2557
+ if (emitEvents) {
2558
+ Quad.emitRemovedQuad(this, alteration);
2559
+ }
2560
+ Quad.globalNumQuads--;
2561
+ }
2562
+ /**
2563
+ * Cancel the removal of a quad
2564
+ */
2565
+ undoRemoval() {
2566
+ this.setup();
2567
+ this._removed = false;
2568
+ }
2569
+ onValueChanged(oldValue) {
2570
+ let oldQuad = new Quad(this.subject, this.predicate, oldValue, this.graph, this.implicit, false, false);
2571
+ this.mimicEventsOnUpdate(oldQuad);
2572
+ }
2573
+ print() {
2574
+ return (Prefix_1.Prefix.toPrefixedIfPossible(this.subject.uri) +
2575
+ ' ' +
2576
+ Prefix_1.Prefix.toPrefixedIfPossible(this.predicate.uri) +
2577
+ ' ' +
2578
+ (this.object instanceof NamedNode
2579
+ ? Prefix_1.Prefix.toPrefixedIfPossible(this.object.uri)
2580
+ : this.object.toString()));
2581
+ }
2582
+ /**
2583
+ * Print this quad as a string
2584
+ */
2585
+ toString() {
2586
+ return (this.subject.toString() +
2587
+ ' ' +
2588
+ this.predicate.toString() +
2589
+ ' ' +
2590
+ this.object.toString() +
2591
+ ' ' +
2592
+ this.graph.toString() +
2593
+ (this.isRemoved ? ' (removed)' : ''));
2594
+ }
2595
+ setup(alteration = false, emitEvents = true) {
2596
+ // if(this.predicate.uri == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" && this.object['uri'] == "http://data.dacore.org/ontologies/core/Editor")
2597
+ // {
2598
+ // debugger;
2599
+ // }
2600
+ //let nodes take note of this quad in which they occur
2601
+ //first, we overwrite the property this.object with the result of register because a Literal may return a clone
2602
+ this.object = this.object.registerInverseProperty(this, alteration);
2603
+ this.subject.registerProperty(this, alteration);
2604
+ // this.predicate.registerAsPredicate(this, alteration);
2605
+ this._graph.registerQuad(this, alteration);
2606
+ if (emitEvents) {
2607
+ Quad.emitCreatedQuad(this, alteration);
2608
+ }
2609
+ Quad.globalNumQuads++;
2610
+ }
2611
+ mimicEventsOnUpdate(oldQuad) {
2612
+ //manually mimic the fact the old quad was removed and the new quad was added (storage requires this to add/remove those quads to/from the right quad stores)
2613
+ EventBatcher_js_1.eventBatcher.register(Quad);
2614
+ Quad.removedQuads.add(oldQuad);
2615
+ Quad.removedQuadsAltered.add(oldQuad);
2616
+ Quad.createdQuads.add(this);
2617
+ Quad.createdQuadsAltered.add(this);
2618
+ }
2619
+ }
2620
+ exports.Quad = Quad;
2621
+ /**
2622
+ * Emitter used by the class itself by static methods emitting events.
2623
+ * Anyone wanting to listen to that should therefore add a listener with Quad.emitter.on(...)
2624
+ * @internal
2625
+ */
2626
+ Quad.emitter = new EventEmitter_js_1.EventEmitter();
2627
+ /**
2628
+ * The number of quads active in this system
2629
+ */
2630
+ Quad.globalNumQuads = 0;
2631
+ /**
2632
+ * @internal
2633
+ * emitted when new quads have been created
2634
+ * TODO: possibly we can remove this, it may never be used. Only alterations are of interest?
2635
+ */
2636
+ Quad.QUADS_CREATED = 'QUADS_CREATED';
2637
+ /**
2638
+ * @internal
2639
+ * emitted by the Quad class itself when quads have been removed
2640
+ * TODO: possibly we can remove this, it may never be used. Only alterations are of interest?
2641
+ */
2642
+ Quad.QUADS_REMOVED = 'QUADS_REMOVED';
2643
+ /**
2644
+ * emitted by a quad when that quad is being removed
2645
+ * TODO: possibly we can remove this, it may never be used. Only alterations are of interest?
2646
+ */
2647
+ Quad.QUAD_REMOVED = 'QUAD_REMOVED';
2648
+ /**
2649
+ * emitted when quads have been altered by user interaction
2650
+ * @internal
2651
+ */
2652
+ Quad.QUADS_ALTERED = 'QUADS_ALTERED';
2653
+ //TODO: possibly we can remove these first two, they may never be used. Only alterations are of interest?
2654
+ Quad.createdQuads = new QuadSet_js_1.QuadSet();
2655
+ Quad.removedQuads = new QuadSet_js_1.QuadSet();
2656
+ Quad.removedQuadsAltered = new QuadSet_js_1.QuadSet();
2657
+ Quad.createdQuadsAltered = new QuadSet_js_1.QuadSet();
2658
+ //for debugging purposes
2659
+ let getNode = function (uri) {
2660
+ return NamedNode.getOrCreate(uri);
2661
+ };
2662
+ if (typeof window !== 'undefined') {
2663
+ window['getNode'] = getNode;
2664
+ }
2665
+ else if (typeof global !== 'undefined') {
2666
+ global['getNode'] = getNode;
2667
+ }
2668
+ //# sourceMappingURL=models.js.map