Skip to content

Commit 71c3101

Browse files
committed
Add preliminary N3 patch support.
1 parent a3f8a77 commit 71c3101

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

lib/handlers/patch.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const DEFAULT_TARGET_TYPE = 'text/turtle'
1414

1515
// Patch handlers by request body content type
1616
const PATCHERS = {
17-
'application/sparql-update': require('./patch/sparql-update-patcher.js')
17+
'application/sparql-update': require('./patch/sparql-update-patcher.js'),
18+
'text/n3': require('./patch/n3-patcher.js')
1819
}
1920

2021
// Handles a PATCH request

lib/handlers/patch/n3-patcher.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Performs a text/n3 patch on a graph
2+
3+
module.exports = patch
4+
5+
const $rdf = require('rdflib')
6+
const debug = require('../../debug').handlers
7+
const error = require('../../http-error')
8+
9+
const PATCH_NS = 'http://example.org/patch#'
10+
const PREFIXES = `PREFIX p: <${PATCH_NS}>\n`
11+
12+
// Patches the given graph
13+
function patch (targetKB, targetURI, patchText) {
14+
const patchKB = $rdf.graph()
15+
const target = patchKB.sym(targetURI)
16+
17+
// Must parse relative to document's base address but patch doc should get diff URI
18+
// @@@ beware the triples from the patch ending up in the same place
19+
const patchURI = targetURI + '#patch'
20+
21+
return parsePatchDocument(targetURI, patchURI, patchText, patchKB)
22+
.then(patchObject => applyPatch(patchObject, target, targetKB))
23+
}
24+
25+
// Parses the given N3 patch document
26+
function parsePatchDocument (targetURI, patchURI, patchText, patchKB) {
27+
debug('PATCH -- Parsing patch...')
28+
29+
// Parse the N3 document into triples
30+
return new Promise((resolve, reject) => {
31+
const patchGraph = $rdf.graph()
32+
$rdf.parse(patchText, patchGraph, patchURI, 'text/n3')
33+
resolve(patchGraph)
34+
})
35+
// Query the N3 document for insertions and deletions
36+
.then(patchGraph => queryForFirstResult(patchGraph, `${PREFIXES}
37+
SELECT ?insert ?delete WHERE {
38+
?patch p:patches <${targetURI}>.
39+
OPTIONAL { ?patch p:insert ?insert. }
40+
OPTIONAL { ?patch p:delete ?delete. }
41+
}`)
42+
)
43+
// Return the insertions and deletions as an rdflib patch document
44+
.then(result => {
45+
return {
46+
insert: result['?insert'],
47+
delete: result['?delete']
48+
}
49+
})
50+
}
51+
52+
// Applies the patch to the target graph
53+
function applyPatch (patchObject, target, targetKB) {
54+
return new Promise((resolve, reject) =>
55+
targetKB.applyPatch(patchObject, target, (err) => {
56+
if (err) {
57+
const message = err.message || err // returns string at the moment
58+
debug('PATCH FAILED. Returning 409. Message: \'' + message + '\'')
59+
return reject(error(409, 'Error when applying the patch'))
60+
}
61+
resolve(targetKB)
62+
})
63+
)
64+
}
65+
66+
// Queries the store with the given SPARQL query and returns the first result
67+
function queryForFirstResult (store, sparql) {
68+
return new Promise((resolve, reject) => {
69+
const query = $rdf.SPARQLToQuery(sparql, false, store)
70+
store.query(query, resolve)
71+
})
72+
}

0 commit comments

Comments
 (0)