import { drainStreams } from "./data.js";
/**
 * An implementation of FilterOutput that throws if push or filter is called.
 * It is used as the initial value for for an operator's output before it is
 * set.
 */
export const throwFilterOutput = {
    push(_change) {
        throw new Error('Output not set');
    },
    filter(_node, _cleanup) {
        throw new Error('Output not set');
    },
};
export class FilterStart {
    #input;
    #output = throwFilterOutput;
    constructor(input) {
        this.#input = input;
        input.setOutput(this);
    }
    setFilterOutput(output) {
        this.#output = output;
    }
    destroy() {
        this.#input.destroy();
    }
    getSchema() {
        return this.#input.getSchema();
    }
    push(change) {
        this.#output.push(change, this);
    }
    *fetch(req) {
        for (const node of this.#input.fetch(req)) {
            if (this.#output.filter(node, false)) {
                yield node;
            }
        }
    }
    *cleanup(req) {
        for (const node of this.#input.cleanup(req)) {
            if (this.#output.filter(node, true)) {
                yield node;
            }
            else {
                drainStreams(node);
            }
        }
    }
}
export class FilterEnd {
    #start;
    #input;
    #output = throwFilterOutput;
    constructor(start, input) {
        this.#start = start;
        this.#input = input;
        input.setFilterOutput(this);
    }
    *fetch(req) {
        for (const node of this.#start.fetch(req)) {
            yield node;
        }
    }
    *cleanup(req) {
        for (const node of this.#start.cleanup(req)) {
            yield node;
        }
    }
    filter(_node, _cleanup) {
        return true;
    }
    setOutput(output) {
        this.#output = output;
    }
    destroy() {
        this.#input.destroy();
    }
    getSchema() {
        return this.#input.getSchema();
    }
    push(change) {
        this.#output.push(change, this);
    }
}
export function buildFilterPipeline(input, delegate, pipeline) {
    const filterStart = new FilterStart(input);
    delegate.addEdge(input, filterStart);
    const middle = pipeline(filterStart);
    delegate.addEdge(filterStart, middle);
    const filterEnd = new FilterEnd(filterStart, middle);
    delegate.addEdge(middle, filterEnd);
    return filterEnd;
}
//# sourceMappingURL=filter-operators.js.map