CommunitySolidServer/src/ldp/representation/RepresentationMetadata.ts
2020-09-16 12:10:42 +02:00

131 lines
3.9 KiB
TypeScript

import { quad as createQuad, literal, namedNode } from '@rdfjs/data-model';
import { Store } from 'n3';
import type { BlankNode, Literal, NamedNode, Quad, Term } from 'rdf-js';
/**
* Stores the metadata triples and provides methods for easy access.
*/
export class RepresentationMetadata {
private store: Store;
private id: NamedNode | BlankNode;
/**
* @param identifier - Identifier of the resource relevant to this metadata.
* A blank node will be generated if none is provided.
* Strings will be converted to named nodes. @ignored
* @param quads - Quads to fill the metadata with. @ignored
*
* `@ignored` tags are necessary for Components-Generator.js
*/
public constructor(identifier?: NamedNode | BlankNode | string, quads?: Quad[]) {
this.store = new Store(quads);
if (identifier) {
if (typeof identifier === 'string') {
this.id = namedNode(identifier);
} else {
this.id = identifier;
}
} else {
this.id = this.store.createBlankNode();
}
}
/**
* @returns All metadata quads.
*/
public quads(): Quad[] {
return this.store.getQuads(null, null, null, null);
}
/**
* Identifier of the resource this metadata is relevant to.
* Will update all relevant triples if this value gets changed.
*/
public get identifier(): NamedNode | BlankNode {
return this.id;
}
public set identifier(id: NamedNode | BlankNode) {
const quads = this.quads().map((quad): Quad => {
if (quad.subject.equals(this.id)) {
return createQuad(id, quad.predicate, quad.object, quad.graph);
}
if (quad.object.equals(this.id)) {
return createQuad(quad.subject, quad.predicate, id, quad.graph);
}
return quad;
});
this.store = new Store(quads);
this.id = id;
}
/**
* @param quads - Quads to add to the metadata.
*/
public addQuads(quads: Quad[]): void {
this.store.addQuads(quads);
}
/**
* @param quads - Quads to remove from the metadata.
*/
public removeQuads(quads: Quad[]): void {
this.store.removeQuads(quads);
}
/**
* Adds a value linked to the identifier. Strings get converted to literals.
* @param predicate - Predicate linking identifier to value.
* @param object - Value to add.
*/
public add(predicate: NamedNode, object: NamedNode | Literal | string): void {
this.store.addQuad(this.id, predicate, typeof object === 'string' ? literal(object) : object);
}
/**
* Removes the given value from the metadata. Strings get converted to literals.
* @param predicate - Predicate linking identifier to value.
* @param object - Value to remove.
*/
public remove(predicate: NamedNode, object: NamedNode | Literal | string): void {
this.store.removeQuad(this.id, predicate, typeof object === 'string' ? literal(object) : object);
}
/**
* Removes all values linked through the given predicate.
* @param predicate - Predicate to remove.
*/
public removeAll(predicate: NamedNode): void {
this.removeQuads(this.store.getQuads(this.id, predicate, null, null));
}
/**
* @param predicate - Predicate to get the value for.
*
* @throws Error
* If there are multiple matching values.
*
* @returns The corresponding value. Undefined if there is no match
*/
public get(predicate: NamedNode): Term | undefined {
const quads = this.store.getQuads(this.id, predicate, null, null);
if (quads.length === 0) {
return;
}
if (quads.length > 1) {
throw new Error(`Multiple results for ${predicate.value}`);
}
return quads[0].object;
}
/**
* Sets the value for the given predicate, removing all other instances.
* @param predicate - Predicate linking to the value.
* @param object - Value to set.
*/
public set(predicate: NamedNode, object: NamedNode | Literal | string): void {
this.removeAll(predicate);
this.add(predicate, object);
}
}