Add generic QuadToRdfConverter

This commit is contained in:
Ruben Taelman 2020-09-01 10:19:00 +02:00 committed by Joachim Van Herwegen
parent 4273c8bc04
commit 2c3ae4eded
7 changed files with 185 additions and 1 deletions

View File

@ -68,6 +68,12 @@ $ curl -H "Accept: text/turtle" \
http://localhost:3000/myfile.ttl
```
Retrieve a turtle file in a different serialization:
```bash
$ curl -H "Accept: application/ld+json" \
http://localhost:3000/myfile.ttl
```
### `DELETE`: Deleting resources
```bash

View File

@ -37,7 +37,7 @@
"@type": "RdfToQuadConverter"
},
{
"@type": "QuadToTurtleConverter"
"@type": "QuadToRdfConverter"
}
]
}

View File

@ -65,6 +65,7 @@ export * from './src/server/HttpRequest';
export * from './src/server/HttpResponse';
// Storage/Conversion
export * from './src/storage/conversion/QuadToRdfConverter';
export * from './src/storage/conversion/RdfToQuadConverter';
export * from './src/storage/conversion/QuadToTurtleConverter';
export * from './src/storage/conversion/RepresentationConverter';

64
package-lock.json generated
View File

@ -507,6 +507,25 @@
"rdfa-streaming-parser": "^1.1.1"
}
},
"@comunica/actor-rdf-serialize-jsonld": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@comunica/actor-rdf-serialize-jsonld/-/actor-rdf-serialize-jsonld-1.15.0.tgz",
"integrity": "sha512-+QeLhBWY9Ce0sNW6yDm7GoEdFNlMsQ01k71yBhaBRPhe/gYEbJc0chZAUoByCY0dJRqtfZK1Wc5gjfTrG/ctdQ==",
"requires": {
"jsonld-streaming-serializer": "^1.1.0"
}
},
"@comunica/actor-rdf-serialize-n3": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@comunica/actor-rdf-serialize-n3/-/actor-rdf-serialize-n3-1.15.0.tgz",
"integrity": "sha512-/9wY7o875w103A9a/SNpk65rFcp+bT3mSOnjV1bUnMVhvy73AsRG88uiwGUbS6GDFBPzA2j/l8OD+I4U3j6I7Q==",
"requires": {
"@types/n3": "^1.4.2",
"@types/rdf-js": "^3.0.0",
"n3": "^1.0.0",
"rdf-string": "^1.4.2"
}
},
"@comunica/bus-http": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/@comunica/bus-http/-/bus-http-1.16.0.tgz",
@ -545,6 +564,15 @@
"@types/rdf-js": "^3.0.0"
}
},
"@comunica/bus-rdf-serialize": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@comunica/bus-rdf-serialize/-/bus-rdf-serialize-1.15.0.tgz",
"integrity": "sha512-c1uJF1LkJ96zscMCe+CB2fLbXhlJ0o8PPVRMm3Jk7/rc8WY5bUxSxf1SFbA/jkOZtcZy59wFHDvPf/NM74ADBg==",
"requires": {
"@comunica/actor-abstract-mediatyped": "^1.15.0",
"@types/rdf-js": "^3.0.0"
}
},
"@comunica/core": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@comunica/core/-/core-1.15.0.tgz",
@ -6636,6 +6664,25 @@
"jsonparse": "^1.3.1"
}
},
"jsonld-streaming-serializer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsonld-streaming-serializer/-/jsonld-streaming-serializer-1.1.0.tgz",
"integrity": "sha512-C+cs913C3XDScZIqUL8fg5crHQtPTQSZstzvFmhA9/r0QBCRw88BR4TYHvLNhJhzB45GOpoF5/Fx4I4xfKGpOQ==",
"requires": {
"@types/rdf-js": "^2.0.1",
"jsonld-context-parser": "^2.0.0"
},
"dependencies": {
"@types/rdf-js": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/@types/rdf-js/-/rdf-js-2.0.12.tgz",
"integrity": "sha512-NBzHFHp2vHOJkPlSqzsOrkEsD9grKn+PdFjZieIw59pc0FlRG6WEQAjQZvHzFxJlYzC6ZDCFyTA1wBvUnnzUQw==",
"requires": {
"@types/node": "*"
}
}
}
},
"jsonparse": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
@ -7811,6 +7858,23 @@
"stream-to-string": "^1.2.0"
}
},
"rdf-serialize": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rdf-serialize/-/rdf-serialize-1.0.0.tgz",
"integrity": "sha512-5OZ7qAKKosAumdVMY7EccR9ICqBq90z78E5PuUMX2ThZ1ezkjQCKmqrJC/h3EfpPCdRbTsqwNGM+i6lYI3wQ3A==",
"requires": {
"@comunica/actor-rdf-serialize-jsonld": "~1.15.0",
"@comunica/actor-rdf-serialize-n3": "~1.15.0",
"@comunica/bus-init": "~1.15.0",
"@comunica/bus-rdf-serialize": "~1.15.0",
"@comunica/core": "~1.15.0",
"@comunica/mediator-combine-union": "~1.15.0",
"@comunica/mediator-number": "~1.15.0",
"@comunica/mediator-race": "~1.15.0",
"@types/rdf-js": "*",
"stream-to-string": "^1.2.0"
}
},
"rdf-string": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/rdf-string/-/rdf-string-1.4.2.tgz",

View File

@ -59,6 +59,7 @@
"mime-types": "^2.1.27",
"n3": "^1.4.0",
"rdf-parse": "^1.5.0",
"rdf-serialize": "^1.0.0",
"rdf-terms": "^1.5.1",
"sparqlalgebrajs": "^2.3.1",
"uuid": "^8.3.0",
@ -86,6 +87,7 @@
"node-mocks-http": "^1.8.1",
"nodemon": "^2.0.4",
"streamify-array": "^1.0.1",
"stream-to-string": "^1.1.0",
"supertest": "^4.0.2",
"ts-jest": "^26.0.0",
"typescript": "^3.9.2"

View File

@ -0,0 +1,31 @@
import { Readable } from 'stream';
import rdfSerializer from 'rdf-serialize';
import { Representation } from '../../ldp/representation/Representation';
import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata';
import { RepresentationPreferences } from '../../ldp/representation/RepresentationPreferences';
import { CONTENT_TYPE_QUADS, DATA_TYPE_BINARY } from '../../util/ContentTypes';
import { checkRequest, matchingTypes } from './ConversionUtil';
import { RepresentationConverter, RepresentationConverterArgs } from './RepresentationConverter';
/**
* Converts `internal/quads` to most major RDF serializations.
*/
export class QuadToRdfConverter extends RepresentationConverter {
public async canHandle(input: RepresentationConverterArgs): Promise<void> {
checkRequest(input, [ CONTENT_TYPE_QUADS ], await rdfSerializer.getContentTypes());
}
public async handle(input: RepresentationConverterArgs): Promise<Representation> {
return this.quadsToRdf(input.representation, input.preferences);
}
private async quadsToRdf(quads: Representation, preferences: RepresentationPreferences): Promise<Representation> {
const contentType = matchingTypes(preferences, await rdfSerializer.getContentTypes())[0].value;
const metadata: RepresentationMetadata = { ...quads.metadata, contentType };
return {
dataType: DATA_TYPE_BINARY,
data: rdfSerializer.serialize(quads.data, { contentType }) as Readable,
metadata,
};
}
}

View File

@ -0,0 +1,80 @@
import { namedNode, triple } from '@rdfjs/data-model';
import stringifyStream from 'stream-to-string';
import streamifyArray from 'streamify-array';
import { Representation } from '../../../../src/ldp/representation/Representation';
import { RepresentationPreferences } from '../../../../src/ldp/representation/RepresentationPreferences';
import { ResourceIdentifier } from '../../../../src/ldp/representation/ResourceIdentifier';
import { QuadToRdfConverter } from '../../../../src/storage/conversion/QuadToRdfConverter';
import { CONTENT_TYPE_QUADS, DATA_TYPE_BINARY } from '../../../../src/util/ContentTypes';
describe('A QuadToRdfConverter', (): void => {
const converter = new QuadToRdfConverter();
const identifier: ResourceIdentifier = { path: 'path' };
it('can handle quad to turtle conversions.', async(): Promise<void> => {
const representation = { metadata: { contentType: CONTENT_TYPE_QUADS }} as Representation;
const preferences: RepresentationPreferences = { type: [{ value: 'text/turtle', weight: 1 }]};
await expect(converter.canHandle({ identifier, representation, preferences })).resolves.toBeUndefined();
});
it('can handle quad to JSON-LD conversions.', async(): Promise<void> => {
const representation = { metadata: { contentType: CONTENT_TYPE_QUADS }} as Representation;
const preferences: RepresentationPreferences = { type: [{ value: 'application/ld+json', weight: 1 }]};
await expect(converter.canHandle({ identifier, representation, preferences })).resolves.toBeUndefined();
});
it('converts quads to turtle.', async(): Promise<void> => {
const representation = {
data: streamifyArray([ triple(
namedNode('http://test.com/s'),
namedNode('http://test.com/p'),
namedNode('http://test.com/o'),
) ]),
metadata: { contentType: CONTENT_TYPE_QUADS },
} as Representation;
const preferences: RepresentationPreferences = { type: [{ value: 'text/turtle', weight: 1 }]};
const result = await converter.handle({ identifier, representation, preferences });
expect(result).toMatchObject({
dataType: DATA_TYPE_BINARY,
metadata: {
contentType: 'text/turtle',
},
});
await expect(stringifyStream(result.data)).resolves.toEqual(
`<http://test.com/s> <http://test.com/p> <http://test.com/o>.
`,
);
});
it('converts quads to JSON-LD.', async(): Promise<void> => {
const representation = {
data: streamifyArray([ triple(
namedNode('http://test.com/s'),
namedNode('http://test.com/p'),
namedNode('http://test.com/o'),
) ]),
metadata: { contentType: CONTENT_TYPE_QUADS },
} as Representation;
const preferences: RepresentationPreferences = { type: [{ value: 'application/ld+json', weight: 1 }]};
const result = await converter.handle({ identifier, representation, preferences });
expect(result).toMatchObject({
dataType: DATA_TYPE_BINARY,
metadata: {
contentType: 'application/ld+json',
},
});
await expect(stringifyStream(result.data)).resolves.toEqual(
`[
{
"@id": "http://test.com/s",
"http://test.com/p": [
{
"@id": "http://test.com/o"
}
]
}
]
`,
);
});
});