rdf-stores
Version:
A TypeScript/JavaScript implementation of the RDF/JS store interface with support for quoted triples.
219 lines • 7.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RdfStoreIndexNestedMap = void 0;
const OrderUtils_1 = require("../OrderUtils");
/**
* An RDF store index that is implemented using nested Maps.
*/
class RdfStoreIndexNestedMap {
constructor(options) {
this.features = {
quotedTripleFiltering: false,
};
this.dictionary = options.dictionary;
this.nestedMap = new Map();
}
set(terms, value) {
const map0 = this.nestedMap;
let map1 = map0.get(terms[0]);
if (!map1) {
map1 = new Map();
map0.set(terms[0], map1);
}
let map2 = map1.get(terms[1]);
if (!map2) {
map2 = new Map();
map1.set(terms[1], map2);
}
let map3 = map2.get(terms[2]);
if (!map3) {
map3 = new Map();
map2.set(terms[2], map3);
}
const contained = map3.has(terms[3]);
if (!contained) {
map3.set(terms[3], value);
}
return !contained;
}
remove(terms) {
const map0 = this.nestedMap;
const map1 = map0.get(terms[0]);
if (!map1) {
return false;
}
const map2 = map1.get(terms[1]);
if (!map2) {
return false;
}
const map3 = map2.get(terms[2]);
if (!map3) {
return false;
}
const ret = map3.delete(terms[3]);
// Clean up intermediate maps
if (ret && map3.size === 0) {
map2.delete(terms[2]);
if (map2.size === 0) {
map1.delete(terms[1]);
if (map1.size === 0) {
map0.delete(terms[0]);
}
}
}
return ret;
}
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) {
const map1 = this.nestedMap.get(ids[0]);
if (!map1) {
return undefined;
}
const map2 = map1.get(ids[1]);
if (!map2) {
return undefined;
}
const map3 = map2.get(ids[2]);
if (!map3) {
return undefined;
}
return map3.get(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.nestedMap;
const map0Keys = id0 !== undefined ? (map0.has(id0) ? [id0] : []) : map0.keys();
for (const key1 of map0Keys) {
map1 = map0.get(key1);
partialQuad0 = term0 || this.dictionary.decode(key1);
const map1Keys = id1 !== undefined ? (map1.has(id1) ? [id1] : []) : map1.keys();
for (const key2 of map1Keys) {
map2 = map1.get(key2);
partialQuad1 = term1 || this.dictionary.decode(key2);
const map2Keys = id2 !== undefined ? (map2.has(id2) ? [id2] : []) : map2.keys();
for (const key3 of map2Keys) {
map3 = map2.get(key3);
partialQuad2 = term2 || this.dictionary.decode(key3);
const map3Keys = id3 !== undefined ? (map3.has(id3) ? [id3] : []) : map3.keys();
for (const key4 of map3Keys) {
partialQuad3 = term3 || this.dictionary.decode(key4);
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.nestedMap;
const map0Keys = id0 !== undefined ? (map0.has(id0) ? [id0] : []) : map0.keys();
for (const key1 of map0Keys) {
map1 = map0.get(key1);
const map1Keys = id1 !== undefined ? (map1.has(id1) ? [id1] : []) : map1.keys();
for (const key2 of map1Keys) {
map2 = map1.get(key2);
const map2Keys = id2 !== undefined ? (map2.has(id2) ? [id2] : []) : map2.keys();
for (const key3 of map2Keys) {
map3 = map2.get(key3);
const map3Keys = id3 !== undefined ? (map3.has(id3) ? [id3] : []) : map3.keys();
for (const key4 of map3Keys) {
yield [key1, key2, key3, key4];
}
}
}
}
}
*findTermsInner(depth, map, matchTerms, partialResult) {
if (matchTerms[depth]) {
for (const entry of map) {
const newPartialResult = [...partialResult, entry[0]];
yield* this.findTermsInner(depth + 1, entry[1], matchTerms, newPartialResult);
}
}
else if (depth < matchTerms.length) {
for (const subMap of map.values()) {
yield* this.findTermsInner(depth + 1, subMap, matchTerms, partialResult);
}
}
else {
yield partialResult;
}
}
findTerms(matchTerms) {
return this.findTermsInner(0, this.nestedMap, 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.nestedMap;
const map0Keys = id0 !== undefined ? (map0.has(id0) ? [id0] : []) : map0.keys();
for (const key1 of map0Keys) {
map1 = map0.get(key1);
const map1Keys = id1 !== undefined ? (map1.has(id1) ? [id1] : []) : map1.keys();
for (const key2 of map1Keys) {
map2 = map1.get(key2);
const map2Keys = id2 !== undefined ? (map2.has(id2) ? [id2] : []) : map2.keys();
for (const key3 of map2Keys) {
map3 = map2.get(key3);
if (id3 !== undefined) {
if (map3.has(id3)) {
count++;
}
}
else {
count += map3.size;
}
}
}
}
return count;
}
countTermsInner(depth, map, matchTerms) {
if (depth === matchTerms.length - 1) {
return map.size;
}
let count = 0;
for (const subMap of map.values()) {
count += this.countTermsInner(depth + 1, subMap, matchTerms);
}
return count;
}
countTerms(matchTerms) {
return this.countTermsInner(0, this.nestedMap, matchTerms);
}
}
exports.RdfStoreIndexNestedMap = RdfStoreIndexNestedMap;
//# sourceMappingURL=RdfStoreIndexNestedMap.js.map