UNPKG

@jahed/sparql-engine

Version:

SPARQL query engine for servers and web browsers.

68 lines 3.08 kB
import bind from "../../operators/bind.js"; import filter from "../../operators/sparql-filter.js"; import groupBy from "../../operators/sparql-groupby.js"; import { isVariable } from "../../utils/rdf.js"; import ExecutionContext from "../context/execution-context.js"; import StageBuilder from "./stage-builder.js"; /** * An AggregateStageBuilder handles the evaluation of Aggregations operations, * GROUP BY and HAVING clauses in SPARQL queries. * @see https://www.w3.org/TR/sparql11-query/#aggregates */ export default class AggregateStageBuilder extends StageBuilder { /** * Build a {@link PipelineStage} for the evaluation of SPARQL aggregations * @param source - Input {@link PipelineStage} * @param query - Parsed SPARQL query (logical execution plan) * @param options - Execution options * @return A {@link PipelineStage} which evaluate SPARQL aggregations */ async execute(source, query, context, customFunctions) { let iterator = source; // group bindings using the GROUP BY clause // WARNING: an empty GROUP BY clause will create a single group with all bindings iterator = this._executeGroupBy(source, ("group" in query && query.group) || [], context, customFunctions); // next, apply the optional HAVING clause to filter groups if ("having" in query) { iterator = this._executeHaving(iterator, query.having || [], context, customFunctions); } return iterator; } /** * Build a {@link PipelineStage} for the evaluation of a GROUP BY clause * @param source - Input {@link PipelineStage} * @param groupby - GROUP BY clause * @param options - Execution options * @return A {@link PipelineStage} which evaluate a GROUP BY clause */ _executeGroupBy(source, groupby, context, customFunctions) { let iterator = source; // extract GROUP By variables & rewrite SPARQL expressions into BIND clauses const groupingVars = []; groupby.forEach((g) => { if (isVariable(g.expression)) { groupingVars.push(g.expression); } else if (g.variable) { groupingVars.push(g.variable); iterator = bind(iterator, g.variable, g.expression, customFunctions); } }); return groupBy(iterator, groupingVars); } /** * Build a {@link PipelineStage} for the evaluation of a HAVING clause * @param source - Input {@link PipelineStage} * @param having - HAVING clause * @param options - Execution options * @return A {@link PipelineStage} which evaluate a HAVING clause */ _executeHaving(source, having, context, customFunctions) { // thanks to the flexibility of SPARQL expressions, // we can rewrite a HAVING clause in a set of FILTER clauses! return having.reduce((iter, expression) => { return filter(iter, expression, customFunctions); }, source); } } //# sourceMappingURL=aggregate-stage-builder.js.map