@comunica/actor-init-query
Version:
A query init actor
175 lines • 7.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VoidMetadataEmitter = void 0;
const quad = require('rdf-quad');
/**
* A VoID metadata emitter that emits metadata used in VoID description of the HTTP service sparql endpoint.
*/
class VoidMetadataEmitter {
static STRING_LITERALS = new Set([
'alternative',
'description',
'title',
]);
static DATE_LITERALS = new Set([
'available',
'created',
'date',
'dateAccepted',
'dateCopyrighted',
'dateSubmitted',
'issued',
'modified',
'valid',
]);
context;
cachedStatistics = [];
constructor(context) {
this.context = context;
}
invalidateCache() {
this.cachedStatistics = [];
}
/**
* Returns a list of all necessary VoID quads.
* @param {QueryEngineBase} engine A SPARQL engine.
* @param {module:stream.internal.Writable} stdout
* @param {module:http.IncomingMessage} request
* @param {module:http.ServerResponse} response
*/
async getVoIDQuads(engine, stdout, request, response) {
const s = request.url;
const sd = 'http://www.w3.org/ns/sparql-service-description#';
const vd = 'http://rdfs.org/ns/void#';
const rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
const rdfType = `${rdf}type`;
const dataset = '_:defaultDataset';
const graph = '_:defaultGraph';
const vocabulary = `${vd}vocabulary`;
const dcterms = 'http://purl.org/dc/terms/';
const quads = [
quad(s, `${sd}defaultDataset`, dataset),
quad(dataset, rdfType, `${sd}Dataset`),
// Basic VoID metadata
quad(dataset, rdfType, `${vd}Dataset`),
quad(dataset, `${vd}sparqlEndpoint`, '/sparql'),
];
// Dublin Core Metadata Terms
if (this.context.dcterms) {
quads.push(quad(dataset, vocabulary, dcterms));
for (const key in this.context.dcterms) {
quads.push(quad(dataset, `${dcterms}${key}`, this.convertValue(key, this.context.dcterms[key])));
}
}
// Statistics
// Default graph for statistics
quads.push(quad(dataset, `${sd}defaultGraph`, graph));
quads.push(quad(graph, rdfType, `${sd}Graph`));
if (this.cachedStatistics.length === 0) {
try {
await this.fetchVoIDStatistics(engine);
}
catch (error) {
stdout.write(`[500] Server error in results: ${error.message} \n`);
response.end('An internal server error occurred.\n');
return [];
}
}
for (const q of this.cachedStatistics) {
quads.push(q);
}
return quads;
}
convertValue(key, value) {
if (VoidMetadataEmitter.STRING_LITERALS.has(key)) {
return `"${value}"`;
}
if (VoidMetadataEmitter.DATE_LITERALS.has(key)) {
return `"${value}"^^http://www.w3.org/2001/XMLSchema#date`;
}
return value;
}
/**
* Fetches the necessary VoID statistics quads and assigns them to this.cachedStatistics
* @param {QueryEngineBase} engine A SPARQL engine.
* @private
*/
async fetchVoIDStatistics(engine) {
const vd = 'http://rdfs.org/ns/void#';
const rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
const rdfType = `${rdf}type`;
const dataset = '_:defaultDataset';
const graph = '_:defaultGraph';
const [globalStatistics, classesStatistic, classPartitions, propertyPartitions] = await Promise.all([
engine.queryBindings(`
SELECT
(COUNT(*) AS ?triples)
(SUM(IF(isIRI(?s), 1, 0)) AS ?entities)
(COUNT(DISTINCT ?s) AS ?distinctSubjects)
(COUNT(DISTINCT ?p) AS ?properties)
(COUNT(DISTINCT ?o) AS ?distinctObjects)
WHERE {
?s ?p ?o
}
`, this.context),
engine.queryBindings(`
SELECT
(COUNT(DISTINCT ?c) AS ?classes)
WHERE {
?s a ?c
}
`, this.context),
engine.queryBindings(`
SELECT ?class (COUNT(*) AS ?count)
WHERE { ?s a ?class }
GROUP BY ?class
`, this.context),
engine.queryBindings(`
SELECT ?property (COUNT(*) AS ?count)
WHERE { ?s ?property ?o }
GROUP BY ?property
`, this.context),
]);
const xsdInteger = (n) => `"${n}"^^http://www.w3.org/2001/XMLSchema#integer`;
await Promise.all([
(async () => {
for await (const bindings of globalStatistics) {
this.cachedStatistics.push(quad(graph, `${vd}triples`, xsdInteger(bindings.get('triples').value)));
this.cachedStatistics.push(quad(graph, `${vd}entities`, xsdInteger(bindings.get('entities').value)));
this.cachedStatistics.push(quad(graph, `${vd}distinctSubjects`, xsdInteger(bindings.get('distinctSubjects').value)));
this.cachedStatistics.push(quad(graph, `${vd}properties`, xsdInteger(bindings.get('properties').value)));
this.cachedStatistics.push(quad(graph, `${vd}distinctObjects`, xsdInteger(bindings.get('distinctObjects').value)));
}
})(),
(async () => {
for await (const bindings of classesStatistic) {
this.cachedStatistics.push(quad(graph, `${vd}classes`, xsdInteger(bindings.get('classes').value)));
}
})(),
(async () => {
let i = 0;
for await (const bindings of classPartitions) {
const classPartition = `_:classPartition${i}`;
this.cachedStatistics.push(quad(dataset, `${vd}classPartition`, classPartition));
this.cachedStatistics.push(quad(classPartition, rdfType, `${vd}ClassPartition`));
this.cachedStatistics.push(quad(classPartition, `${vd}class`, bindings.get('class').value));
this.cachedStatistics.push(quad(classPartition, `${vd}entities`, xsdInteger(bindings.get('count').value)));
i++;
}
})(),
(async () => {
let i = 0;
for await (const bindings of propertyPartitions) {
const propertyPartition = `_:propertyPartition${i}`;
this.cachedStatistics.push(quad(dataset, `${vd}propertyPartition`, propertyPartition));
this.cachedStatistics.push(quad(propertyPartition, rdfType, `${vd}PropertyPartition`));
this.cachedStatistics.push(quad(propertyPartition, `${vd}property`, bindings.get('property').value));
this.cachedStatistics.push(quad(propertyPartition, `${vd}triples`, xsdInteger(bindings.get('count').value)));
i++;
}
})(),
]);
}
}
exports.VoidMetadataEmitter = VoidMetadataEmitter;
//# sourceMappingURL=VoidMetadataEmitter.js.map