@jahed/sparql-engine
Version:
SPARQL query engine for servers and web browsers.
99 lines • 3.51 kB
JavaScript
// SPDX-License-Identifier: MIT
import { isBoolean } from "lodash-es";
import { Pipeline } from "../engine/pipeline/pipeline.js";
import { BindingBase, Bindings } from "../rdf/bindings.js";
import { termIsBNode, termIsIRI, termIsLiteral } from "../utils/rdf.js";
/**
* Write the JSON headers
* @private
* @param bindings - Input bindings
* @param input - Output where to write results
*/
function writeHead(bindings, input) {
const variables = Array.from(bindings.variables())
.map((v) => (v.startsWith("?") ? `"${v.substring(1)}"` : `"${v}"`))
.join(",");
input.next(`"head":{"vars": [${variables}]}`);
}
/**
* Write a set of bindings as JSON
* @private
* @param bindings - Input bindings
* @param input - Output where to write results
*/
function writeBindings(bindings, input) {
let cpt = 0;
bindings.forEach((variable, value) => {
if (cpt >= 1) {
input.next(",");
}
input.next(`"${variable}":`);
const term = value;
if (termIsIRI(term)) {
input.next(`{"type":"uri","value":"${term.value}"}`);
}
else if (termIsBNode(term)) {
input.next(`{"type":"bnode","value":"${term.value}"}`);
}
else if (termIsLiteral(term)) {
if (term.language.length > 0) {
input.next(`{"type":"literal","value":"${term.value}","xml:lang":"${term.language}"}`);
}
else if (term.datatype) {
input.next(`{"type":"literal","value":"${term.value}","datatype":"${term.datatype.value}"}`);
}
else {
input.next(`{"type":"literal","value":"${term.value}"}`);
}
}
else {
input.error(`Invalid RDF term "${value}" encountered during JSON serialization`);
}
cpt++;
});
}
/**
* Formats query solutions (bindings or booleans) from a PipelineStage in W3C SPARQL JSON format
* @see https://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/
* @param source - Input pipeline
* @return A pipeline that yields results in W3C SPARQL JSON format
*/
export default function jsonFormat(source) {
return Pipeline.getInstance().fromAsync(async (input) => {
try {
input.next("{");
let cpt = 0;
let isAsk = false;
for await (const b of source) {
// Build the head attribute from the first set of bindings
if (cpt === 0 && b instanceof BindingBase) {
writeHead(b, input);
input.next(',"results": {"bindings": [');
}
else if (cpt === 0 && isBoolean(b)) {
isAsk = true;
input.next('"boolean":');
}
else if (cpt >= 1) {
input.next(",");
}
// handle results (boolean for ASK queries, bindings for SELECT queries)
if (isBoolean(b)) {
input.next(b ? "true" : "false");
}
else if (b instanceof BindingBase) {
input.next("{");
writeBindings(b, input);
input.next("}");
}
cpt++;
}
input.next(isAsk ? "}" : "]}}");
input.complete();
}
catch (error) {
console.error(error);
}
});
}
//# sourceMappingURL=json-formatter.js.map