rdf-stores
Version:
A TypeScript/JavaScript implementation of the RDF/JS store interface with support for quoted triples.
196 lines • 6.76 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RdfStoreIndexNestedMapRecursive = void 0;
const OrderUtils_1 = require("../OrderUtils");
/**
* An RDF store index that is implemented using nested Maps,
* and finds quads components via recursive methods calls.
*/
class RdfStoreIndexNestedMapRecursive {
constructor(options) {
this.features = {
quotedTripleFiltering: false,
};
this.dictionary = options.dictionary;
this.nestedMap = new Map();
}
set(terms, value) {
let map = this.nestedMap;
let contained = false;
for (const [i, term] of terms.entries()) {
const mapActual = map;
let nextMap = mapActual.get(term);
if (!nextMap) {
nextMap = i === terms.length - 1 ? value : new Map();
mapActual.set(term, nextMap);
}
else if (i === terms.length - 1) {
contained = true;
}
map = nextMap;
}
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;
}
for (const termsEncoded of this.findEncoded(ids, terms)) {
yield [
ids[0] !== undefined ? terms[0] : this.dictionary.decode(termsEncoded[0]),
ids[1] !== undefined ? terms[1] : this.dictionary.decode(termsEncoded[1]),
ids[2] !== undefined ? terms[2] : this.dictionary.decode(termsEncoded[2]),
ids[3] !== undefined ? terms[3] : this.dictionary.decode(termsEncoded[3]),
];
}
}
*findEncoded(ids, terms) {
return yield* this
.findEncodedInner(0, ids, terms, this.nestedMap, []);
}
*findEncodedInner(index, ids, terms, map, partialQuad) {
if (index === ids.length) {
yield [...partialQuad];
}
else {
const id = ids[index];
const currentTerm = terms[index];
// If current term is undefined, iterate over all terms at this level.
if (!currentTerm) {
for (const [key, subMap] of map.entries()) {
partialQuad[index] = key;
yield* this
.findEncodedInner(index + 1, ids, terms, subMap, partialQuad);
}
}
else {
// If the current term is defined, find one matching map for the current term.
const encodedTerm = id;
const subMap = map.get(encodedTerm);
if (subMap) {
partialQuad[index] = id;
yield* this
.findEncodedInner(index + 1, ids, terms, subMap, partialQuad);
}
}
}
}
*findTermsInner(depth, map, matchTerms, partialResult) {
if (matchTerms[depth]) {
for (const [key1, subMap] of map.entries()) {
const newPartialResult = [...partialResult, key1];
yield* this.findTermsInner(depth + 1, subMap, 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) {
return this.countInner(0, terms, this.nestedMap);
}
countInner(index, terms, map) {
const currentTerm = terms[index];
let count = 0;
// If current term is undefined, iterate over all terms at this level.
if (!currentTerm) {
if (index === terms.length - 1) {
return map.size;
}
for (const subMap of map.values()) {
count += this.countInner(index + 1, terms, subMap);
}
}
else {
// If the current term is defined, find one matching map for the current term.
const encodedTerm = this.dictionary.encodeOptional(currentTerm);
if (encodedTerm !== undefined) {
if (index === terms.length - 1) {
if (map.has(encodedTerm)) {
return 1;
}
return 0;
}
const subMap = map.get(encodedTerm);
if (subMap) {
count += this.countInner(index + 1, terms, subMap);
}
}
}
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.RdfStoreIndexNestedMapRecursive = RdfStoreIndexNestedMapRecursive;
//# sourceMappingURL=RdfStoreIndexNestedMapRecursive.js.map