'use strict' const { AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('../abstract-iterator') const ModuleError = require('module-error') const kNut = Symbol('nut') const kUndefer = Symbol('undefer') const kFactory = Symbol('factory') class DeferredIterator extends AbstractIterator { constructor (db, options) { super(db, options) this[kNut] = null this[kFactory] = () => db.iterator(options) this.db.defer(() => this[kUndefer]()) } } class DeferredKeyIterator extends AbstractKeyIterator { constructor (db, options) { super(db, options) this[kNut] = null this[kFactory] = () => db.keys(options) this.db.defer(() => this[kUndefer]()) } } class DeferredValueIterator extends AbstractValueIterator { constructor (db, options) { super(db, options) this[kNut] = null this[kFactory] = () => db.values(options) this.db.defer(() => this[kUndefer]()) } } for (const Iterator of [DeferredIterator, DeferredKeyIterator, DeferredValueIterator]) { Iterator.prototype[kUndefer] = function () { if (this.db.status === 'open') { this[kNut] = this[kFactory]() } } Iterator.prototype._next = function (callback) { if (this[kNut] !== null) { this[kNut].next(callback) } else if (this.db.status === 'opening') { this.db.defer(() => this._next(callback)) } else { this.nextTick(callback, new ModuleError('Iterator is not open: cannot call next() after close()', { code: 'LEVEL_ITERATOR_NOT_OPEN' })) } } Iterator.prototype._nextv = function (size, options, callback) { if (this[kNut] !== null) { this[kNut].nextv(size, options, callback) } else if (this.db.status === 'opening') { this.db.defer(() => this._nextv(size, options, callback)) } else { this.nextTick(callback, new ModuleError('Iterator is not open: cannot call nextv() after close()', { code: 'LEVEL_ITERATOR_NOT_OPEN' })) } } Iterator.prototype._all = function (options, callback) { if (this[kNut] !== null) { this[kNut].all(callback) } else if (this.db.status === 'opening') { this.db.defer(() => this._all(options, callback)) } else { this.nextTick(callback, new ModuleError('Iterator is not open: cannot call all() after close()', { code: 'LEVEL_ITERATOR_NOT_OPEN' })) } } Iterator.prototype._seek = function (target, options) { if (this[kNut] !== null) { // TODO: explain why we need _seek() rather than seek() here this[kNut]._seek(target, options) } else if (this.db.status === 'opening') { this.db.defer(() => this._seek(target, options)) } } Iterator.prototype._close = function (callback) { if (this[kNut] !== null) { this[kNut].close(callback) } else if (this.db.status === 'opening') { this.db.defer(() => this._close(callback)) } else { this.nextTick(callback) } } } exports.DeferredIterator = DeferredIterator exports.DeferredKeyIterator = DeferredKeyIterator exports.DeferredValueIterator = DeferredValueIterator