UNPKG

rdf-stores

Version:

A TypeScript/JavaScript implementation of the RDF/JS store interface with support for quoted triples.

203 lines 7.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RdfStoreIndexNestedRecord = void 0; const OrderUtils_1 = require("../OrderUtils"); /** * An RDF store index that is implemented using nested records. */ class RdfStoreIndexNestedRecord { constructor(options) { this.features = { quotedTripleFiltering: false, }; this.dictionary = options.dictionary; this.nestedRecords = {}; } set(terms, value) { const map0 = this.nestedRecords; const map1 = map0[terms[0]] || (map0[terms[0]] = {}); const map2 = map1[terms[1]] || (map1[terms[1]] = {}); const map3 = map2[terms[2]] || (map2[terms[2]] = {}); if (map3[terms[3]]) { return false; } map3[terms[3]] = value; return true; } remove(terms) { const map0 = this.nestedRecords; const map1 = map0[terms[0]]; if (!map1) { return false; } const map2 = map1[terms[1]]; if (!map2) { return false; } const map3 = map2[terms[2]]; if (!map3) { return false; } if (!map3[terms[3]]) { return false; } delete map3[terms[3]]; // Clean up intermediate maps if (Object.keys(map3).length === 0) { delete map2[terms[2]]; if (Object.keys(map2).length === 0) { delete map1[terms[1]]; if (Object.keys(map1).length === 0) { delete map0[terms[0]]; } } } return true; } get(key) { const encoded = (0, OrderUtils_1.encodeOptionalTerms)(key, this.dictionary); // eslint-disable-next-line unicorn/no-useless-undefined if (!encoded || encoded.includes(undefined)) { return undefined; } return this.getEncoded(encoded); } getEncoded(ids) { return this.nestedRecords[ids[0]]?.[ids[1]]?.[ids[2]]?.[ids[3]]; } *find(terms) { const ids = (0, OrderUtils_1.encodeOptionalTerms)(terms, this.dictionary); if (!ids) { return; } const [id0, id1, id2, id3] = ids; const [term0, term1, term2, term3] = terms; let partialQuad0; let partialQuad1; let partialQuad2; let partialQuad3; let map1; let map2; let map3; const map0 = this.nestedRecords; const map0Keys = id0 !== undefined ? (id0 in map0 ? [id0] : []) : Object.keys(map0); for (const key1 of map0Keys) { map1 = map0[key1]; partialQuad0 = term0 || this.dictionary.decode(Number.parseInt(key1, 10)); const map1Keys = id1 !== undefined ? (id1 in map1 ? [id1] : []) : Object.keys(map1); for (const key2 of map1Keys) { map2 = map1[key2]; partialQuad1 = term1 || this.dictionary.decode(Number.parseInt(key2, 10)); const map2Keys = id2 !== undefined ? (id2 in map2 ? [id2] : []) : Object.keys(map2); for (const key3 of map2Keys) { map3 = map2[key3]; partialQuad2 = term2 || this.dictionary.decode(Number.parseInt(key3, 10)); const map3Keys = id3 !== undefined ? (id3 in map3 ? [id3] : []) : Object.keys(map3); for (const key4 of map3Keys) { partialQuad3 = term3 || this.dictionary.decode(Number.parseInt(key4, 10)); yield [partialQuad0, partialQuad1, partialQuad2, partialQuad3]; } } } } } // The code below is nearly identical. We duplicate because abstraction would result in a significant performance hit. *findEncoded(ids, terms) { const [id0, id1, id2, id3] = ids; let map1; let map2; let map3; const map0 = this.nestedRecords; const map0Keys = id0 !== undefined ? (id0 in map0 ? [id0] : []) : Object.keys(map0); for (const key1 of map0Keys) { map1 = map0[key1]; const map1Keys = id1 !== undefined ? (id1 in map1 ? [id1] : []) : Object.keys(map1); for (const key2 of map1Keys) { map2 = map1[key2]; const map2Keys = id2 !== undefined ? (id2 in map2 ? [id2] : []) : Object.keys(map2); for (const key3 of map2Keys) { map3 = map2[key3]; const map3Keys = id3 !== undefined ? (id3 in map3 ? [id3] : []) : Object.keys(map3); for (const key4 of map3Keys) { yield [ Number.parseInt(key1, 10), Number.parseInt(key2, 10), Number.parseInt(key3, 10), Number.parseInt(key4, 10), ]; } } } } } *findTermsInner(depth, map, matchTerms, partialResult) { if (matchTerms[depth]) { for (const [key1, subMap] of Object.entries(map)) { const newPartialResult = [...partialResult, Number.parseInt(key1, 10)]; yield* this.findTermsInner(depth + 1, subMap, matchTerms, newPartialResult); } } else if (depth < matchTerms.length) { for (const subMap of Object.values(map)) { yield* this.findTermsInner(depth + 1, subMap, matchTerms, partialResult); } } else { yield partialResult; } } findTerms(matchTerms) { return this.findTermsInner(0, this.nestedRecords, matchTerms, []); } count(terms) { let count = 0; const ids = (0, OrderUtils_1.encodeOptionalTerms)(terms, this.dictionary); if (!ids) { return 0; } const id0 = ids[0]; const id1 = ids[1]; const id2 = ids[2]; const id3 = ids[3]; let map1; let map2; let map3; const map0 = this.nestedRecords; const map0Keys = id0 !== undefined ? (id0 in map0 ? [id0] : []) : Object.keys(map0); for (const key1 of map0Keys) { map1 = map0[key1]; const map1Keys = id1 !== undefined ? (id1 in map1 ? [id1] : []) : Object.keys(map1); for (const key2 of map1Keys) { map2 = map1[key2]; const map2Keys = id2 !== undefined ? (id2 in map2 ? [id2] : []) : Object.keys(map2); for (const key3 of map2Keys) { map3 = map2[key3]; if (id3 !== undefined) { if (id3 in map3) { count++; } } else { count += Object.keys(map3).length; } } } } return count; } countTermsInner(depth, map, matchTerms) { if (depth === matchTerms.length - 1) { return Object.keys(map).length; } let count = 0; for (const subMap of Object.values(map)) { count += this.countTermsInner(depth + 1, subMap, matchTerms); } return count; } countTerms(matchTerms) { return this.countTermsInner(0, this.nestedRecords, matchTerms); } } exports.RdfStoreIndexNestedRecord = RdfStoreIndexNestedRecord; //# sourceMappingURL=RdfStoreIndexNestedRecord.js.map