feat: Create new resources when patching

This commit is contained in:
Joachim Van Herwegen 2020-12-07 16:48:30 +01:00
parent 07cd63bffa
commit 7011b766b4
2 changed files with 36 additions and 8 deletions

View File

@ -10,6 +10,7 @@ import { RepresentationMetadata } from '../../ldp/representation/RepresentationM
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
import { getLoggerFor } from '../../logging/LogUtil';
import { INTERNAL_QUADS } from '../../util/ContentTypes';
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
import { guardStream } from '../../util/GuardedStream';
import type { ResourceLocker } from '../../util/locking/ResourceLocker';
@ -82,15 +83,23 @@ export class SparqlUpdatePatchHandler extends PatchHandler {
*/
private async applyPatch(identifier: ResourceIdentifier, deletes: Algebra.Pattern[], inserts: Algebra.Pattern[]):
Promise<void> {
// Read the quads of the current representation
const quads = await this.source.getRepresentation(identifier, { type: [{ value: INTERNAL_QUADS, weight: 1 }]});
const store = new Store<BaseQuad>();
const importEmitter = store.import(quads.data);
await new Promise((resolve, reject): void => {
importEmitter.on('end', resolve);
importEmitter.on('error', reject);
});
this.logger.debug(`${store.size} quads in ${identifier.path}.`);
try {
// Read the quads of the current representation
const quads = await this.source.getRepresentation(identifier, { type: [{ value: INTERNAL_QUADS, weight: 1 }]});
const importEmitter = store.import(quads.data);
await new Promise((resolve, reject): void => {
importEmitter.on('end', resolve);
importEmitter.on('error', reject);
});
this.logger.debug(`${store.size} quads in ${identifier.path}.`);
} catch (error: unknown) {
// In case the resource does not exist yet we want to create it
if (!(error instanceof NotFoundHttpError)) {
throw error;
}
this.logger.debug(`Patching new resource ${identifier.path}.`);
}
// Apply the patch
store.removeQuads(deletes);

View File

@ -8,6 +8,7 @@ import { RepresentationMetadata } from '../../../../src/ldp/representation/Repre
import { SparqlUpdatePatchHandler } from '../../../../src/storage/patch/SparqlUpdatePatchHandler';
import type { ResourceStore } from '../../../../src/storage/ResourceStore';
import { INTERNAL_QUADS } from '../../../../src/util/ContentTypes';
import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError';
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
import type { Lock } from '../../../../src/util/locking/Lock';
import type { ResourceLocker } from '../../../../src/util/locking/ResourceLocker';
@ -215,4 +216,22 @@ describe('A SparqlUpdatePatchHandler', (): void => {
await expect(handler.handle(input)).rejects.toThrow('error');
expect(order).toEqual([ 'acquire', 'getRepresentation', 'release' ]);
});
it('creates a new resource if it does not exist yet.', async(): Promise<void> => {
// There is no initial data
startQuads = [];
source.getRepresentation = jest.fn((): any => {
order.push('getRepresentation');
throw new NotFoundHttpError();
});
await handler.handle({ identifier: { path: 'path' },
patch: { algebra: translate(
'INSERT DATA { <http://test.com/s1> <http://test.com/p1> <http://test.com/o1>. }',
{ quads: true },
) } as SparqlUpdatePatch });
expect(await basicChecks(startQuads.concat(
[ quad(namedNode('http://test.com/s1'), namedNode('http://test.com/p1'), namedNode('http://test.com/o1')) ],
))).toBe(true);
});
});