UNPKG

@ontola/memoized-factory

Version:

RDF Factory with neat memory usage and good cpu performance.

330 lines (269 loc) 8.1 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var core = require('@ontologies/core'); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } const rdflibQuadPatch = { get why() { return this.graph; } }; const rdfBase = factory => ({ equals(other) { return factory.equals.call(factory, this, other); }, /* rdflib compat */ /** @deprecated */ toCanonical() { return this; }, /** @deprecated */ toNT() { return factory.toNQ(this); }, /** @deprecated */ toString() { return factory.toNQ(this); }, /** @deprecated */ get uri() { return this.value; }, /** @deprecated */ set uri(uri) { this.value = uri; } }); const datatypes = { boolean: "http://www.w3.org/2001/XMLSchema#boolean", dateTime: "http://www.w3.org/2001/XMLSchema#dateTime", decimal: "http://www.w3.org/2001/XMLSchema#decimal", double: "http://www.w3.org/2001/XMLSchema#double", integer: "http://www.w3.org/2001/XMLSchema#integer", langString: "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", string: "http://www.w3.org/2001/XMLSchema#string" }; function createException(type, value) { const valueType = value && typeof value === "object" ? value.constructor : typeof value; return new TypeError(`Value of ${type} has to be type string, was value '${value}' of type '${valueType}'`); } /** * RDF DataFactory which stores every value once at most. * * This version uses hashing which might be more CPU consuming but has deterministic id creation. */ class MemoizedHashFactory extends core.PlainFactory { constructor(opts = {}) { super(_objectSpread2({ supports: MemoizedHashFactory.FactorySupport }, opts)); this.memoizationMap = {}; this.blankNodeMap = {}; this.namedNodeMap = {}; this.literalMap = {}; this.quadMap = {}; this.index = 1; this.bnIndex = opts.bnIndex || 1; this.base = rdfBase(this); } blankNode(value) { if (value && typeof value !== "string") { throw createException("BlankNode", value); } const usedValue = value || `_:b${++this.bnIndex}`; const mapId = this.mapId({ termType: "BlankNode", value: usedValue }); if (mapId && this.blankNodeMap[mapId]) { return this.blankNodeMap[mapId]; } const term = Object.create(this.base); term.termType = core.TermType.BlankNode; term.value = usedValue; term.id = this.index++; this.blankNodeMap[mapId] = term; this.memoizationMap[term.id] = term; return term; } namedNode(value) { if (typeof value !== "string") { throw createException("NamedNode", value); } const mapId = this.mapId({ termType: "NamedNode", value }); if (this.namedNodeMap[mapId]) { return this.namedNodeMap[mapId]; } const term = Object.create(this.base); term.termType = core.TermType.NamedNode; term.value = value; term.id = this.index++; this.namedNodeMap[mapId] = term; this.memoizationMap[term.id] = term; return term; } defaultGraph() { return this.namedNode("rdf:defaultGraph"); } literal(value, languageOrDatatype) { if (typeof value !== "string") { return this.parseLiteral(value); } const isLangString = typeof languageOrDatatype === "string"; const datatype = isLangString ? this.namedNode(datatypes.langString) : languageOrDatatype || this.namedNode(datatypes.string); if (datatype === undefined) { throw Error("datatype must be defined"); } const language = isLangString ? languageOrDatatype || "" : ""; const mapId = this.mapId({ termType: "Literal", value, datatype, language }); if (this.literalMap[mapId]) { return this.literalMap[mapId]; } const term = Object.create(this.base); term.termType = core.TermType.Literal; term.datatype = datatype; term.language = language; term.value = value; term.id = this.index++; this.literalMap[mapId] = term; this.memoizationMap[term.id] = term; return term; } quad(subject, predicate, object, graph) { const usedGraph = graph || this.defaultGraph(); const quadMapId = `${this.id(subject)},${this.id(predicate)},${this.id(object)},${graph ? this.id(graph) : 0}`; if (this.quadMap[quadMapId]) { return this.quadMap[quadMapId]; } const quad = Object.create(rdflibQuadPatch); quad.id = this.index++; quad.subject = subject; quad.predicate = predicate; quad.object = object; quad.graph = usedGraph; this.quadMap[quadMapId] = quad; this.memoizationMap[quad.id] = quad; return quad; } equals(a, b) { if (!a || !b) { return a === b; } if (Array.isArray(a) && Array.isArray(b)) { return this.id(a[0]) === this.id(b[0]) && this.id(a[1]) === this.id(b[1]) && this.id(a[2]) === this.id(b[2]) && this.id(a[3]) === this.id(b[3]); } return this.id(a) === this.id(b); } fromId(id) { return this.memoizationMap[id]; } id(term) { if (Array.isArray(term) || typeof term === "undefined") { return -1; } if (term.id) { return term.id; } const mapId = this.mapId(term); if (this.isQuad(term)) { const mapValue = this.quadMap[mapId]; return mapValue ? mapValue.id : this.index++; } switch (term.termType) { case core.TermType.BlankNode: { const mapValue = this.blankNodeMap[mapId]; return mapValue ? mapValue.id : this.index++; } case core.TermType.NamedNode: { const mapValue = this.namedNodeMap[mapId]; return mapValue ? mapValue.id : this.index++; } case core.TermType.Literal: { const mapValue = this.literalMap[mapId]; return mapValue ? mapValue.id : this.index++; } default: return -1; } } mapId(term) { if (this.isQuad(term)) { return `${this.id(term.subject)},${this.id(term.predicate)},${this.id(term.object)},${term.graph ? this.id(term.graph) : 0}`; } switch (term.termType) { case core.TermType.BlankNode: case core.TermType.NamedNode: return term.value; case core.TermType.Literal: { return `${term.value},${term.language},${term.datatype.value}`; } default: return undefined; } } } MemoizedHashFactory.FactorySupport = { [core.Feature.collections]: false, [core.Feature.defaultGraphType]: false, [core.Feature.equalsMethod]: false, [core.Feature.id]: true, [core.Feature.idStamp]: true, [core.Feature.identity]: true, [core.Feature.reversibleId]: true, [core.Feature.variableType]: false }; var index = new MemoizedHashFactory(); exports.MemoizedHashFactory = MemoizedHashFactory; exports.default = index; //# sourceMappingURL=index.js.map