@jahed/sparql-engine
Version:
SPARQL query engine for servers and web browsers.
68 lines • 3.08 kB
JavaScript
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