UNPKG

@comunica/actor-abstract-path

Version:

An abstract actor for handling mediatypes

135 lines 5.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PathVariableObjectIterator = void 0; const utils_query_operation_1 = require("@comunica/utils-query-operation"); const asynciterator_1 = require("asynciterator"); const rdf_string_1 = require("rdf-string"); /** * An iterator that implements the multi-length property path operation (* and +) * for a fixed subject and predicate, and a variable object. */ class PathVariableObjectIterator extends asynciterator_1.BufferedIterator { constructor(algebraFactory, subject, predicate, graph, context, mediatorQueryOperation, emitFirstSubject, maxRunningOperations = 16) { super({ autoStart: false }); this.algebraFactory = algebraFactory; this.subject = subject; this.predicate = predicate; this.graph = graph; this.context = context; this.mediatorQueryOperation = mediatorQueryOperation; this.maxRunningOperations = maxRunningOperations; this.termHashes = new Map(); this.runningOperations = []; this.pendingOperations = []; this.started = false; // Push the subject as starting point this._push(this.subject, emitFirstSubject); } getProperty(propertyName, callback) { // Kickstart iterator when metadata is requested if (!this.started && propertyName === 'metadata') { this.startNextOperation(false) .catch(error => this.emit('error', error)); } return super.getProperty(propertyName, callback); } _end(destroy) { // Close all running iterators for (const it of this.runningOperations) { it.destroy(); } super._end(destroy); } _push(item, pushAsResult = true) { let termString; if (pushAsResult) { // Don't push if this subject was already found termString = (0, rdf_string_1.termToString)(item); if (this.termHashes.has(termString)) { return false; } } // Add a pending path operation for this item const variable = this.algebraFactory.dataFactory.variable('b'); this.pendingOperations.push({ variable, operation: this.algebraFactory.createPath(item, this.predicate, variable, this.graph), }); // Otherwise, push the subject if (termString) { this.termHashes.set(termString, item); super._push(item); } return true; } async startNextOperation(fillBuffer) { this.started = true; const pendingOperation = this.pendingOperations.pop(); const results = (0, utils_query_operation_1.getSafeBindings)(await this.mediatorQueryOperation.mediate({ operation: pendingOperation.operation, context: this.context })); const runningOperation = results.bindingsStream.map(bindings => bindings.get(pendingOperation.variable)); if (!runningOperation.done) { this.runningOperations.push(runningOperation); runningOperation.on('error', error => this.destroy(error)); runningOperation.on('readable', () => { if (fillBuffer) { this._fillBufferAsync(); } this.readable = true; }); runningOperation.on('end', () => { this.runningOperations.splice(this.runningOperations.indexOf(runningOperation), 1); if (fillBuffer) { this._fillBufferAsync(); } this.readable = true; }); } if (!this.getProperty('metadata')) { this.setProperty('metadata', results.metadata); } } _read(count, done) { // eslint-disable-next-line ts/no-this-alias const self = this; (async function () { // Open as many operations as possible while (self.runningOperations.length < self.maxRunningOperations) { if (self.pendingOperations.length === 0) { break; } await self.startNextOperation(true); } // Try to read `count` items (based on UnionIterator) let lastCount = 0; let item; let pushSucceeded = true; // eslint-disable-next-line no-cond-assign while (!pushSucceeded || lastCount !== (lastCount = count)) { pushSucceeded = true; // Prioritize the operations that have been added first for (let i = 0; i < self.runningOperations.length && count > 0; i++) { // eslint-disable-next-line no-cond-assign if ((item = self.runningOperations[i].read()) !== null) { if (self._push(item)) { count--; } else { pushSucceeded = false; } } } } // Close if everything has been read self.closeIfNeeded(); })().then(() => { done(); }, error => this.destroy(error)); } closeIfNeeded() { if (this.runningOperations.length === 0 && this.pendingOperations.length === 0) { this.close(); } } } exports.PathVariableObjectIterator = PathVariableObjectIterator; //# sourceMappingURL=PathVariableObjectIterator.js.map