rdf-stores
Version:
A TypeScript/JavaScript implementation of the RDF/JS store interface with support for quoted triples.
183 lines • 8.63 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TermDictionaryQuotedIndexed = void 0;
const rdf_data_factory_1 = require("rdf-data-factory");
const RdfStoreIndexNestedMap_1 = require("../index/RdfStoreIndexNestedMap");
const OrderUtils_1 = require("../OrderUtils");
/**
* A term dictionary for quoted triples.
*
* Plain terms are stored in a regular dictionary.
* Quoted triples are stored separately using an index, which is backed the same dictionary.
*
* Finding quoted triples is done through indexed lookups.
*/
class TermDictionaryQuotedIndexed {
constructor(rawTermDictionary, dataFactory = new rdf_data_factory_1.DataFactory()) {
this.quotedTriplesDictionary = [];
this.features = { quotedTriples: true };
this.plainTermDictionary = rawTermDictionary;
const subIndexOpts = {
// Not required
indexCombinations: [],
// Not required
indexConstructor: undefined,
dictionary: this,
dataFactory,
};
this.quotedTriplesReverseDictionaries = [
new RdfStoreIndexNestedMap_1.RdfStoreIndexNestedMap(subIndexOpts),
new RdfStoreIndexNestedMap_1.RdfStoreIndexNestedMap(subIndexOpts),
new RdfStoreIndexNestedMap_1.RdfStoreIndexNestedMap(subIndexOpts),
];
this.dataFactory = dataFactory;
}
encode(term) {
if (term.termType === 'Quad') {
return this.encodeQuotedTriple(term, false);
}
return this.plainTermDictionary.encode(term);
}
encodeQuotedTriple(quad, optional) {
// Only quoted triples are supported
if (quad.graph.termType !== 'DefaultGraph') {
throw new Error('Encoding of quoted quads outside of the default graph is not allowed');
}
// Check if the quad was already encoded
const encodedTripleOptional = (0, OrderUtils_1.encodeOptionalTerms)([quad.subject, quad.predicate, quad.object, quad.graph], this);
const id = encodedTripleOptional && encodedTripleOptional.every(encoded => encoded !== undefined) ?
this.quotedTriplesReverseDictionaries[0].getEncoded(encodedTripleOptional) :
undefined;
// Return the encoding if we found one
if (id !== undefined || optional) {
// Mask MSB to indicate that the encoding should refer to the quoted triples dictionary.
return (id === undefined ? undefined : TermDictionaryQuotedIndexed.BITMASK | id);
}
// If the quad was not encoded yet, add a new entry for it in the dictionary.
const encodedTriple = [
this.encode(quad.subject),
this.encode(quad.predicate),
this.encode(quad.object),
];
const encodingBase = this.quotedTriplesDictionary.length + 1;
this.quotedTriplesDictionary.push(encodedTriple);
const encodedGraph = this.encode(this.dataFactory.defaultGraph());
this.quotedTriplesReverseDictionaries[0].set([
encodedTriple[0],
encodedTriple[1],
encodedTriple[2],
encodedGraph,
], encodingBase);
this.quotedTriplesReverseDictionaries[1].set([
encodedTriple[1],
encodedTriple[2],
encodedTriple[0],
encodedGraph,
], encodingBase);
this.quotedTriplesReverseDictionaries[2].set([
encodedTriple[2],
encodedTriple[0],
encodedTriple[1],
encodedGraph,
], encodingBase);
// Mask MSB to indicate that the encoding should refer to the quoted triples dictionary.
return TermDictionaryQuotedIndexed.BITMASK | encodingBase;
}
encodeOptional(term) {
if (term.termType === 'Quad') {
return this.encodeQuotedTriple(term, true);
}
return this.plainTermDictionary.encodeOptional(term);
}
decode(encoding) {
if (TermDictionaryQuotedIndexed.BITMASK & encoding) {
// Term comes from the quoted triples dictionary
const encodingBase = (~TermDictionaryQuotedIndexed.BITMASK & encoding) - 1;
if (encodingBase >= this.quotedTriplesDictionary.length) {
throw new Error(`The value ${encoding} is not present in the quoted triples range of the dictionary`);
}
const encodedTerms = this.quotedTriplesDictionary[encodingBase];
return this.dataFactory.quad(this.decode(encodedTerms[0]), this.decode(encodedTerms[1]), this.decode(encodedTerms[2]));
}
// Term comes from the plain terms dictionary
return this.plainTermDictionary.decode(encoding);
}
*encodings() {
for (const encoding of this.plainTermDictionary.encodings()) {
yield encoding;
}
for (const encoding of this.quotedTriplesDictionary.keys()) {
yield TermDictionaryQuotedIndexed.BITMASK | (1 + encoding);
}
}
*findQuotedTriples(quotedTriplePattern) {
for (const termEncoded of this.findQuotedTriplesEncoded(quotedTriplePattern)) {
yield this.decode(termEncoded);
}
}
*findQuotedTriplesEncoded(quotedTriplePattern) {
const [patternIn, requireQuotedTripleFiltering] = (0, OrderUtils_1.quadToPattern)(quotedTriplePattern.subject, quotedTriplePattern.predicate, quotedTriplePattern.object, quotedTriplePattern.graph, true);
// Find all matching terms iteratively
for (const termS of this.patternToIterable(patternIn[0])) {
for (const termP of this.patternToIterable(patternIn[1])) {
for (const termO of this.patternToIterable(patternIn[2])) {
for (const termG of this.patternToIterable(patternIn[3])) {
// Find all terms matching the pattern from the reverse indexes
// We select the reverse index according to the current triple pattern
if ((termS && termP) || (!termP && !termO)) {
// SPO
const pattern = [termS, termP, termO, termG];
for (const termEncoded of this.quotedTriplesReverseDictionaries[0].findEncoded(pattern, patternIn)) {
yield TermDictionaryQuotedIndexed.BITMASK |
this.quotedTriplesReverseDictionaries[0].getEncoded(termEncoded);
}
}
else if (!termS && termP) {
// POS
const pattern = [termP, termO, termS, termG];
for (const termEncoded of this.quotedTriplesReverseDictionaries[1].findEncoded(pattern, patternIn)) {
yield TermDictionaryQuotedIndexed.BITMASK |
this.quotedTriplesReverseDictionaries[1].getEncoded(termEncoded);
}
}
else {
// OSP
const pattern = [termO, termS, termP, termG];
for (const termEncoded of this.quotedTriplesReverseDictionaries[2].findEncoded(pattern, patternIn)) {
yield TermDictionaryQuotedIndexed.BITMASK |
this.quotedTriplesReverseDictionaries[2].getEncoded(termEncoded);
}
}
}
}
}
}
}
/**
* Helper function to convert a term to an iterator over encoded terms.
* @param patternTerm A term.
* @protected
*/
*patternToIterable(patternTerm) {
// If the term is another quoted quad, recursively find other quoted triples
if (patternTerm?.termType === 'Quad') {
yield* this.findQuotedTriplesEncoded(patternTerm);
return;
}
// Undefined terms indicate a variable
if (patternTerm === undefined) {
// eslint-disable-next-line unicorn/no-useless-undefined
yield undefined;
return;
}
// Defined terms indicate a precise match
const enc = this.encodeOptional(patternTerm);
if (enc === undefined) {
return;
}
yield enc;
}
}
exports.TermDictionaryQuotedIndexed = TermDictionaryQuotedIndexed;
TermDictionaryQuotedIndexed.BITMASK = 1 << 31;
//# sourceMappingURL=TermDictionaryQuotedIndexed.js.map