From 96a07e4853dc58be8dc9526622742349d68e7369 Mon Sep 17 00:00:00 2001 From: Joachim Van Herwegen Date: Tue, 11 May 2021 14:55:21 +0200 Subject: [PATCH] refactor: Simplify resource metadata generation --- src/init/RootContainerInitializer.ts | 6 ++-- src/storage/DataAccessorBasedStore.ts | 4 +-- src/storage/accessors/FileDataAccessor.ts | 34 ++++++++++------------- src/util/QuadUtil.ts | 24 ++-------------- src/util/ResourceUtil.ts | 15 ++++------ test/unit/util/QuadUtil.test.ts | 21 +------------- 6 files changed, 26 insertions(+), 78 deletions(-) diff --git a/src/init/RootContainerInitializer.ts b/src/init/RootContainerInitializer.ts index 060ee7488..6dff2ad7c 100644 --- a/src/init/RootContainerInitializer.ts +++ b/src/init/RootContainerInitializer.ts @@ -1,4 +1,3 @@ -import { DataFactory } from 'n3'; import { BasicRepresentation } from '../ldp/representation/BasicRepresentation'; import { RepresentationMetadata } from '../ldp/representation/RepresentationMetadata'; import type { ResourceIdentifier } from '../ldp/representation/ResourceIdentifier'; @@ -6,10 +5,9 @@ import { getLoggerFor } from '../logging/LogUtil'; import type { ResourceStore } from '../storage/ResourceStore'; import { TEXT_TURTLE } from '../util/ContentTypes'; import { ensureTrailingSlash } from '../util/PathUtil'; -import { generateResourceQuads } from '../util/ResourceUtil'; +import { addResourceMetadata } from '../util/ResourceUtil'; import { PIM, RDF } from '../util/Vocabularies'; import { Initializer } from './Initializer'; -import namedNode = DataFactory.namedNode; /** * Initializes ResourceStores by creating a root container if it didn't exist yet. @@ -43,7 +41,7 @@ export class RootContainerInitializer extends Initializer { */ protected async createRootContainer(): Promise { const metadata = new RepresentationMetadata(this.baseId, TEXT_TURTLE); - metadata.addQuads(generateResourceQuads(namedNode(this.baseId.path), true)); + addResourceMetadata(metadata, true); // Make sure the root container is a pim:Storage // This prevents deletion of the root container as storage root containers can not be deleted diff --git a/src/storage/DataAccessorBasedStore.ts b/src/storage/DataAccessorBasedStore.ts index 39e75fe9a..5df621a50 100644 --- a/src/storage/DataAccessorBasedStore.ts +++ b/src/storage/DataAccessorBasedStore.ts @@ -25,7 +25,7 @@ import { toCanonicalUriPath, } from '../util/PathUtil'; import { parseQuads } from '../util/QuadUtil'; -import { generateResourceQuads } from '../util/ResourceUtil'; +import { addResourceMetadata } from '../util/ResourceUtil'; import { CONTENT_TYPE, DC, HTTP, LDP, POSIX, PIM, RDF, VANN, XSD } from '../util/Vocabularies'; import type { DataAccessor } from './accessors/DataAccessor'; import type { ResourceStore } from './ResourceStore'; @@ -293,7 +293,7 @@ export class DataAccessorBasedStore implements ResourceStore { // Need to do this before handling container data to have the correct identifier const { metadata } = representation; metadata.identifier = DataFactory.namedNode(identifier.path); - metadata.addQuads(generateResourceQuads(metadata.identifier, isContainer)); + addResourceMetadata(metadata, isContainer); // Validate container data if (isContainer) { diff --git a/src/storage/accessors/FileDataAccessor.ts b/src/storage/accessors/FileDataAccessor.ts index 33241d3aa..98cc513a2 100644 --- a/src/storage/accessors/FileDataAccessor.ts +++ b/src/storage/accessors/FileDataAccessor.ts @@ -1,8 +1,7 @@ import type { Stats } from 'fs'; import { createWriteStream, createReadStream, promises as fsPromises } from 'fs'; import type { Readable } from 'stream'; -import { DataFactory } from 'n3'; -import type { NamedNode, Quad } from 'rdf-js'; +import type { Quad } from 'rdf-js'; import type { Representation } from '../../ldp/representation/Representation'; import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata'; import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier'; @@ -13,8 +12,8 @@ import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMedi import { guardStream } from '../../util/GuardedStream'; import type { Guarded } from '../../util/GuardedStream'; import { joinFilePath, isContainerIdentifier } from '../../util/PathUtil'; -import { parseQuads, pushQuad, serializeQuads } from '../../util/QuadUtil'; -import { generateResourceQuads } from '../../util/ResourceUtil'; +import { parseQuads, serializeQuads } from '../../util/QuadUtil'; +import { addResourceMetadata } from '../../util/ResourceUtil'; import { toLiteral } from '../../util/TermUtil'; import { CONTENT_TYPE, DC, LDP, POSIX, RDF, XSD } from '../../util/Vocabularies'; import type { FileIdentifierMapper, ResourceLink } from '../mapping/FileIdentifierMapper'; @@ -251,8 +250,8 @@ export class FileDataAccessor implements DataAccessor { Promise { const metadata = new RepresentationMetadata(link.identifier) .addQuads(await this.getRawMetadata(link.identifier)); - metadata.addQuads(generateResourceQuads(metadata.identifier as NamedNode, isContainer)); - metadata.addQuads(this.generatePosixQuads(metadata.identifier as NamedNode, stats)); + addResourceMetadata(metadata, isContainer); + this.addPosixMetadata(metadata, stats); return metadata; } @@ -306,30 +305,25 @@ export class FileDataAccessor implements DataAccessor { .mapFilePathToUrl(joinFilePath(link.filePath, childName), entry.isDirectory()); // Generate metadata of this specific child - const subject = DataFactory.namedNode(childLink.identifier.path); const childStats = await fsPromises.lstat(joinFilePath(link.filePath, childName)); - const quads: Quad[] = []; - quads.push(...generateResourceQuads(subject, childStats.isDirectory())); - quads.push(...this.generatePosixQuads(subject, childStats)); - yield new RepresentationMetadata(subject).addQuads(quads); + const metadata = new RepresentationMetadata(childLink.identifier); + addResourceMetadata(metadata, childStats.isDirectory()); + this.addPosixMetadata(metadata, childStats); + yield metadata; } } /** * Helper function to add file system related metadata. - * @param subject - Subject for the new quads. + * @param metadata - metadata object to add to * @param stats - Stats of the file/directory corresponding to the resource. */ - private generatePosixQuads(subject: NamedNode, stats: Stats): Quad[] { - const quads: Quad[] = []; - pushQuad(quads, subject, DC.terms.modified, toLiteral(stats.mtime.toISOString(), XSD.terms.dateTime)); - pushQuad(quads, subject, POSIX.terms.mtime, toLiteral( - Math.floor(stats.mtime.getTime() / 1000), XSD.terms.integer, - )); + private addPosixMetadata(metadata: RepresentationMetadata, stats: Stats): void { + metadata.add(DC.terms.modified, toLiteral(stats.mtime.toISOString(), XSD.terms.dateTime)); + metadata.add(POSIX.terms.mtime, toLiteral(Math.floor(stats.mtime.getTime() / 1000), XSD.terms.integer)); if (!stats.isDirectory()) { - pushQuad(quads, subject, POSIX.terms.size, toLiteral(stats.size, XSD.terms.integer)); + metadata.add(POSIX.terms.size, toLiteral(stats.size, XSD.terms.integer)); } - return quads; } /** diff --git a/src/util/QuadUtil.ts b/src/util/QuadUtil.ts index f432d82ff..bd706cd7f 100644 --- a/src/util/QuadUtil.ts +++ b/src/util/QuadUtil.ts @@ -1,32 +1,12 @@ import type { Readable } from 'stream'; import arrayifyStream from 'arrayify-stream'; import type { ParserOptions } from 'n3'; -import { DataFactory, StreamParser, StreamWriter } from 'n3'; -import type { Literal, NamedNode, Quad } from 'rdf-js'; +import { StreamParser, StreamWriter } from 'n3'; +import type { Quad } from 'rdf-js'; import streamifyArray from 'streamify-array'; import type { Guarded } from './GuardedStream'; import { pipeSafely } from './StreamUtil'; -import { toSubjectTerm, toPredicateTerm, toObjectTerm } from './TermUtil'; -/** - * Generates a quad with the given subject/predicate/object and pushes it to the given array. - */ -export function pushQuad( - quads: Quad[] | Readable, - subject: string | NamedNode, - predicate: string | NamedNode, - object: string | NamedNode | Literal, -): void { - quads.push(DataFactory.quad(toSubjectTerm(subject), toPredicateTerm(predicate), toObjectTerm(object))); -} - -/** - * Helper function for serializing an array of quads, with as result a Readable object. - * @param quads - The array of quads. - * @param contentType - The content-type to serialize to. - * - * @returns The Readable object. - */ export function serializeQuads(quads: Quad[], contentType?: string): Guarded { return pipeSafely(streamifyArray(quads), new StreamWriter({ format: contentType })); } diff --git a/src/util/ResourceUtil.ts b/src/util/ResourceUtil.ts index f461465fe..6a4d80607 100644 --- a/src/util/ResourceUtil.ts +++ b/src/util/ResourceUtil.ts @@ -1,29 +1,24 @@ import arrayifyStream from 'arrayify-stream'; -import type { NamedNode, Quad } from 'rdf-js'; import { BasicRepresentation } from '../ldp/representation/BasicRepresentation'; import type { Representation } from '../ldp/representation/Representation'; import { RepresentationMetadata } from '../ldp/representation/RepresentationMetadata'; -import { pushQuad } from './QuadUtil'; import { guardedStreamFrom } from './StreamUtil'; import { LDP, RDF } from './Vocabularies'; /** * Helper function to generate type quads for a Container or Resource. - * @param subject - Subject for the new quads. + * @param metadata - Metadata to add to. * @param isContainer - If the identifier corresponds to a container. * * @returns The generated quads. */ -export function generateResourceQuads(subject: NamedNode, isContainer: boolean): Quad[] { - const quads: Quad[] = []; +export function addResourceMetadata(metadata: RepresentationMetadata, isContainer: boolean): void { if (isContainer) { - pushQuad(quads, subject, RDF.terms.type, LDP.terms.Container); - pushQuad(quads, subject, RDF.terms.type, LDP.terms.BasicContainer); + metadata.add(RDF.terms.type, LDP.terms.Container); + metadata.add(RDF.terms.type, LDP.terms.BasicContainer); } - pushQuad(quads, subject, RDF.terms.type, LDP.terms.Resource); - - return quads; + metadata.add(RDF.terms.type, LDP.terms.Resource); } /** diff --git a/test/unit/util/QuadUtil.test.ts b/test/unit/util/QuadUtil.test.ts index d1e8d03b0..236b65c34 100644 --- a/test/unit/util/QuadUtil.test.ts +++ b/test/unit/util/QuadUtil.test.ts @@ -1,28 +1,9 @@ import 'jest-rdf'; import { literal, namedNode, quad } from '@rdfjs/data-model'; -import type { Quad } from 'rdf-js'; -import { parseQuads, pushQuad, serializeQuads } from '../../../src/util/QuadUtil'; +import { parseQuads, serializeQuads } from '../../../src/util/QuadUtil'; import { guardedStreamFrom, readableToString } from '../../../src/util/StreamUtil'; describe('QuadUtil', (): void => { - describe('#pushQuad', (): void => { - it('creates a quad and adds it to the given array.', async(): Promise => { - const quads: Quad[] = []; - pushQuad(quads, namedNode('sub'), namedNode('pred'), literal('obj')); - expect(quads).toEqualRdfQuadArray([ - quad(namedNode('sub'), namedNode('pred'), literal('obj')), - ]); - }); - - it('creates a quad from strings and adds it to the given array.', async(): Promise => { - const quads: Quad[] = []; - pushQuad(quads, 'sub', 'pred', 'obj'); - expect(quads).toEqualRdfQuadArray([ - quad(namedNode('sub'), namedNode('pred'), namedNode('obj')), - ]); - }); - }); - describe('#serializeQuads', (): void => { it('converts quads to the requested format.', async(): Promise => { const quads = [ quad(