UNPKG

@tpluscode/rdfine

Version:
215 lines (214 loc) 8.52 kB
import once from 'onetime'; import TypeCollectionCtor from './lib/TypeCollection.js'; import { toJSON } from './lib/toJSON.js'; import { fromInitializer } from './lib/resource.js'; import { mixins } from './lib/mixins.js'; export default class RdfResourceImpl { static { this.__mixins = []; } static { this.__properties = new Map(); } static { this.__initializers = new Map(); } static _userInitializeProperties(resource, init = {}) { Object.entries(init) .filter(([prop]) => prop !== 'id' && prop !== 'types') .forEach(([prop, value]) => { if (!prop.startsWith('http')) { // use decorated setter property if (typeof value === 'function') { resource[prop] = value(resource.pointer.any()); } else { resource[prop] = value; } return; } const values = Array.isArray(value) ? value : [value]; const pointers = values.map(function toPointer(value) { if (typeof value === 'function') { const result = value(resource.pointer.any()); if (typeof result === 'function') { throw new Error('Initializer factory function cannot return a function'); } if (Array.isArray(result)) { throw new Error('Initializer factory function cannot return an array'); } return toPointer(result); } if (typeof value === 'object' && 'term' in value) { return value.term; } if (typeof value === 'object' && 'pointer' in value) { return value.pointer; } if (typeof value === 'object' && 'termType' in value) { return resource.pointer.node(value); } let literal; if (typeof value === 'object' && 'value' in value && 'datatype' in value) { literal = resource.env.rdfine().convert.toLiteral(value.value, value.datatype); } else { literal = resource.env.rdfine().convert.toLiteral(value); } if (literal) { return resource.pointer.node(literal); } // create and initialize an object resource const childResource = fromInitializer(resource, value); return childResource.pointer; }); resource.pointer.addOut(resource.pointer.namedNode(prop), pointers); }); for (const type of init.types || []) { resource.types.add(type); } } constructor(pointer, parentOrEnv, init = {}) { this.__initialized = false; if (pointer.term.termType !== 'BlankNode' && pointer.term.termType !== 'NamedNode') { throw new Error(`RdfResource cannot be initialized from a ${pointer.term.termType} node`); } let parent; if ('id' in parentOrEnv) { parent = parentOrEnv; this.env = parent.env; } else { this.env = parentOrEnv; } /* TODO: when clownface gets graph feature if (pointer._context[0].graph) { this.pointer = pointer this.unionGraphPointer = pointer.fromGraph(null) } else { this.pointer = pointer.fromGraph(pointer.defaultGraph) this.unionGraphPointer = pointer } */ const selfGraph = this.env.clownface({ ...pointer, term: pointer.term, }); if (selfGraph._context[0].graph) { this.pointer = selfGraph; this.unionGraphPointer = this.env.clownface({ dataset: selfGraph.dataset, term: selfGraph.term, graph: undefined }); } else { this.pointer = this.env.clownface({ dataset: selfGraph.dataset, term: selfGraph.term, graph: this.env.defaultGraph() }); this.unionGraphPointer = this.env.clownface({ dataset: selfGraph.dataset, term: selfGraph.term }); } this.__initializeProperties = once(() => { const self = this; const defaults = [...mixins(self)].flatMap((mixinProto) => [...mixinProto.__initializers]); defaults.forEach(([key, value]) => { const currentValue = self[key]; const valueIsEmptyArray = Array.isArray(currentValue) && currentValue.length === 0; const valueIsUndefined = typeof currentValue === 'undefined'; if (!(valueIsEmptyArray || valueIsUndefined)) { return; } if (typeof value === 'function') { self[key] = value(self); return; } self[key] = value; }); return true; }); this._parent = parent; this.__initialized = this.__initializeProperties(); RdfResourceImpl._userInitializeProperties(this, init); } get id() { return this.pointer.term; } get _graphId() { return this.pointer._context[0].graph; } get types() { return new TypeCollectionCtor(this); } get isAnonymous() { return this.id.termType === 'BlankNode'; } hasType(type) { return this.types.has(type); } equals(other) { if (!other) { return false; } if ('termType' in other) { return this.id.equals(other); } const otherPointer = '_context' in other ? other : other.pointer; const idsEqual = this.id.equals(otherPointer.term); if (this.isAnonymous || otherPointer.term.termType === 'BlankNode') { return idsEqual && this.pointer.dataset === otherPointer.dataset; } return idsEqual; } get(property, options) { const objects = this.getArray(property, options); if (objects.length > 0) { return objects[0]; } return null; } getArray(property, options) { const values = this._getObjects(property, options) .filter(obj => obj.term.termType === 'NamedNode' || obj.term.termType === 'BlankNode') .map(obj => { return this._create(obj, [], { parent: this }); }); if (!values.length) { return []; } return values; } getNumber(property, options) { const [value] = this._getObjects(property, options).toArray(); if (typeof value === 'undefined') { return null; } if (value.term.termType === 'Literal') { return parseFloat(value.value); } throw new Error(`Expected property '${property}' to be a number but found '${value}'`); } getString(property, options) { const [value] = this._getObjects(property, options).toArray(); if (typeof value === 'undefined') { return null; } if (value.term.termType === 'Literal') { return value.value; } throw new Error(`Expected property '${property}' to be a literal but found '${value}'`); } getBoolean(property, options) { const [value] = this._getObjects(property, options).toArray(); if (typeof value === 'undefined') { return false; } if (value.term.termType === 'Literal' && this.env.ns.xsd.boolean.equals(value.term.datatype)) { return value.term.equals(this.pointer.literal(true).term); } throw new Error(`Expected property '${property}' to be a boolean but found '${value}'`); } _getObjects(property, { strict } = { strict: false }) { const propertyNode = typeof property === 'string' ? this.pointer.namedNode(property) : property; const objects = this.pointer.out(propertyNode); if (!objects.terms.length && strict) { throw new Error(`Value for predicate <${property}> was missing`); } return objects; } _create(term, mixins, options = {}) { return this.env.rdfine().factory.createEntity(term, mixins, options); } toJSON() { return toJSON(this); } } export function fromObject(initializer) { return initializer; }