@comunica/actor-optimize-query-operation-query-source-skolemize
Version:
A query-source-skolemize optimize-query-operation actor
189 lines • 8.21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.deskolemizeOperation = exports.deskolemizeQuad = exports.deskolemizeTermNestedThrowing = exports.deskolemizeTerm = exports.skolemizeBindingsStream = exports.skolemizeQuadStream = exports.skolemizeBindings = exports.skolemizeQuad = exports.skolemizeTerm = exports.getSourceId = exports.SKOLEM_PREFIX = void 0;
const utils_algebra_1 = require("@comunica/utils-algebra");
const utils_data_factory_1 = require("@comunica/utils-data-factory");
const rdf_terms_1 = require("rdf-terms");
exports.SKOLEM_PREFIX = 'urn:comunica_skolem:source_';
/**
* Get the unique, deterministic id for the given source.
* @param sourceIds ID's of datasources, see KeysRdfResolveQuadPattern.sourceIds.
* @param source A data source.
* @return The id of the given source.
*/
function getSourceId(sourceIds, source) {
let sourceId = sourceIds.get(source.referenceValue);
if (sourceId === undefined) {
sourceId = `${sourceIds.size}`;
sourceIds.set(source.referenceValue, sourceId);
}
return sourceId;
}
exports.getSourceId = getSourceId;
/**
* If the given term is a blank node, return a deterministic named node for it
* based on the source id and the blank node value.
* @param dataFactory The data factory.
* @param term Any RDF term.
* @param sourceId A source identifier.
* @return If the given term was a blank node, this will return a skolemized named node, otherwise the original term.
*/
function skolemizeTerm(dataFactory, term, sourceId) {
if (term.termType === 'BlankNode') {
return new utils_data_factory_1.BlankNodeScoped(`bc_${sourceId}_${term.value}`, dataFactory.namedNode(`${exports.SKOLEM_PREFIX}${sourceId}:${term.value}`));
}
return term;
}
exports.skolemizeTerm = skolemizeTerm;
/**
* Skolemize all terms in the given quad.
* @param dataFactory The data factory.
* @param quad An RDF quad.
* @param sourceId A source identifier.
* @return The skolemized quad.
*/
function skolemizeQuad(dataFactory, quad, sourceId) {
return (0, rdf_terms_1.mapTermsNested)(quad, term => skolemizeTerm(dataFactory, term, sourceId));
}
exports.skolemizeQuad = skolemizeQuad;
/**
* Skolemize all terms in the given bindings.
* @param dataFactory The data factory.
* @param bindings An RDF bindings object.
* @param sourceId A source identifier.
* @return The skolemized bindings.
*/
function skolemizeBindings(dataFactory, bindings, sourceId) {
return bindings.map((term) => {
if (term.termType === 'Quad') {
return skolemizeQuad(dataFactory, term, sourceId);
}
return skolemizeTerm(dataFactory, term, sourceId);
});
}
exports.skolemizeBindings = skolemizeBindings;
/**
* Skolemize all terms in the given quad stream.
* @param dataFactory The data factory.
* @param iterator An RDF quad stream.
* @param sourceId A source identifier.
* @return The skolemized quad stream.
*/
function skolemizeQuadStream(dataFactory, iterator, sourceId) {
const ret = iterator.map(quad => skolemizeQuad(dataFactory, quad, sourceId));
function inheritMetadata() {
iterator.getProperty('metadata', (metadata) => {
ret.setProperty('metadata', metadata);
metadata.state.addInvalidateListener(inheritMetadata);
});
}
inheritMetadata();
return ret;
}
exports.skolemizeQuadStream = skolemizeQuadStream;
/**
* Skolemize all terms in the given bindings stream.
* @param dataFactory The data factory.
* @param iterator An RDF bindings stream.
* @param sourceId A source identifier.
* @return The skolemized bindings stream.
*/
function skolemizeBindingsStream(dataFactory, iterator, sourceId) {
const ret = iterator.map(bindings => skolemizeBindings(dataFactory, bindings, sourceId));
function inheritMetadata() {
iterator.getProperty('metadata', (metadata) => {
ret.setProperty('metadata', metadata);
metadata.state.addInvalidateListener(inheritMetadata);
});
}
inheritMetadata();
return ret;
}
exports.skolemizeBindingsStream = skolemizeBindingsStream;
/**
* If a given term was a skolemized named node for the given source id,
* deskolemize it again to a blank node.
* If the given term was a skolemized named node for another source, return false.
* If the given term was not a skolemized named node, return the original term.
* @param dataFactory The data factory.
* @param term Any RDF term.
* @param sourceId A source identifier.
*/
function deskolemizeTerm(dataFactory, term, sourceId) {
if (term.termType === 'BlankNode' && 'skolemized' in term) {
term = term.skolemized;
}
if (term.termType === 'NamedNode' && term.value.startsWith(exports.SKOLEM_PREFIX)) {
const colonSeparator = term.value.indexOf(':', exports.SKOLEM_PREFIX.length);
const termSourceId = term.value.slice(exports.SKOLEM_PREFIX.length, colonSeparator);
// We had a skolemized term
if (termSourceId === sourceId) {
// It came from the correct source
const termLabel = term.value.slice(colonSeparator + 1, term.value.length);
return dataFactory.blankNode(termLabel);
}
// It came from a different source
return null;
}
return term;
}
exports.deskolemizeTerm = deskolemizeTerm;
function deskolemizeTermNestedThrowing(dataFactory, term, sourceId) {
if (term.termType === 'Quad') {
return (0, rdf_terms_1.mapTermsNested)(term, (subTerm) => {
const deskolemized = deskolemizeTerm(dataFactory, subTerm, sourceId);
if (!deskolemized) {
throw new Error(`Skolemized term is not in scope for this source`);
}
return deskolemized;
});
}
const ret = deskolemizeTerm(dataFactory, term, sourceId);
if (ret === null) {
throw new Error(`Skolemized term is not in scope for this source`);
}
return ret;
}
exports.deskolemizeTermNestedThrowing = deskolemizeTermNestedThrowing;
/**
* Deskolemize all terms in the given quad.
* @param dataFactory The data factory.
* @param quad An RDF quad.
* @param sourceId A source identifier.
* @return The deskolemized quad.
*/
function deskolemizeQuad(dataFactory, quad, sourceId) {
return (0, rdf_terms_1.mapTermsNested)(quad, (term) => {
const newTerm = deskolemizeTerm(dataFactory, term, sourceId);
// If the term was skolemized in a different source then don't deskolemize it
return newTerm ?? term;
});
}
exports.deskolemizeQuad = deskolemizeQuad;
/**
* Deskolemize all terms in the given quad.
* Will return undefined if there is at least one blank node not in scope for this sourceId.
* @param dataFactory The data factory.
* @param operation An algebra operation.
* @param sourceId A source identifier.
*/
function deskolemizeOperation(dataFactory, operation, sourceId) {
const factory = new utils_algebra_1.AlgebraFactory();
try {
return utils_algebra_1.algebraUtils.mapOperation(operation, {
[utils_algebra_1.Algebra.Types.PATTERN]: {
preVisitor: () => ({ continue: false }),
transform: op => Object.assign(factory.createPattern(deskolemizeTermNestedThrowing(dataFactory, op.subject, sourceId), deskolemizeTermNestedThrowing(dataFactory, op.predicate, sourceId), deskolemizeTermNestedThrowing(dataFactory, op.object, sourceId), deskolemizeTermNestedThrowing(dataFactory, op.graph, sourceId)), { metadata: op.metadata }),
},
[utils_algebra_1.Algebra.Types.PATH]: {
preVisitor: () => ({ continue: false }),
transform: op => Object.assign(factory.createPath(deskolemizeTermNestedThrowing(dataFactory, op.subject, sourceId), op.predicate, deskolemizeTermNestedThrowing(dataFactory, op.object, sourceId), deskolemizeTermNestedThrowing(dataFactory, op.graph, sourceId)), { metadata: op.metadata }),
},
});
}
catch {
// Return undefined for skolemized terms not in scope for this source
}
}
exports.deskolemizeOperation = deskolemizeOperation;
//# sourceMappingURL=utils.js.map