mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
fix: Take baseIRI into account when calling parseQuads
This commit is contained in:
parent
5995057240
commit
fea726ae7d
@ -219,6 +219,12 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
*/
|
*/
|
||||||
protected async writeData(identifier: ResourceIdentifier, representation: Representation, isContainer: boolean,
|
protected async writeData(identifier: ResourceIdentifier, representation: Representation, isContainer: boolean,
|
||||||
createContainers?: boolean): Promise<void> {
|
createContainers?: boolean): Promise<void> {
|
||||||
|
// Make sure the metadata has the correct identifier and correct type quads
|
||||||
|
// 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));
|
||||||
|
|
||||||
if (isContainer) {
|
if (isContainer) {
|
||||||
await this.handleContainerData(representation);
|
await this.handleContainerData(representation);
|
||||||
}
|
}
|
||||||
@ -228,11 +234,6 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
await this.createRecursiveContainers(this.identifierStrategy.getParentContainer(identifier));
|
await this.createRecursiveContainers(this.identifierStrategy.getParentContainer(identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the metadata has the correct identifier and correct type quads
|
|
||||||
const { metadata } = representation;
|
|
||||||
metadata.identifier = DataFactory.namedNode(identifier.path);
|
|
||||||
metadata.addQuads(generateResourceQuads(metadata.identifier, isContainer));
|
|
||||||
|
|
||||||
await (isContainer ?
|
await (isContainer ?
|
||||||
this.accessor.writeContainer(identifier, representation.metadata) :
|
this.accessor.writeContainer(identifier, representation.metadata) :
|
||||||
this.accessor.writeDocument(identifier, representation.data, representation.metadata));
|
this.accessor.writeDocument(identifier, representation.data, representation.metadata));
|
||||||
@ -251,7 +252,8 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
if (representation.metadata.contentType === INTERNAL_QUADS) {
|
if (representation.metadata.contentType === INTERNAL_QUADS) {
|
||||||
quads = await arrayifyStream(representation.data);
|
quads = await arrayifyStream(representation.data);
|
||||||
} else {
|
} else {
|
||||||
quads = await parseQuads(representation.data, representation.metadata.contentType);
|
const { contentType, identifier } = representation.metadata;
|
||||||
|
quads = await parseQuads(representation.data, { format: contentType, baseIRI: identifier.value });
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
@ -266,7 +266,7 @@ export class FileDataAccessor implements DataAccessor {
|
|||||||
await fsPromises.lstat(metadataLink.filePath);
|
await fsPromises.lstat(metadataLink.filePath);
|
||||||
|
|
||||||
const readMetadataStream = guardStream(createReadStream(metadataLink.filePath));
|
const readMetadataStream = guardStream(createReadStream(metadataLink.filePath));
|
||||||
return await parseQuads(readMetadataStream, metadataLink.contentType);
|
return await parseQuads(readMetadataStream, { format: metadataLink.contentType, baseIRI: identifier.path });
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
// Metadata file doesn't exist so lets keep `rawMetaData` an empty array.
|
// Metadata file doesn't exist so lets keep `rawMetaData` an empty array.
|
||||||
if (!isSystemError(error) || error.code !== 'ENOENT') {
|
if (!isSystemError(error) || error.code !== 'ENOENT') {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { Readable, PassThrough } from 'stream';
|
import type { Readable, PassThrough } from 'stream';
|
||||||
import arrayifyStream from 'arrayify-stream';
|
import arrayifyStream from 'arrayify-stream';
|
||||||
|
import type { ParserOptions } from 'n3';
|
||||||
import { DataFactory, StreamParser, StreamWriter } from 'n3';
|
import { DataFactory, StreamParser, StreamWriter } from 'n3';
|
||||||
import type { Literal, NamedNode, Quad } from 'rdf-js';
|
import type { Literal, NamedNode, Quad } from 'rdf-js';
|
||||||
import streamifyArray from 'streamify-array';
|
import streamifyArray from 'streamify-array';
|
||||||
@ -33,10 +34,10 @@ export function serializeQuads(quads: Quad[], contentType?: string): Guarded<Rea
|
|||||||
/**
|
/**
|
||||||
* Helper function to convert a Readable into an array of quads.
|
* Helper function to convert a Readable into an array of quads.
|
||||||
* @param readable - The readable object.
|
* @param readable - The readable object.
|
||||||
* @param contentType - The content-type of the stream.
|
* @param options - Options for the parser.
|
||||||
*
|
*
|
||||||
* @returns A promise containing the array of quads.
|
* @returns A promise containing the array of quads.
|
||||||
*/
|
*/
|
||||||
export async function parseQuads(readable: Guarded<Readable>, contentType?: string): Promise<Quad[]> {
|
export async function parseQuads(readable: Guarded<Readable>, options: ParserOptions = {}): Promise<Quad[]> {
|
||||||
return arrayifyStream(pipeSafely(readable, new StreamParser({ format: contentType })));
|
return arrayifyStream(pipeSafely(readable, new StreamParser(options)));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'jest-rdf';
|
import 'jest-rdf';
|
||||||
import type { Readable } from 'stream';
|
import type { Readable } from 'stream';
|
||||||
import arrayifyStream from 'arrayify-stream';
|
import arrayifyStream from 'arrayify-stream';
|
||||||
|
import type { Quad } from 'n3';
|
||||||
import { DataFactory } from 'n3';
|
import { DataFactory } from 'n3';
|
||||||
import type { Representation } from '../../../src/ldp/representation/Representation';
|
import type { Representation } from '../../../src/ldp/representation/Representation';
|
||||||
import { RepresentationMetadata } from '../../../src/ldp/representation/RepresentationMetadata';
|
import { RepresentationMetadata } from '../../../src/ldp/representation/RepresentationMetadata';
|
||||||
@ -187,13 +188,18 @@ describe('A DataAccessorBasedStore', (): void => {
|
|||||||
const resourceID = { path: root };
|
const resourceID = { path: root };
|
||||||
representation.metadata.add(RDF.type, LDP.terms.Container);
|
representation.metadata.add(RDF.type, LDP.terms.Container);
|
||||||
representation.metadata.contentType = 'text/turtle';
|
representation.metadata.contentType = 'text/turtle';
|
||||||
representation.data = guardedStreamFrom([ `<${`${root}resource/`}> a <coolContainer>.` ]);
|
representation.data = guardedStreamFrom([ '<> a <http://test.com/coolContainer>.' ]);
|
||||||
const result = await store.addResource(resourceID, representation);
|
const result = await store.addResource(resourceID, representation);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
path: expect.stringMatching(new RegExp(`^${root}[^/]+/$`, 'u')),
|
path: expect.stringMatching(new RegExp(`^${root}[^/]+/$`, 'u')),
|
||||||
});
|
});
|
||||||
expect(accessor.data[result.path]).toBeTruthy();
|
expect(accessor.data[result.path]).toBeTruthy();
|
||||||
expect(accessor.data[result.path].metadata.contentType).toBeUndefined();
|
expect(accessor.data[result.path].metadata.contentType).toBeUndefined();
|
||||||
|
|
||||||
|
const { data } = await store.getRepresentation(result);
|
||||||
|
const quads: Quad[] = await arrayifyStream(data);
|
||||||
|
expect(quads.some((entry): boolean => entry.subject.value === result.path &&
|
||||||
|
entry.object.value === 'http://test.com/coolContainer')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a URI based on the incoming slug.', async(): Promise<void> => {
|
it('creates a URI based on the incoming slug.', async(): Promise<void> => {
|
||||||
|
@ -128,13 +128,13 @@ describe('A FileDataAccessor', (): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('adds stored metadata when requesting metadata.', async(): Promise<void> => {
|
it('adds stored metadata when requesting metadata.', async(): Promise<void> => {
|
||||||
cache.data = { resource: 'data', 'resource.meta': '<this> <is> <metadata>.' };
|
cache.data = { resource: 'data', 'resource.meta': '<http://this> <http://is> <http://metadata>.' };
|
||||||
metadata = await accessor.getMetadata({ path: `${base}resource` });
|
metadata = await accessor.getMetadata({ path: `${base}resource` });
|
||||||
expect(metadata.quads().some((quad): boolean => quad.subject.value === 'this')).toBe(true);
|
expect(metadata.quads().some((quad): boolean => quad.subject.value === 'http://this')).toBe(true);
|
||||||
|
|
||||||
cache.data = { container: { '.meta': '<this> <is> <metadata>.' }};
|
cache.data = { container: { '.meta': '<http://this> <http://is> <http://metadata>.' }};
|
||||||
metadata = await accessor.getMetadata({ path: `${base}container/` });
|
metadata = await accessor.getMetadata({ path: `${base}container/` });
|
||||||
expect(metadata.quads().some((quad): boolean => quad.subject.value === 'this')).toBe(true);
|
expect(metadata.quads().some((quad): boolean => quad.subject.value === 'http://this')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws an error if there is a problem with the internal metadata.', async(): Promise<void> => {
|
it('throws an error if there is a problem with the internal metadata.', async(): Promise<void> => {
|
||||||
|
@ -36,9 +36,18 @@ describe('QuadUtil', (): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#parseQuads', (): void => {
|
describe('#parseQuads', (): void => {
|
||||||
it('parses quads from the requested format.', async(): Promise<void> => {
|
it('parses quads.', async(): Promise<void> => {
|
||||||
const stream = guardedStreamFrom([ '<pre:sub> <pre:pred> "obj".' ]);
|
const stream = guardedStreamFrom([ '<pre:sub> <pre:pred> "obj".' ]);
|
||||||
await expect(parseQuads(stream, 'application/n-triples')).resolves.toEqualRdfQuadArray([ quad(
|
await expect(parseQuads(stream)).resolves.toEqualRdfQuadArray([ quad(
|
||||||
|
namedNode('pre:sub'),
|
||||||
|
namedNode('pre:pred'),
|
||||||
|
literal('obj'),
|
||||||
|
) ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses quads with the given options.', async(): Promise<void> => {
|
||||||
|
const stream = guardedStreamFrom([ '<> <pre:pred> "obj".' ]);
|
||||||
|
await expect(parseQuads(stream, { baseIRI: 'pre:sub' })).resolves.toEqualRdfQuadArray([ quad(
|
||||||
namedNode('pre:sub'),
|
namedNode('pre:sub'),
|
||||||
namedNode('pre:pred'),
|
namedNode('pre:pred'),
|
||||||
literal('obj'),
|
literal('obj'),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user