rdf-stores
Version:
A TypeScript/JavaScript implementation of the RDF/JS store interface with support for quoted triples.
203 lines • 7.61 kB
JavaScript
;
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