rdflib 2.2.31 → 2.2.32-2f2a2f3c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/670.rdflib.min.js +1 -0
- package/dist/730.rdflib.min.js +3 -0
- package/dist/730.rdflib.min.js.LICENSE.txt +58 -0
- package/dist/730.rdflib.min.js.map +1 -0
- package/dist/rdflib.min.js +1 -1
- package/dist/rdflib.min.js.LICENSE.txt +0 -59
- package/dist/rdflib.min.js.map +1 -1
- package/esm/blank-node.js +10 -6
- package/esm/collection.js +3 -4
- package/esm/factories/factory-types.js +10 -10
- package/esm/fetcher.js +64 -35
- package/esm/formula.js +10 -13
- package/esm/jsonldparser.js +4 -3
- package/esm/lists.js +2 -1
- package/esm/literal.js +6 -8
- package/esm/node-internal.js +5 -10
- package/esm/rdfxmlparser.js +3 -0
- package/esm/serializer.js +2 -3
- package/esm/statement.js +7 -11
- package/esm/store.js +39 -32
- package/esm/types.js +18 -1
- package/esm/update-manager.js +150 -83
- package/esm/utils.js +0 -1
- package/esm/variable.js +2 -4
- package/lib/blank-node.js +10 -6
- package/lib/collection.js +3 -4
- package/lib/factories/factory-types.js +10 -10
- package/lib/fetcher.js +88 -36
- package/lib/formula.js +10 -13
- package/lib/index.d.ts +1 -1
- package/lib/jsonldparser.js +9 -3
- package/lib/lists.js +15 -1
- package/lib/literal.js +6 -8
- package/lib/node-internal.js +5 -10
- package/lib/query.d.ts +1 -1
- package/lib/rdfxmlparser.js +3 -0
- package/lib/serializer.d.ts +1 -1
- package/lib/serializer.js +2 -3
- package/lib/sparql-to-query.d.ts +1 -1
- package/lib/statement.js +7 -11
- package/lib/store.d.ts +1 -1
- package/lib/store.js +55 -34
- package/lib/types.js +22 -0
- package/lib/update-manager.d.ts +25 -5
- package/lib/update-manager.js +154 -82
- package/lib/utils-js.d.ts +3 -3
- package/lib/variable.js +2 -4
- package/lib/xsd-internal.d.ts +1 -1
- package/package.json +20 -19
- package/src/fetcher.ts +13 -0
- package/src/jsonldparser.js +2 -4
- package/src/serializer.js +1 -1
- package/src/store.ts +18 -1
- package/src/update-manager.ts +243 -163
package/src/update-manager.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/* @file Update Manager Class
|
|
2
2
|
**
|
|
3
|
-
** 2007-07-15
|
|
3
|
+
** 2007-07-15 original SPARQL Update module by Joe Presbrey <presbrey@mit.edu>
|
|
4
4
|
** 2010-08-08 TimBL folded in Kenny's WEBDAV
|
|
5
|
-
** 2010-12-07 TimBL
|
|
5
|
+
** 2010-12-07 TimBL added local file write code
|
|
6
6
|
*/
|
|
7
7
|
import IndexedFormula from './store'
|
|
8
|
-
import {docpart, join as uriJoin} from './uri'
|
|
9
|
-
import Fetcher, {Options} from './fetcher'
|
|
8
|
+
import { docpart, join as uriJoin } from './uri'
|
|
9
|
+
import Fetcher, { Options } from './fetcher'
|
|
10
10
|
import Namespace from './namespace'
|
|
11
11
|
import Serializer from './serializer'
|
|
12
|
-
import {isBlankNode, isStore} from './utils/terms'
|
|
12
|
+
import { isBlankNode, isStore } from './utils/terms'
|
|
13
13
|
import * as Util from './utils-js'
|
|
14
14
|
import Statement from './statement'
|
|
15
15
|
import RDFlibNamedNode from './named-node'
|
|
16
|
-
import {termValue} from './utils/termValue'
|
|
17
|
-
import {BlankNode, NamedNode, Quad, Quad_Graph, Quad_Object, Quad_Predicate, Quad_Subject, Term,} from './tf-types'
|
|
16
|
+
import { termValue } from './utils/termValue'
|
|
17
|
+
import { BlankNode, NamedNode, Quad, Quad_Graph, Quad_Object, Quad_Predicate, Quad_Subject, Term, } from './tf-types'
|
|
18
18
|
|
|
19
19
|
interface UpdateManagerFormula extends IndexedFormula {
|
|
20
20
|
fetcher: Fetcher
|
|
@@ -45,7 +45,7 @@ export default class UpdateManager {
|
|
|
45
45
|
/**
|
|
46
46
|
* @param store - The quadstore to store data and metadata. Created if not passed.
|
|
47
47
|
*/
|
|
48
|
-
constructor
|
|
48
|
+
constructor(store?: IndexedFormula) {
|
|
49
49
|
store = store || new IndexedFormula()
|
|
50
50
|
if (store.updater) {
|
|
51
51
|
throw new Error("You can't have two UpdateManagers for the same store")
|
|
@@ -70,56 +70,65 @@ export default class UpdateManager {
|
|
|
70
70
|
this.patchControl = []
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
patchControlFor
|
|
73
|
+
patchControlFor(doc: NamedNode) {
|
|
74
74
|
if (!this.patchControl[doc.value]) {
|
|
75
75
|
this.patchControl[doc.value] = []
|
|
76
76
|
}
|
|
77
77
|
return this.patchControl[doc.value]
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
isHttpUri(uri:string){
|
|
81
|
-
return(
|
|
80
|
+
isHttpUri(uri: string) {
|
|
81
|
+
return (uri.slice(0, 4) === 'http')
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
/** Remove from the store HTTP authorization metadata
|
|
85
|
-
* The
|
|
86
|
-
* of the results of previous HTTP transactions.
|
|
87
|
-
* the user logs in, then that data misrepresents what would happen
|
|
88
|
-
* if the user tried again.
|
|
89
|
-
*/
|
|
90
|
-
flagAuthorizationMetadata
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
/** Remove from the store HTTP authorization metadata
|
|
85
|
+
* The editable function below relies on copies we have in the store
|
|
86
|
+
* of the results of previous HTTP transactions. However, when
|
|
87
|
+
* the user logs in, then that data misrepresents what would happen
|
|
88
|
+
* if the user tried again.
|
|
89
|
+
*/
|
|
90
|
+
flagAuthorizationMetadata(kb?: IndexedFormula) {
|
|
91
|
+
if (!kb) {
|
|
92
|
+
kb = this.store
|
|
93
|
+
}
|
|
94
|
+
const meta = kb.fetcher?.appNode
|
|
95
|
+
const requests = kb.statementsMatching(undefined, this.ns.link('requestedURI'), undefined, meta).map(st => st.subject)
|
|
96
|
+
for (const request of requests) {
|
|
97
|
+
const response = kb.any(request, this.ns.link('response'), null, meta) as Quad_Subject
|
|
98
|
+
if (response !== undefined) { // ts
|
|
99
|
+
kb.add(response, this.ns.link('outOfDate'), true as any, meta) // @@ Boolean is fine - fix types
|
|
100
|
+
}
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
|
-
}
|
|
101
103
|
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Tests whether a file is editable.
|
|
106
|
+
* If the file has a specific annotation that it is machine written,
|
|
107
|
+
* for safety, it is editable (this doesn't actually check for write access)
|
|
108
|
+
* If the file has wac-allow and accept patch headers, those are respected.
|
|
109
|
+
* and local write access is determined by those headers.
|
|
110
|
+
* This async version not only looks at past HTTP requests, it also makes new ones if necessary.
|
|
111
|
+
*
|
|
112
|
+
* @returns The method string N3PATCH or SPARQL or DAV or
|
|
113
|
+
* LOCALFILE or false if known, undefined if not known.
|
|
114
|
+
*/
|
|
115
|
+
async checkEditable(uri: string | NamedNode, kb?: IndexedFormula): Promise<string | boolean | undefined> {
|
|
116
|
+
if (!uri) {
|
|
117
|
+
return false // Eg subject is bnode, no known doc to write to
|
|
118
|
+
}
|
|
119
|
+
if (!kb) {
|
|
120
|
+
kb = this.store
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const initial = this.editable(uri, kb)
|
|
124
|
+
if (initial !== undefined) {
|
|
125
|
+
return initial
|
|
126
|
+
}
|
|
127
|
+
await kb.fetcher?.load(uri)
|
|
128
|
+
const final = this.editable(uri, kb)
|
|
129
|
+
// console.log(`Loaded ${uri} just to check editable, result: ${final}.`)
|
|
130
|
+
return final
|
|
131
|
+
}
|
|
123
132
|
/**
|
|
124
133
|
* Tests whether a file is editable.
|
|
125
134
|
* If the file has a specific annotation that it is machine written,
|
|
@@ -131,7 +140,7 @@ flagAuthorizationMetadata () {
|
|
|
131
140
|
* @returns The method string SPARQL or DAV or
|
|
132
141
|
* LOCALFILE or false if known, undefined if not known.
|
|
133
142
|
*/
|
|
134
|
-
editable
|
|
143
|
+
editable(uri: string | NamedNode, kb?: IndexedFormula): string | boolean | undefined {
|
|
135
144
|
if (!uri) {
|
|
136
145
|
return false // Eg subject is bnode, no known doc to write to
|
|
137
146
|
}
|
|
@@ -140,21 +149,21 @@ flagAuthorizationMetadata () {
|
|
|
140
149
|
}
|
|
141
150
|
uri = termValue(uri)
|
|
142
151
|
|
|
143
|
-
if (
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
if (!this.isHttpUri(uri as string)) {
|
|
153
|
+
if (kb.holds(
|
|
154
|
+
kb.rdfFactory.namedNode(uri),
|
|
155
|
+
kb.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
|
|
156
|
+
kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/link#MachineEditableDocument'))) {
|
|
148
157
|
return 'LOCALFILE'
|
|
149
158
|
}
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
var request
|
|
153
162
|
var definitive = false
|
|
154
|
-
const meta =
|
|
163
|
+
const meta = kb.fetcher?.appNode
|
|
155
164
|
// const kb = s
|
|
156
165
|
|
|
157
|
-
|
|
166
|
+
// @ts-ignore passes a string to kb.each, which expects a term. Should this work?
|
|
158
167
|
var requests = kb.each(undefined, this.ns.link('requestedURI'), docpart(uri), meta)
|
|
159
168
|
var method: string
|
|
160
169
|
for (var r = 0; r < requests.length; r++) {
|
|
@@ -170,7 +179,7 @@ flagAuthorizationMetadata () {
|
|
|
170
179
|
if (wacAllow) {
|
|
171
180
|
for (var bit of wacAllow.split(',')) {
|
|
172
181
|
var lr = bit.split('=')
|
|
173
|
-
if (lr[0].includes('user') && !lr[1].includes('write') && !lr[1].includes('append')
|
|
182
|
+
if (lr[0].includes('user') && !lr[1].includes('write') && !lr[1].includes('append')) {
|
|
174
183
|
// console.log(' editable? excluded by WAC-Allow: ', wacAllow)
|
|
175
184
|
return false
|
|
176
185
|
}
|
|
@@ -180,6 +189,7 @@ flagAuthorizationMetadata () {
|
|
|
180
189
|
if (acceptPatch.length) {
|
|
181
190
|
for (let i = 0; i < acceptPatch.length; i++) {
|
|
182
191
|
method = acceptPatch[i].value.trim()
|
|
192
|
+
if (method.indexOf('text/n3') >= 0) return 'N3PATCH'
|
|
183
193
|
if (method.indexOf('application/sparql-update') >= 0) return 'SPARQL'
|
|
184
194
|
if (method.indexOf('application/sparql-update-single-match') >= 0) return 'SPARQL'
|
|
185
195
|
}
|
|
@@ -197,8 +207,8 @@ flagAuthorizationMetadata () {
|
|
|
197
207
|
}
|
|
198
208
|
}
|
|
199
209
|
|
|
200
|
-
if (
|
|
201
|
-
if(
|
|
210
|
+
if (!this.isHttpUri(uri as string)) {
|
|
211
|
+
if (!wacAllow) return false;
|
|
202
212
|
else return 'LOCALFILE';
|
|
203
213
|
}
|
|
204
214
|
|
|
@@ -228,13 +238,15 @@ flagAuthorizationMetadata () {
|
|
|
228
238
|
return undefined // We don't know (yet) as we haven't had a response (yet)
|
|
229
239
|
}
|
|
230
240
|
|
|
231
|
-
anonymize
|
|
232
|
-
|
|
241
|
+
anonymize(obj) {
|
|
242
|
+
let anonymized = (obj.toNT().substr(0, 2) === '_:' && this.mentioned(obj))
|
|
233
243
|
? '?' + obj.toNT().substr(2)
|
|
234
|
-
: obj.toNT()
|
|
244
|
+
: obj.toNT();
|
|
245
|
+
|
|
246
|
+
return anonymized;
|
|
235
247
|
}
|
|
236
248
|
|
|
237
|
-
anonymizeNT
|
|
249
|
+
anonymizeNT(stmt: Quad) {
|
|
238
250
|
return this.anonymize(stmt.subject) + ' ' +
|
|
239
251
|
this.anonymize(stmt.predicate) + ' ' +
|
|
240
252
|
this.anonymize(stmt.object) + ' .'
|
|
@@ -248,7 +260,7 @@ flagAuthorizationMetadata () {
|
|
|
248
260
|
* Returns a list of all bnodes occurring in a statement
|
|
249
261
|
* @private
|
|
250
262
|
*/
|
|
251
|
-
statementBnodes
|
|
263
|
+
statementBnodes(st: Quad): BlankNode[] {
|
|
252
264
|
return [st.subject, st.predicate, st.object].filter(function (x) {
|
|
253
265
|
return isBlankNode(x)
|
|
254
266
|
}) as BlankNode[]
|
|
@@ -258,7 +270,7 @@ flagAuthorizationMetadata () {
|
|
|
258
270
|
* Returns a list of all bnodes occurring in a list of statements
|
|
259
271
|
* @private
|
|
260
272
|
*/
|
|
261
|
-
statementArrayBnodes
|
|
273
|
+
statementArrayBnodes(sts: ReadonlyArray<Quad>) {
|
|
262
274
|
var bnodes: BlankNode[] = []
|
|
263
275
|
for (let i = 0; i < sts.length; i++) {
|
|
264
276
|
bnodes = bnodes.concat(this.statementBnodes(sts[i]))
|
|
@@ -277,7 +289,7 @@ flagAuthorizationMetadata () {
|
|
|
277
289
|
* Makes a cached list of [Inverse-]Functional properties
|
|
278
290
|
* @private
|
|
279
291
|
*/
|
|
280
|
-
cacheIfps
|
|
292
|
+
cacheIfps() {
|
|
281
293
|
this.ifps = {}
|
|
282
294
|
var a = this.store.each(undefined, this.ns.rdf('type'),
|
|
283
295
|
this.ns.owl('InverseFunctionalProperty'))
|
|
@@ -295,7 +307,7 @@ flagAuthorizationMetadata () {
|
|
|
295
307
|
* Returns a context to bind a given node, up to a given depth
|
|
296
308
|
* @private
|
|
297
309
|
*/
|
|
298
|
-
bnodeContext2
|
|
310
|
+
bnodeContext2(x, source, depth) {
|
|
299
311
|
// Return a list of statements which indirectly identify a node
|
|
300
312
|
// Depth > 1 if try further indirection.
|
|
301
313
|
// Return array of statements (possibly empty), or null if failure
|
|
@@ -306,12 +318,12 @@ flagAuthorizationMetadata () {
|
|
|
306
318
|
if (this.fps[sts[i].predicate.value]) {
|
|
307
319
|
y = sts[i].subject
|
|
308
320
|
if (!y.isBlank) {
|
|
309
|
-
return [
|
|
321
|
+
return [sts[i]]
|
|
310
322
|
}
|
|
311
323
|
if (depth) {
|
|
312
324
|
res = this.bnodeContext2(y, source, depth - 1)
|
|
313
325
|
if (res) {
|
|
314
|
-
return res.concat([
|
|
326
|
+
return res.concat([sts[i]])
|
|
315
327
|
}
|
|
316
328
|
}
|
|
317
329
|
}
|
|
@@ -322,12 +334,12 @@ flagAuthorizationMetadata () {
|
|
|
322
334
|
if (this.ifps[sts[i].predicate.value]) {
|
|
323
335
|
y = sts[i].object
|
|
324
336
|
if (!y.isBlank) {
|
|
325
|
-
return [
|
|
337
|
+
return [sts[i]]
|
|
326
338
|
}
|
|
327
339
|
if (depth) {
|
|
328
340
|
res = this.bnodeContext2(y, source, depth - 1)
|
|
329
341
|
if (res) {
|
|
330
|
-
return res.concat([
|
|
342
|
+
return res.concat([sts[i]])
|
|
331
343
|
}
|
|
332
344
|
}
|
|
333
345
|
}
|
|
@@ -339,7 +351,7 @@ flagAuthorizationMetadata () {
|
|
|
339
351
|
* Returns the smallest context to bind a given single bnode
|
|
340
352
|
* @private
|
|
341
353
|
*/
|
|
342
|
-
bnodeContext1
|
|
354
|
+
bnodeContext1(x, source) {
|
|
343
355
|
// Return a list of statements which indirectly identify a node
|
|
344
356
|
// Breadth-first
|
|
345
357
|
for (var depth = 0; depth < 3; depth++) { // Try simple first
|
|
@@ -354,7 +366,7 @@ flagAuthorizationMetadata () {
|
|
|
354
366
|
/**
|
|
355
367
|
* @private
|
|
356
368
|
*/
|
|
357
|
-
mentioned
|
|
369
|
+
mentioned(x) {
|
|
358
370
|
return this.store.statementsMatching(x, null, null, null).length !== 0 || // Don't pin fresh bnodes
|
|
359
371
|
this.store.statementsMatching(null, x).length !== 0 ||
|
|
360
372
|
this.store.statementsMatching(null, null, x).length !== 0
|
|
@@ -363,7 +375,7 @@ flagAuthorizationMetadata () {
|
|
|
363
375
|
/**
|
|
364
376
|
* @private
|
|
365
377
|
*/
|
|
366
|
-
bnodeContext
|
|
378
|
+
bnodeContext(bnodes, doc) {
|
|
367
379
|
var context = []
|
|
368
380
|
if (bnodes.length) {
|
|
369
381
|
this.cacheIfps()
|
|
@@ -380,7 +392,7 @@ flagAuthorizationMetadata () {
|
|
|
380
392
|
* Returns the best context for a single statement
|
|
381
393
|
* @private
|
|
382
394
|
*/
|
|
383
|
-
statementContext
|
|
395
|
+
statementContext(st: Quad) {
|
|
384
396
|
var bnodes = this.statementBnodes(st)
|
|
385
397
|
return this.bnodeContext(bnodes, st.graph)
|
|
386
398
|
}
|
|
@@ -388,7 +400,7 @@ flagAuthorizationMetadata () {
|
|
|
388
400
|
/**
|
|
389
401
|
* @private
|
|
390
402
|
*/
|
|
391
|
-
contextWhere
|
|
403
|
+
contextWhere(context) {
|
|
392
404
|
var updater = this
|
|
393
405
|
return (!context || context.length === 0)
|
|
394
406
|
? ''
|
|
@@ -401,7 +413,7 @@ flagAuthorizationMetadata () {
|
|
|
401
413
|
/**
|
|
402
414
|
* @private
|
|
403
415
|
*/
|
|
404
|
-
fire
|
|
416
|
+
fire(
|
|
405
417
|
uri: string,
|
|
406
418
|
query: string,
|
|
407
419
|
callbackFunction: CallBackFunction,
|
|
@@ -415,7 +427,7 @@ flagAuthorizationMetadata () {
|
|
|
415
427
|
// console.log('UpdateManager: sending update to <' + uri + '>')
|
|
416
428
|
|
|
417
429
|
options.noMeta = true;
|
|
418
|
-
options.contentType = 'application/sparql-update';
|
|
430
|
+
options.contentType = options.contentType || 'application/sparql-update';
|
|
419
431
|
options.body = query;
|
|
420
432
|
|
|
421
433
|
return this.store.fetcher.webOperation('PATCH', uri, options)
|
|
@@ -438,7 +450,7 @@ flagAuthorizationMetadata () {
|
|
|
438
450
|
})
|
|
439
451
|
}
|
|
440
452
|
|
|
441
|
-
// ARE THESE
|
|
453
|
+
// ARE THESE THREE FUNCTIONS USED? DEPRECATE?
|
|
442
454
|
|
|
443
455
|
/** return a statemnet updating function
|
|
444
456
|
*
|
|
@@ -446,7 +458,7 @@ flagAuthorizationMetadata () {
|
|
|
446
458
|
* It returns an object which includes
|
|
447
459
|
* function which can be used to change the object of the statement.
|
|
448
460
|
*/
|
|
449
|
-
update_statement
|
|
461
|
+
update_statement(statement: Quad) {
|
|
450
462
|
if (statement && !statement.graph) {
|
|
451
463
|
return
|
|
452
464
|
}
|
|
@@ -474,7 +486,7 @@ flagAuthorizationMetadata () {
|
|
|
474
486
|
}
|
|
475
487
|
}
|
|
476
488
|
|
|
477
|
-
insert_statement
|
|
489
|
+
insert_statement(st: Quad, callbackFunction: CallBackFunction): void {
|
|
478
490
|
var st0 = st instanceof Array ? st[0] : st
|
|
479
491
|
var query = this.contextWhere(this.statementContext(st0))
|
|
480
492
|
|
|
@@ -492,7 +504,7 @@ flagAuthorizationMetadata () {
|
|
|
492
504
|
this.fire(st0.graph.value, query, callbackFunction)
|
|
493
505
|
}
|
|
494
506
|
|
|
495
|
-
delete_statement
|
|
507
|
+
delete_statement(st: Quad | Quad[], callbackFunction: CallBackFunction): void {
|
|
496
508
|
var st0 = st instanceof Array ? st[0] : st
|
|
497
509
|
var query = this.contextWhere(this.statementContext(st0))
|
|
498
510
|
|
|
@@ -510,7 +522,7 @@ flagAuthorizationMetadata () {
|
|
|
510
522
|
this.fire(st0.graph.value, query, callbackFunction)
|
|
511
523
|
}
|
|
512
524
|
|
|
513
|
-
/// //////////////////////
|
|
525
|
+
/// //////////////////////
|
|
514
526
|
|
|
515
527
|
/**
|
|
516
528
|
* Requests a now or future action to refresh changes coming downstream
|
|
@@ -521,7 +533,7 @@ flagAuthorizationMetadata () {
|
|
|
521
533
|
* @param doc
|
|
522
534
|
* @param action
|
|
523
535
|
*/
|
|
524
|
-
requestDownstreamAction
|
|
536
|
+
requestDownstreamAction(doc: NamedNode, action): void {
|
|
525
537
|
var control = this.patchControlFor(doc)
|
|
526
538
|
if (!control.pendingUpstream) {
|
|
527
539
|
action(doc)
|
|
@@ -540,18 +552,18 @@ flagAuthorizationMetadata () {
|
|
|
540
552
|
* We want to start counting websocket notifications
|
|
541
553
|
* to distinguish the ones from others from our own.
|
|
542
554
|
*/
|
|
543
|
-
clearUpstreamCount
|
|
555
|
+
clearUpstreamCount(doc: NamedNode): void {
|
|
544
556
|
var control = this.patchControlFor(doc)
|
|
545
557
|
control.upstreamCount = 0
|
|
546
558
|
}
|
|
547
559
|
|
|
548
|
-
getUpdatesVia
|
|
560
|
+
getUpdatesVia(doc: NamedNode): string | null {
|
|
549
561
|
var linkHeaders = this.store.fetcher.getHeader(doc, 'updates-via')
|
|
550
562
|
if (!linkHeaders || !linkHeaders.length) return null
|
|
551
563
|
return linkHeaders[0].trim()
|
|
552
564
|
}
|
|
553
565
|
|
|
554
|
-
addDownstreamChangeListener
|
|
566
|
+
addDownstreamChangeListener(doc: NamedNode, listener): void {
|
|
555
567
|
var control = this.patchControlFor(doc)
|
|
556
568
|
if (!control.downstreamChangeListeners) { control.downstreamChangeListeners = [] }
|
|
557
569
|
control.downstreamChangeListeners.push(listener)
|
|
@@ -560,7 +572,7 @@ flagAuthorizationMetadata () {
|
|
|
560
572
|
})
|
|
561
573
|
}
|
|
562
574
|
|
|
563
|
-
reloadAndSync
|
|
575
|
+
reloadAndSync(doc: NamedNode): void {
|
|
564
576
|
var control = this.patchControlFor(doc)
|
|
565
577
|
var updater = this
|
|
566
578
|
|
|
@@ -582,7 +594,7 @@ flagAuthorizationMetadata () {
|
|
|
582
594
|
}
|
|
583
595
|
}
|
|
584
596
|
control.reloading = false
|
|
585
|
-
if (control.outOfDate){
|
|
597
|
+
if (control.outOfDate) {
|
|
586
598
|
// console.log(' Extra reload because of extra update.')
|
|
587
599
|
control.outOfDate = false
|
|
588
600
|
tryReload()
|
|
@@ -622,7 +634,7 @@ flagAuthorizationMetadata () {
|
|
|
622
634
|
*
|
|
623
635
|
* @returns {boolean}
|
|
624
636
|
*/
|
|
625
|
-
setRefreshHandler
|
|
637
|
+
setRefreshHandler(doc: NamedNode, handler): boolean {
|
|
626
638
|
let wssURI = this.getUpdatesVia(doc) // relative
|
|
627
639
|
// var kb = this.store
|
|
628
640
|
var theHandler = handler
|
|
@@ -663,7 +675,7 @@ flagAuthorizationMetadata () {
|
|
|
663
675
|
var control = self.patchControlFor(doc)
|
|
664
676
|
control.upstreamCount = 0
|
|
665
677
|
|
|
666
|
-
socket.onerror = function onerror
|
|
678
|
+
socket.onerror = function onerror(err: Error) {
|
|
667
679
|
// console.log('Error on Websocket:', err)
|
|
668
680
|
}
|
|
669
681
|
|
|
@@ -728,8 +740,8 @@ flagAuthorizationMetadata () {
|
|
|
728
740
|
const thisUpdater = this
|
|
729
741
|
const uniqueDocs: Array<NamedNode> = []
|
|
730
742
|
docs.forEach(doc => {
|
|
731
|
-
|
|
732
|
-
|
|
743
|
+
if (!uniqueDocs.find(uniqueDoc => uniqueDoc.equals(doc))) uniqueDocs.push(doc as NamedNode)
|
|
744
|
+
})
|
|
733
745
|
const updates = uniqueDocs.map(doc =>
|
|
734
746
|
thisUpdater.update(deletions.filter(st => st.why.equals(doc)),
|
|
735
747
|
insertions.filter(st => st.why.equals(doc))))
|
|
@@ -740,7 +752,103 @@ flagAuthorizationMetadata () {
|
|
|
740
752
|
}
|
|
741
753
|
|
|
742
754
|
/**
|
|
743
|
-
*
|
|
755
|
+
* @private
|
|
756
|
+
*
|
|
757
|
+
* This helper function constructs SPARQL Update query from resolved arguments.
|
|
758
|
+
*
|
|
759
|
+
* @param ds: deletions array.
|
|
760
|
+
* @param is: insertions array.
|
|
761
|
+
* @param bnodes_context: Additional context to uniquely identify any blank nodes.
|
|
762
|
+
*/
|
|
763
|
+
constructSparqlUpdateQuery(
|
|
764
|
+
ds: ReadonlyArray<Statement>,
|
|
765
|
+
is: ReadonlyArray<Statement>,
|
|
766
|
+
bnodes_context,
|
|
767
|
+
): string {
|
|
768
|
+
var whereClause = this.contextWhere(bnodes_context)
|
|
769
|
+
var query = ''
|
|
770
|
+
if (whereClause.length) { // Is there a WHERE clause?
|
|
771
|
+
if (ds.length) {
|
|
772
|
+
query += 'DELETE { '
|
|
773
|
+
for (let i = 0; i < ds.length; i++) {
|
|
774
|
+
query += this.anonymizeNT(ds[i]) + '\n'
|
|
775
|
+
}
|
|
776
|
+
query += ' }\n'
|
|
777
|
+
}
|
|
778
|
+
if (is.length) {
|
|
779
|
+
query += 'INSERT { '
|
|
780
|
+
for (let i = 0; i < is.length; i++) {
|
|
781
|
+
query += this.anonymizeNT(is[i]) + '\n'
|
|
782
|
+
}
|
|
783
|
+
query += ' }\n'
|
|
784
|
+
}
|
|
785
|
+
query += whereClause
|
|
786
|
+
} else { // no where clause
|
|
787
|
+
if (ds.length) {
|
|
788
|
+
query += 'DELETE DATA { '
|
|
789
|
+
for (let i = 0; i < ds.length; i++) {
|
|
790
|
+
query += this.anonymizeNT(ds[i]) + '\n'
|
|
791
|
+
}
|
|
792
|
+
query += ' } \n'
|
|
793
|
+
}
|
|
794
|
+
if (is.length) {
|
|
795
|
+
if (ds.length) query += ' ; '
|
|
796
|
+
query += 'INSERT DATA { '
|
|
797
|
+
for (let i = 0; i < is.length; i++) {
|
|
798
|
+
query += this.nTriples(is[i]) + '\n'
|
|
799
|
+
}
|
|
800
|
+
query += ' }\n'
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return query;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* @private
|
|
808
|
+
*
|
|
809
|
+
* This helper function constructs n3-patch query from resolved arguments.
|
|
810
|
+
*
|
|
811
|
+
* @param ds: deletions array.
|
|
812
|
+
* @param is: insertions array.
|
|
813
|
+
* @param bnodes_context: Additional context to uniquely identify any blanknodes.
|
|
814
|
+
*/
|
|
815
|
+
constructN3PatchQuery(
|
|
816
|
+
ds: ReadonlyArray<Statement>,
|
|
817
|
+
is: ReadonlyArray<Statement>,
|
|
818
|
+
bnodes_context,
|
|
819
|
+
): string {
|
|
820
|
+
var query = `
|
|
821
|
+
@prefix solid: <http://www.w3.org/ns/solid/terms#>.
|
|
822
|
+
@prefix ex: <http://www.example.org/terms#>.
|
|
823
|
+
|
|
824
|
+
_:patch
|
|
825
|
+
`;
|
|
826
|
+
// If bnode context is non trivial, express it as ?conditions formula.
|
|
827
|
+
if (bnodes_context && bnodes_context.length > 0) {
|
|
828
|
+
query += `
|
|
829
|
+
solid:where {
|
|
830
|
+
${bnodes_context.map((x) => this.anonymizeNT(x)).join('\n ')}
|
|
831
|
+
};`
|
|
832
|
+
}
|
|
833
|
+
if (ds.length > 0) {
|
|
834
|
+
query += `
|
|
835
|
+
solid:deletes {
|
|
836
|
+
${ds.map((x) => this.anonymizeNT(x)).join('\n ')}
|
|
837
|
+
};`
|
|
838
|
+
}
|
|
839
|
+
if (is.length > 0) {
|
|
840
|
+
query += `
|
|
841
|
+
solid:inserts {
|
|
842
|
+
${is.map((x) => this.anonymizeNT(x)).join('\n ')}
|
|
843
|
+
};`
|
|
844
|
+
}
|
|
845
|
+
query += " a solid:InsertDeletePatch .\n"
|
|
846
|
+
|
|
847
|
+
return query;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* This high-level function updates the local store if the web is changed successfully.
|
|
744
852
|
* Deletions, insertions may be undefined or single statements or lists or formulae (may contain bnodes which can be indirectly identified by a where clause).
|
|
745
853
|
* The `why` property of each statement must be the same and give the web document to be updated.
|
|
746
854
|
* @param deletions - Statement or statements to be deleted.
|
|
@@ -750,16 +858,16 @@ flagAuthorizationMetadata () {
|
|
|
750
858
|
* @param options - Options for the fetch call
|
|
751
859
|
*/
|
|
752
860
|
update(
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
861
|
+
deletions: ReadonlyArray<Statement>,
|
|
862
|
+
insertions: ReadonlyArray<Statement>,
|
|
863
|
+
callback?: (
|
|
864
|
+
uri: string | undefined | null,
|
|
865
|
+
success: boolean,
|
|
866
|
+
errorBody?: string,
|
|
867
|
+
response?: Response | Error
|
|
868
|
+
) => void,
|
|
869
|
+
secondTry?: boolean,
|
|
870
|
+
options: Options = {}
|
|
763
871
|
): void | Promise<void> {
|
|
764
872
|
if (!callback) {
|
|
765
873
|
var thisUpdater = this
|
|
@@ -778,10 +886,10 @@ flagAuthorizationMetadata () {
|
|
|
778
886
|
var kb = this.store
|
|
779
887
|
var ds = !deletions ? []
|
|
780
888
|
: isStore(deletions) ? deletions.statements
|
|
781
|
-
: deletions instanceof Array ? deletions : [
|
|
889
|
+
: deletions instanceof Array ? deletions : [deletions]
|
|
782
890
|
var is = !insertions ? []
|
|
783
891
|
: isStore(insertions) ? insertions.statements
|
|
784
|
-
: insertions instanceof Array ? insertions : [
|
|
892
|
+
: insertions instanceof Array ? insertions : [insertions]
|
|
785
893
|
if (!(ds instanceof Array)) {
|
|
786
894
|
throw new Error('Type Error ' + (typeof ds) + ': ' + ds)
|
|
787
895
|
}
|
|
@@ -823,70 +931,42 @@ flagAuthorizationMetadata () {
|
|
|
823
931
|
})
|
|
824
932
|
})
|
|
825
933
|
|
|
826
|
-
var protocol = this.editable(doc.value, kb)
|
|
934
|
+
var protocol = this.editable(doc.value, kb);
|
|
935
|
+
|
|
827
936
|
if (protocol === false) {
|
|
828
937
|
throw new Error('Update: Can\'t make changes in uneditable ' + doc)
|
|
829
938
|
}
|
|
830
939
|
if (protocol === undefined) { // Not enough metadata
|
|
831
940
|
if (secondTry) {
|
|
832
|
-
throw new Error('Update: Loaded ' + doc + "but
|
|
941
|
+
throw new Error('Update: Loaded ' + doc + "but still can't figure out what editing protocol it supports.")
|
|
833
942
|
}
|
|
834
943
|
// console.log(`Update: have not loaded ${doc} before: loading now...`);
|
|
835
944
|
(this.store.fetcher.load(doc as NamedNode) as Promise<Response>).then(response => {
|
|
836
945
|
this.update(deletions, insertions, callback, true, options)
|
|
837
946
|
}, err => {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
947
|
+
if (err.response.status === 404) { // nonexistent files are fine
|
|
948
|
+
this.update(deletions, insertions, callback, true, options)
|
|
949
|
+
} else {
|
|
950
|
+
throw new Error(`Update: Can't get updatability status ${doc} before patching: ${err}`)
|
|
951
|
+
}
|
|
843
952
|
})
|
|
844
953
|
return
|
|
845
|
-
} else if ((protocol as string).indexOf('SPARQL') >= 0) {
|
|
954
|
+
} else if ((protocol as string).indexOf('SPARQL') >= 0 || (protocol as string).indexOf('N3PATCH') >= 0) {
|
|
955
|
+
var isSparql = (protocol as string).indexOf('SPARQL') >= 0
|
|
956
|
+
|
|
846
957
|
var bnodes: BlankNode[] = []
|
|
847
958
|
// change ReadOnly type to Mutable type
|
|
848
959
|
type Mutable<Type> = {
|
|
849
960
|
-readonly [Key in keyof Type]: Type[Key];
|
|
850
961
|
}
|
|
851
|
-
|
|
962
|
+
|
|
852
963
|
if (ds.length) bnodes = this.statementArrayBnodes(ds as Mutable<typeof ds>)
|
|
853
964
|
if (is.length) bnodes = bnodes.concat(this.statementArrayBnodes(is as Mutable<typeof is>))
|
|
854
965
|
var context = this.bnodeContext(bnodes, doc)
|
|
855
|
-
|
|
856
|
-
var query =
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
query += 'DELETE { '
|
|
860
|
-
for (let i = 0; i < ds.length; i++) {
|
|
861
|
-
query += this.anonymizeNT(ds[i]) + '\n'
|
|
862
|
-
}
|
|
863
|
-
query += ' }\n'
|
|
864
|
-
}
|
|
865
|
-
if (is.length) {
|
|
866
|
-
query += 'INSERT { '
|
|
867
|
-
for (let i = 0; i < is.length; i++) {
|
|
868
|
-
query += this.anonymizeNT(is[i]) + '\n'
|
|
869
|
-
}
|
|
870
|
-
query += ' }\n'
|
|
871
|
-
}
|
|
872
|
-
query += whereClause
|
|
873
|
-
} else { // no where clause
|
|
874
|
-
if (ds.length) {
|
|
875
|
-
query += 'DELETE DATA { '
|
|
876
|
-
for (let i = 0; i < ds.length; i++) {
|
|
877
|
-
query += this.anonymizeNT(ds[i]) + '\n'
|
|
878
|
-
}
|
|
879
|
-
query += ' } \n'
|
|
880
|
-
}
|
|
881
|
-
if (is.length) {
|
|
882
|
-
if (ds.length) query += ' ; '
|
|
883
|
-
query += 'INSERT DATA { '
|
|
884
|
-
for (let i = 0; i < is.length; i++) {
|
|
885
|
-
query += this.nTriples(is[i]) + '\n'
|
|
886
|
-
}
|
|
887
|
-
query += ' }\n'
|
|
888
|
-
}
|
|
889
|
-
}
|
|
966
|
+
|
|
967
|
+
var query = isSparql ? this.constructSparqlUpdateQuery(ds, is, context) : this.constructN3PatchQuery(ds, is, context);
|
|
968
|
+
options.contentType = isSparql ? 'application/sparql-update' : 'text/n3'
|
|
969
|
+
|
|
890
970
|
// Track pending upstream patches until they have finished their callbackFunction
|
|
891
971
|
control.pendingUpstream = control.pendingUpstream ? control.pendingUpstream + 1 : 1
|
|
892
972
|
if ('upstreamCount' in control) {
|
|
@@ -944,7 +1024,7 @@ flagAuthorizationMetadata () {
|
|
|
944
1024
|
}
|
|
945
1025
|
}
|
|
946
1026
|
|
|
947
|
-
updateDav
|
|
1027
|
+
updateDav(
|
|
948
1028
|
doc: Quad_Subject,
|
|
949
1029
|
ds,
|
|
950
1030
|
is,
|
|
@@ -962,7 +1042,7 @@ flagAuthorizationMetadata () {
|
|
|
962
1042
|
if (!response) {
|
|
963
1043
|
return null // throw "No record HTTP GET response for document: "+doc
|
|
964
1044
|
}
|
|
965
|
-
var contentType = (kb.the(response, this.ns.httph('content-type'))as Term).value
|
|
1045
|
+
var contentType = (kb.the(response, this.ns.httph('content-type')) as Term).value
|
|
966
1046
|
|
|
967
1047
|
// prepare contents of revised document
|
|
968
1048
|
let newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice() // copy!
|
|
@@ -1015,7 +1095,7 @@ flagAuthorizationMetadata () {
|
|
|
1015
1095
|
* @param callbackFunction
|
|
1016
1096
|
* @param options
|
|
1017
1097
|
*/
|
|
1018
|
-
updateLocalFile
|
|
1098
|
+
updateLocalFile(doc: NamedNode, ds, is, callbackFunction, options: Options = {}): void {
|
|
1019
1099
|
const kb = this.store
|
|
1020
1100
|
// console.log('Writing back to local file\n')
|
|
1021
1101
|
|
|
@@ -1023,10 +1103,10 @@ flagAuthorizationMetadata () {
|
|
|
1023
1103
|
let newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice() // copy!
|
|
1024
1104
|
|
|
1025
1105
|
for (let i = 0; i < ds.length; i++) {
|
|
1026
|
-
Util.RDFArrayRemove(newSts, ds[
|
|
1106
|
+
Util.RDFArrayRemove(newSts, ds[i])
|
|
1027
1107
|
}
|
|
1028
1108
|
for (let i = 0; i < is.length; i++) {
|
|
1029
|
-
newSts.push(is[
|
|
1109
|
+
newSts.push(is[i])
|
|
1030
1110
|
}
|
|
1031
1111
|
// serialize to the appropriate format
|
|
1032
1112
|
var dot = doc.value.lastIndexOf('.')
|
|
@@ -1035,7 +1115,7 @@ flagAuthorizationMetadata () {
|
|
|
1035
1115
|
}
|
|
1036
1116
|
var ext = doc.value.slice(dot + 1)
|
|
1037
1117
|
|
|
1038
|
-
let contentType = Fetcher.CONTENT_TYPE_BY_EXT[
|
|
1118
|
+
let contentType = Fetcher.CONTENT_TYPE_BY_EXT[ext]
|
|
1039
1119
|
if (!contentType) {
|
|
1040
1120
|
throw new Error('File extension .' + ext + ' not supported for data write')
|
|
1041
1121
|
}
|
|
@@ -1043,8 +1123,8 @@ flagAuthorizationMetadata () {
|
|
|
1043
1123
|
options.body = this.serialize(doc.value, newSts, contentType);
|
|
1044
1124
|
options.contentType = contentType;
|
|
1045
1125
|
|
|
1046
|
-
kb.fetcher.webOperation('PUT', doc.value, options).then(
|
|
1047
|
-
if(!response.ok) return callbackFunction(doc.value,false,response.error)
|
|
1126
|
+
kb.fetcher.webOperation('PUT', doc.value, options).then((response) => {
|
|
1127
|
+
if (!response.ok) return callbackFunction(doc.value, false, response.error)
|
|
1048
1128
|
for (let i = 0; i < ds.length; i++) {
|
|
1049
1129
|
kb.remove(ds[i]);
|
|
1050
1130
|
}
|
|
@@ -1060,7 +1140,7 @@ flagAuthorizationMetadata () {
|
|
|
1060
1140
|
*
|
|
1061
1141
|
* @returns {string}
|
|
1062
1142
|
*/
|
|
1063
|
-
serialize
|
|
1143
|
+
serialize(uri: string, data: string | Quad[], contentType: string): string {
|
|
1064
1144
|
const kb = this.store
|
|
1065
1145
|
let documentString
|
|
1066
1146
|
|
|
@@ -1143,7 +1223,7 @@ flagAuthorizationMetadata () {
|
|
|
1143
1223
|
* @param doc {RDFlibNamedNode}
|
|
1144
1224
|
* @param callbackFunction
|
|
1145
1225
|
*/
|
|
1146
|
-
reload
|
|
1226
|
+
reload(
|
|
1147
1227
|
kb: IndexedFormula,
|
|
1148
1228
|
doc: docReloadType,
|
|
1149
1229
|
callbackFunction: (ok: boolean, message?: string, response?: Error | Response) => {} | void
|
|
@@ -1163,8 +1243,8 @@ flagAuthorizationMetadata () {
|
|
|
1163
1243
|
//@ts-ignore Where does onErrorWasCalled come from?
|
|
1164
1244
|
} else if (response.onErrorWasCalled || response.status !== 200) {
|
|
1165
1245
|
// console.log(' Non-HTTP error reloading data! onErrorWasCalled=' +
|
|
1166
|
-
|
|
1167
|
-
|
|
1246
|
+
//@ts-ignore Where does onErrorWasCalled come from?
|
|
1247
|
+
// response.onErrorWasCalled + ' status: ' + response.status)
|
|
1168
1248
|
callbackFunction(false, 'Non-HTTP error reloading data: ' + body, response)
|
|
1169
1249
|
} else {
|
|
1170
1250
|
var elapsedTimeMs = Date.now() - startTime
|
|
@@ -1176,8 +1256,8 @@ flagAuthorizationMetadata () {
|
|
|
1176
1256
|
doc.reloadTimeCount += 1
|
|
1177
1257
|
|
|
1178
1258
|
// console.log(' Fetch took ' + elapsedTimeMs + 'ms, av. of ' +
|
|
1179
|
-
|
|
1180
|
-
|
|
1259
|
+
// doc.reloadTimeCount + ' = ' +
|
|
1260
|
+
// (doc.reloadTimeTotal / doc.reloadTimeCount) + 'ms.')
|
|
1181
1261
|
|
|
1182
1262
|
callbackFunction(true)
|
|
1183
1263
|
}
|