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