UNPKG

@jahed/sparql-engine

Version:

SPARQL query engine for servers and web browsers.

68 lines 2.57 kB
// SPDX-License-Identifier: MIT import { sortedIndexOf } from "lodash-es"; import { termToString } from "rdf-string"; import { Pipeline } from "../engine/pipeline/pipeline.js"; import { Bindings } from "../rdf/bindings.js"; import { UNBOUND } from "../utils/rdf.js"; /** * Hash functions for set of bindings * @private * @param variables - SPARQL variables to hash * @param bindings - Set of bindings to hash * @return Hashed set of bindings */ function _hashBindings(variables, bindings) { // if no GROUP BY variables are used (in the case of an empty GROUP BY) // then we use a default grouping key if (variables.length === 0) { return "http://callidon.github.io/sparql-engine#DefaultGroupKey"; } return variables .map((v) => termToString(bindings.get(v) ?? UNBOUND)) .join(";"); } /** * Apply a SPARQL GROUP BY clause * @see {@link https://www.w3.org/TR/sparql11-query/#groupby} * @param source - Input {@link PipelineStage} * @param variables - GROUP BY variables * @return A {@link PipelineStage} which evaluate the GROUP BY operation */ export default function sparqlGroupBy(source, variables) { const groups = new Map(); const keys = new Map(); const engine = Pipeline.getInstance(); const groupVariables = variables.map((v) => v.value).sort(); let op = engine.map(source, (bindings) => { const key = _hashBindings(groupVariables, bindings); // create a new group is needed if (!groups.has(key)) { keys.set(key, bindings.filter((variable) => sortedIndexOf(groupVariables, variable) > -1)); groups.set(key, {}); } // parse each binding in the intermediate format used by SPARQL expressions // and insert it into the corresponding group bindings.forEach((variable, value) => { const group = groups.get(key); if (variable in group) { group[variable].push(value); } else { group[variable] = [value]; } }); return null; }); return engine.mergeMap(engine.collect(op), () => { const aggregates = []; // transform each group in a set of bindings groups.forEach((group, key) => { // also add the GROUP BY keys to the set of bindings const b = keys.get(key).clone(); b.setProperty("__aggregate", group); aggregates.push(b); }); return engine.from(aggregates); }); } //# sourceMappingURL=sparql-groupby.js.map