@jahed/sparql-engine
Version:
SPARQL query engine for servers and web browsers.
69 lines • 2.87 kB
JavaScript
// SPDX-License-Identifier: MIT
import { isArray } from "lodash-es";
import { Pipeline } from "../engine/pipeline/pipeline.js";
import { Bindings } from "../rdf/bindings.js";
import { UNBOUND } from "../utils/rdf.js";
import { SPARQLExpression, } from "./expressions/sparql-expression.js";
/**
* Test if an object is an iterator that yields RDF Terms or null values
* @param obj - Input object
* @return True if the input obkect is an iterator, False otherwise
*/
function isIterable(obj) {
return Symbol.iterator in obj && typeof obj[Symbol.iterator] === "function";
}
/**
* Apply a SPARQL BIND clause
* @see {@link https://www.w3.org/TR/sparql11-query/#bind}
* @param source - Source {@link PipelineStage}
* @param variable - SPARQL variable used to bind results
* @param expression - SPARQL expression
* @return A {@link PipelineStage} which evaluate the BIND operation
*/
export default function bind(source, variable, expression, customFunctions) {
const expr = new SPARQLExpression(expression, customFunctions);
return Pipeline.getInstance().mergeMapAsync(source, async (bindings) => {
try {
const value = await expr.evaluate(bindings);
if (value && (isArray(value) || isIterable(value))) {
// build a source of bindings from the array/iterable produced by the expression's evaluation
return Pipeline.getInstance().fromAsync((input) => {
try {
for (let term of value) {
const mu = bindings.clone();
if (!term) {
mu.set(variable.value, UNBOUND);
}
else {
mu.set(variable.value, term);
}
input.next(mu);
}
}
catch (e) {
input.error(e);
}
input.complete();
});
}
else {
// simple case: bound the value to the given variable in the set of bindings
const res = bindings.clone();
// null values indicates that an error occurs during the expression's evaluation
// in this case, the variable is bind to a special UNBOUND value
if (!value) {
res.set(variable.value, UNBOUND);
}
else {
res.set(variable.value, value);
}
return Pipeline.getInstance().of(res);
}
}
catch (e) {
console.debug("internal bind() error", e);
}
return Pipeline.getInstance().empty();
});
}
//# sourceMappingURL=bind.js.map