alcaeus-model
Version:
rdfine models for Alcaeus, Hydra client
115 lines (114 loc) • 5.31 kB
JavaScript
import { hydra, rdf } from '@tpluscode/rdf-ns-builders';
import literal from 'rdf-literal';
import { createMixin } from '../Operation.js';
function only(termTypes = ['BlankNode', 'NamedNode', 'Literal']) {
return function (term) {
return termTypes.includes(term.term.termType);
};
}
function getObject(obj) {
if (obj.term.termType === 'BlankNode' || obj.term.termType === 'NamedNode') {
return this._create(obj, [], {
parent: this,
});
}
return literal.fromRdf(obj.term);
}
export function createHydraResourceMixin(env) {
function* getSupportedClasses(resource) {
for (const { root: docs } of env.hydra.apiDocumentations) {
if (!docs) {
continue;
}
const classes = docs.pointer.node(resource.out(rdf.type));
for (const clas of classes.toArray()) {
yield clas;
}
}
}
function HydraResourceMixin(base) {
return class extends base {
get operations() {
const classOperations = [...getSupportedClasses(this.pointer)]
.reduce((operations, clas) => [...operations, ...clas.out(hydra.supportedOperation).toArray()], []);
const propertyOperations = [...this.pointer.dataset.match(null, null, this.pointer.term)]
.reduce((operations, quad) => {
if (quad.subject.termType !== 'NamedNode') {
return operations;
}
return [...getSupportedClasses(this.pointer.namedNode(quad.subject))]
.reduce((operations, clas) => {
return [...operations, ...clas
.out(hydra.supportedProperty)
.has(hydra.property, quad.predicate)
.out(hydra.property)
.out(hydra.supportedOperation).toArray()];
}, operations);
}, []);
const supportedOperations = Array.prototype.concat.apply([], [...classOperations, ...propertyOperations]);
const operations = supportedOperations.reduce((map, pointer) => {
if (!map.has(pointer.term)) {
map.set(pointer.term, this._create(pointer, [createMixin(env.hydra, this)]));
}
return map;
}, env.termMap());
return [...operations.values()];
}
get apiDocumentation() {
const client = env.hydra;
const id = this.pointer.out(hydra.apiDocumentation).value ||
client.resources.get(this.pointer)?.response.apiDocumentationLink;
if (id) {
const idNode = env.namedNode(id);
const representation = client.apiDocumentations.find(apiDoc => apiDoc.root?.equals(idNode));
if (representation?.root) {
return representation.root;
}
}
return undefined;
}
getLinks(includeMissing = false) {
return this.getProperties({ termTypes: ['NamedNode'] })
.filter((tuple) => tuple.supportedProperty.property?.isLink)
.filter((tuple) => tuple.objects.length > 0 || includeMissing)
.map((tuple) => ({
resources: tuple.objects,
supportedProperty: tuple.supportedProperty,
}));
}
getProperties(options) {
const classProperties = [...getSupportedClasses(this.pointer)]
.reduce((operations, clas) => [...operations, ...clas.out(hydra.supportedProperty).toArray()], []);
const map = classProperties.reduce((current, supportedProperty) => {
const predicate = supportedProperty.out(hydra.property).toArray()[0];
if (predicate.term.termType !== 'NamedNode' || current.has(predicate.term)) {
return current;
}
const objects = this._getObjects(predicate.term)
.toArray()
.filter(only(options?.termTypes))
.map(getObject, this);
return current.set(predicate.term, {
objects,
supportedProperty: this._create(supportedProperty),
});
}, env.termMap());
return [...map.values()];
}
getCollections(filter) {
if (filter) {
return this.collection.filter((c) => {
const memberAssertions = [
...c.memberAssertion || [],
...c.manages || [],
];
return memberAssertions.find((assertion) => assertion.matches(filter));
});
}
return this.collection;
}
};
}
HydraResourceMixin.shouldApply = true;
return HydraResourceMixin;
}