@jahed/sparql-engine
Version:
SPARQL query engine for servers and web browsers.
83 lines • 3.67 kB
JavaScript
import { Wildcard } from "sparqljs";
import { isVariable } from "../../utils/rdf.js";
import ExecutionContext from "../context/execution-context.js";
import ContextSymbols from "../context/symbols.js";
import { Pipeline } from "../pipeline/pipeline.js";
import StageBuilder from "./stage-builder.js";
/**
* A GraphStageBuilder evaluates GRAPH clauses in a SPARQL query.
*/
export default class GraphStageBuilder extends StageBuilder {
/**
* Build a {@link PipelineStage} to evaluate a GRAPH clause
* @param source - Input {@link PipelineStage}
* @param node - Graph clause
* @param options - Execution options
* @return A {@link PipelineStage} used to evaluate a GRAPH clause
*/
async execute(source, node, context) {
let subquery;
if (node.patterns[0].type === "query") {
subquery = node.patterns[0];
}
else {
subquery = {
prefixes: context.getProperty(ContextSymbols.PREFIXES),
queryType: "SELECT",
variables: [new Wildcard()],
type: "query",
where: node.patterns,
};
}
// handle the case where the GRAPh IRI is a SPARQL variable
if (isVariable(node.name)) {
// clone the source first
source = Pipeline.getInstance().clone(source);
let namedGraphs = [];
// use named graphs is provided, otherwise use all named graphs
if (context.namedGraphs.length > 0) {
namedGraphs = context.namedGraphs;
}
else {
namedGraphs = [];
for await (const graph of this._dataset.getAllGraphs(true)) {
namedGraphs.push(graph.iri);
}
}
// build a pipeline stage that allows to peek on the first set of input bindings
return Pipeline.getInstance().peekIf(source, 1, (values) => {
return values[0].has(node.name.value);
}, async (values) => {
// if the input bindings bound the graph's variable, use it as graph IRI
const graphIRI = values[0].get(node.name.value);
return this._buildIterator(source, graphIRI, subquery, context);
}, async () => {
// otherwise, execute the subquery using each graph, and bound the graph var to the graph iri
const results = [];
for (const iri of namedGraphs) {
const stage = await this._buildIterator(source, iri, subquery, context);
results.push(Pipeline.getInstance().map(stage, (bindings) => {
return bindings.extendMany([[node.name.value, iri]]);
}));
}
return Pipeline.getInstance().merge(...results);
});
}
// otherwise, execute the subquery using the Graph
return this._buildIterator(source, node.name, subquery, context);
}
/**
* Returns a {@link PipelineStage} used to evaluate a GRAPH clause
* @param source - Input {@link PipelineStage}
* @param iri - IRI of the GRAPH clause
* @param subquery - Subquery to be evaluated
* @param options - Execution options
* @return A {@link PipelineStage} used to evaluate a GRAPH clause
*/
_buildIterator(source, iri, subquery, context) {
const opts = context.clone();
opts.defaultGraphs = [iri];
return this._builder._buildQueryPlan(subquery, opts, source);
}
}
//# sourceMappingURL=graph-stage-builder.js.map