/**
 * Modified from bcoin's bdb (https://github.com/bcoin-org/bdb) (MIT LICENSE).
 * Credit to the original author, Christopher Jeffrey (https://github.com/chjj).
 */ import { AbstractIterator } from 'abstract-leveldown' ; import { Iterator , IteratorOptions , K , V , KV , DB , RangeEntry } from '../types' ; const defaultIteratorOptions = { reverse : false , limit : - 1 , keys : true , values : true , keyAsBuffer : true , valueAsBuffer : true , prefix : Buffer . from ( '' ) , } ; /**
 * Wrapper for an abstract-leveldown compliant iterator.
 */ export class BaseIterator implements Iterator { private readonly options : IteratorOptions ; private readonly prefix : Buffer ; private iterator : AbstractIterator < K , V > ; private finished : boolean ; constructor ( readonly db , options = { } ) { this . prefix = options . prefix || defaultIteratorOptions . prefix ; /**
         * Option values for iterators cannot be `null` or `undefined`.
         * We need to be careful not to set these values
         * accidentally or risk an error in the underlying DB.
         */ if ( options . gte !== undefined ) { options . gte = this . addPrefix ( options . gte ) ; } if ( options . lte !== undefined ) { options . lte = this . addPrefix ( options . lte ) ; } if ( options . gt !== undefined ) { options . gt = this . addPrefix ( options . gt ) ; } if ( options . lt !== undefined ) { options . lt = this . addPrefix ( options . lt ) ; } this . options = { ... defaultIteratorOptions , ... options , } ; } returns public async next ( ) { this . start ( ) ; const { key , value } = await new Promise < KV > ( ( resolve , reject ) => { this . iterator . next ( ( err , k , v ) => { if ( err ) { reject ( err ) ; return ; } resolve ( { key : k , value : v } ) ; } ) ; } ) ; if ( key === undefined && value === undefined ) { this . cleanup ( ) ; } return { key : this . removePrefix ( key ) , value } ; } param target public async seek ( target ) { this . start ( ) ; this . iterator . seek ( this . addPrefix ( target ) ) ; } param cb public async each ( cb ) { while ( ! this . finished ) { const { key , value } = await this . next ( ) ; if ( this . finished ) { return this . end ( ) ; } let result ; try { result = cb ( key , value ) ; if ( result instanceof Promise ) { result = await result ; } } catch ( err ) { await this . end ( ) ; throw err ; } if ( result === false ) { return this . end ( ) ; } } return this . end ( ) ; } returns public async items ( ) { const items = [ ] ; await this . each ( ( key , value ) => { return items . push ( { key , value , } ) ; } ) ; return items ; } returns public async keys ( ) { const items = await this . items ( ) ; return items . map ( ( item ) => { return item . key ; } ) ; } returns public async values ( ) { const items = await this . items ( ) ; return items . map ( ( item ) => { return item . value ; } ) ; } /**
     * Ends iteration and frees up resources.
     */ public async end ( ) { if ( ! this . iterator ) { try { this . start ( ) ; } catch ( err ) { throw err ; } } this . cleanup ( ) ; await new Promise < void > ( ( resolve , reject ) => { this . iterator . end ( ( err ) => { if ( err ) { reject ( err ) ; return ; } resolve ( ) ; } ) ; } ) ; } /**
     * Starts iteration by creating a snapshot.
     */ private start ( ) { if ( this . iterator !== undefined ) { return ; } this . iterator = this . db . db . iterator ( this . options ) ; } /**
     * Cleans up the iterator.
     */ private cleanup ( ) { this . finished = true ; } param value returns private addPrefix ( value ) { return value ? Buffer . concat ( [ this . prefix , value ] ) : value ; } param value returns private removePrefix ( value ) { return value ? value . slice ( this . prefix . length ) : value ; } } /**
 * A special purpose iterator which includes a nextRange() function that returns RangeEntrys instead of simple KVs.
 * This is used by the RangeBucket class.
 */ export class BaseRangeIterator extends BaseIterator { /**
     * Constructs a RangeIterator with a particular `resultToRange()` function that will transform
     * the it.next() result into a RangeEntry.
     */ constructor ( db , options = { } , readonly resultToRange ) { super ( db , options ) ; } returns public async nextRange ( ) { const res = await this . next ( ) ; if ( typeof res . key === 'undefined' ) { return ; } return this . resultToRange ( res ) ; } }