mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
Add generic QuadToRdfConverter
This commit is contained in:
parent
4273c8bc04
commit
2c3ae4eded
@ -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
|
||||
|
@ -37,7 +37,7 @@
|
||||
"@type": "RdfToQuadConverter"
|
||||
},
|
||||
{
|
||||
"@type": "QuadToTurtleConverter"
|
||||
"@type": "QuadToRdfConverter"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
1
index.ts
1
index.ts
@ -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
64
package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
31
src/storage/conversion/QuadToRdfConverter.ts
Normal file
31
src/storage/conversion/QuadToRdfConverter.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
80
test/unit/storage/conversion/QuadToRdfConverter.test.ts
Normal file
80
test/unit/storage/conversion/QuadToRdfConverter.test.ts
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
`,
|
||||
);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user