Skip to content

Commit 4e08bfb

Browse files
committed
Refactor patch handler to perform everything but parsing.
1 parent 8b863fc commit 4e08bfb

File tree

5 files changed

+57
-91
lines changed

5 files changed

+57
-91
lines changed

lib/handlers/patch.js

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ const crypto = require('crypto')
1313

1414
const DEFAULT_TARGET_TYPE = 'text/turtle'
1515

16-
// Patch handlers by request body content type
17-
const PATCHERS = {
18-
'application/sparql-update': require('./patch/sparql-update-patcher.js'),
19-
'text/n3': require('./patch/n3-patcher.js')
16+
// Patch parsers by request body content type
17+
const PATCH_PARSERS = {
18+
'application/sparql-update': require('./patch/sparql-update-parser.js'),
19+
'text/n3': require('./patch/n3-patch-parser.js')
2020
}
2121

2222
// Handles a PATCH request
2323
function patchHandler (req, res, next) {
24-
debug('PATCH -- ' + req.originalUrl)
24+
debug(`PATCH -- ${req.originalUrl}`)
2525
res.header('MS-Author-Via', 'SPARQL')
2626

2727
// Obtain details of the target resource
2828
const ldp = req.app.locals.ldp
29-
const root = !ldp.idp ? ldp.root : ldp.root + req.hostname + '/'
29+
const root = !ldp.idp ? ldp.root : `${ldp.root}${req.hostname}/`
3030
const target = {}
3131
target.file = utils.uriToFilename(req.path, root)
3232
target.uri = utils.uriAbs(req) + req.originalUrl
@@ -39,17 +39,18 @@ function patchHandler (req, res, next) {
3939
patch.uri = `${target.uri}#patch-${hash(patch.text)}`
4040
patch.contentType = (req.get('content-type') || '').match(/^[^;\s]*/)[0]
4141
debug('PATCH -- Received patch (%d bytes, %s)', patch.text.length, patch.contentType)
42-
43-
// Find the appropriate patcher for the given content type
44-
const patchGraph = PATCHERS[patch.contentType]
45-
if (!patchGraph) {
46-
return next(error(415, 'Unsupported patch content type: ' + patch.contentType))
42+
const parsePatch = PATCH_PARSERS[patch.contentType]
43+
if (!parsePatch) {
44+
return next(error(415, `Unsupported patch content type: ${patch.contentType}`))
4745
}
4846

49-
// Read the RDF graph to be patched from the file
50-
readGraph(target)
47+
// Parse the target graph and the patch document
48+
Promise.all([
49+
readGraph(target),
50+
parsePatch(target.uri, patch.uri, patch.text)
51+
])
5152
// Patch the graph and write it back to the file
52-
.then(graph => patchGraph(graph, target.uri, patch.uri, patch.text))
53+
.then(([graph, patchObject]) => applyPatch(patchObject, graph, target))
5354
.then(graph => writeGraph(graph, target))
5455
// Send the result to the client
5556
.then(result => { res.send(result) })
@@ -74,7 +75,7 @@ function readGraph (resource) {
7475
fileContents = ''
7576
// Fail on all other errors
7677
} else {
77-
return reject(error(500, 'Patch: Original file read error:' + err))
78+
return reject(error(500, `Original file read error: ${err}`))
7879
}
7980
}
8081
debug('PATCH -- Read target file (%d bytes)', fileContents.length)
@@ -88,22 +89,38 @@ function readGraph (resource) {
8889
try {
8990
$rdf.parse(fileContents, graph, resource.uri, resource.contentType)
9091
} catch (err) {
91-
throw error(500, 'Patch: Target ' + resource.contentType + ' file syntax error:' + err)
92+
throw error(500, `Patch: Target ${resource.contentType} file syntax error: ${err}`)
9293
}
9394
debug('PATCH -- Parsed target file')
9495
return graph
9596
})
9697
}
9798

99+
// Applies the patch to the RDF graph
100+
function applyPatch (patchObject, graph, target) {
101+
debug('PATCH -- Applying patch')
102+
return new Promise((resolve, reject) =>
103+
graph.applyPatch(patchObject, graph.sym(target.uri), (err) => {
104+
if (err) {
105+
const message = err.message || err // returns string at the moment
106+
debug(`PATCH -- FAILED. Returning 409. Message: '${message}'`)
107+
return reject(error(409, `The patch could not be applied. ${message}`))
108+
}
109+
resolve(graph)
110+
})
111+
)
112+
}
113+
98114
// Writes the RDF graph to the given resource
99115
function writeGraph (graph, resource) {
116+
debug('PATCH -- Writing patched file')
100117
return new Promise((resolve, reject) => {
101118
const resourceSym = graph.sym(resource.uri)
102119
const serialized = $rdf.serialize(resourceSym, graph, resource.uri, resource.contentType)
103120

104121
fs.writeFile(resource.file, serialized, {encoding: 'utf8'}, function (err) {
105122
if (err) {
106-
return reject(error(500, 'Failed to write file back after patch: ' + err))
123+
return reject(error(500, `Failed to write file after patch: ${err}`))
107124
}
108125
debug('PATCH -- applied successfully')
109126
resolve('Patch applied successfully.\n')

lib/handlers/patch/n3-patcher.js renamed to lib/handlers/patch/n3-patch-parser.js

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,22 @@
1-
// Performs a text/n3 patch on a graph
1+
// Parses a text/n3 patch
22

3-
module.exports = patch
3+
module.exports = parsePatchDocument
44

55
const $rdf = require('rdflib')
6-
const debug = require('../../debug').handlers
76
const error = require('../../http-error')
87

98
const PATCH_NS = 'http://example.org/patch#'
109
const PREFIXES = `PREFIX p: <${PATCH_NS}>\n`
1110

12-
// Patches the given graph
13-
function patch (targetKB, targetURI, patchURI, patchText) {
14-
const patchKB = $rdf.graph()
15-
const target = patchKB.sym(targetURI)
16-
17-
return parsePatchDocument(targetURI, patchURI, patchText, patchKB)
18-
.then(patchObject => applyPatch(patchObject, target, targetKB))
19-
}
20-
2111
// Parses the given N3 patch document
22-
function parsePatchDocument (targetURI, patchURI, patchText, patchKB) {
23-
debug('PATCH -- Parsing patch...')
24-
12+
function parsePatchDocument (targetURI, patchURI, patchText) {
2513
// Parse the N3 document into triples
2614
return new Promise((resolve, reject) => {
2715
const patchGraph = $rdf.graph()
2816
$rdf.parse(patchText, patchGraph, patchURI, 'text/n3')
2917
resolve(patchGraph)
3018
})
31-
.catch(err => { throw error(400, `Invalid patch document: ${err}`) })
19+
.catch(err => { throw error(400, `Patch document syntax error: ${err}`) })
3220

3321
// Query the N3 document for insertions and deletions
3422
.then(patchGraph => queryForFirstResult(patchGraph, `${PREFIXES}
@@ -51,20 +39,6 @@ function parsePatchDocument (targetURI, patchURI, patchText, patchKB) {
5139
})
5240
}
5341

54-
// Applies the patch to the target graph
55-
function applyPatch (patchObject, target, targetKB) {
56-
return new Promise((resolve, reject) =>
57-
targetKB.applyPatch(patchObject, target, (err) => {
58-
if (err) {
59-
const message = err.message || err // returns string at the moment
60-
debug('PATCH FAILED. Returning 409. Message: \'' + message + '\'')
61-
return reject(error(409, `The patch could not be applied. ${message}`))
62-
}
63-
resolve(targetKB)
64-
})
65-
)
66-
}
67-
6842
// Queries the store with the given SPARQL query and returns the first result
6943
function queryForFirstResult (store, sparql) {
7044
return new Promise((resolve, reject) => {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Parses an application/sparql-update patch
2+
3+
module.exports = parsePatchDocument
4+
5+
const $rdf = require('rdflib')
6+
const error = require('../../http-error')
7+
8+
// Parses the given SPARQL UPDATE document
9+
function parsePatchDocument (targetURI, patchURI, patchText) {
10+
return new Promise((resolve, reject) => {
11+
const baseURI = patchURI.replace(/#.*/, '')
12+
try {
13+
resolve($rdf.sparqlUpdateParser(patchText, $rdf.graph(), baseURI))
14+
} catch (err) {
15+
reject(error(400, `Patch document syntax error: ${err}`))
16+
}
17+
})
18+
}

lib/handlers/patch/sparql-update-patcher.js

Lines changed: 0 additions & 43 deletions
This file was deleted.

test/integration/patch.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('PATCH', () => {
5151
.send('invalid')
5252
.expect(400)
5353
.then(response => {
54-
assert.include(response.text, 'Invalid patch document')
54+
assert.include(response.text, 'Patch document syntax error')
5555
})
5656
)
5757
})

0 commit comments

Comments
 (0)