@netwerk-digitaal-erfgoed/ld-workbench
Version:
LDWorkbench is a Linked Data Transformation tool designed to use only SPARQL as transformation language.
104 lines • 3.89 kB
JavaScript
import EventEmitter from 'node:events';
import sparqljs from 'sparqljs';
import getEngine from './utils/getEngine.js';
import getEngineSource from './utils/getEngineSource.js';
import { BaseQuery } from './sparql.js';
const DEFAULT_LIMIT = 10;
export default class Iterator extends EventEmitter {
constructor(query, endpoint, delay = 0) {
super();
this.query = query;
this.endpoint = endpoint;
this.delay = delay;
this.offset = 0;
this.totalResults = 0;
this.engine = getEngine(this.endpoint);
}
async run() {
setTimeout(async () => {
let resultsPerPage = 0;
this.query.offset = this.offset;
try {
const stream = await this.engine.queryBindings(this.query.toString(), {
sources: [(this.source ?? (this.source = getEngineSource(this.endpoint)))],
});
stream.on('data', (binding) => {
resultsPerPage++;
if (!binding.has('this'))
throw new Error('Missing binding $this in the Iterator result.');
const $this = binding.get('this');
if ($this.termType !== 'NamedNode') {
throw new Error(`Binding $this in the Iterator result must be an Iri/NamedNode, but it is of type ${$this.termType}.`);
}
else {
this.emit('data', $this);
}
});
stream.on('end', () => {
this.totalResults += resultsPerPage;
if (this.totalResults === 0) {
this.emit('error', new IteratorError({
endpoint: this.endpoint,
query: this.query,
error: new Error('No results'),
}));
}
this.offset += this.query.limit;
if (resultsPerPage < this.query.limit) {
this.emit('end', this.totalResults);
}
else {
this.run();
}
});
stream.on('error', e => {
this.emit('error', new IteratorError({
error: e,
endpoint: this.endpoint,
query: this.query,
}));
});
}
catch (e) {
this.emit('error', new IteratorError({
error: e,
endpoint: this.endpoint,
query: this.query,
}));
}
}, this.delay);
}
}
export class Query extends BaseQuery {
static from(query, limit) {
const self = new Query(query);
self.query.limit = limit ?? self.query.limit ?? DEFAULT_LIMIT;
self.validate();
return self;
}
constructor(query) {
super(query);
this.query = query;
}
get limit() {
return this.query.limit;
}
set offset(offset) {
this.query.offset = offset;
}
validate() {
if (!this.query.variables.find(v => v instanceof sparqljs.Wildcard || v.value === 'this')) {
throw new Error('The SPARQL iterator query must select either a variable $this or a wildcard *');
}
}
}
export class IteratorError extends Error {
constructor(args) {
super(`Iterator failed: ${args.error.message} for endpoint ${args.endpoint.toString()} with query:\n${args.query.toString()}`, { cause: args.error });
this.context = {
endpoint: args.endpoint.toString(),
query: args.query.toString(),
};
}
}
//# sourceMappingURL=iterator.js.map