From 78e4911458371740f2c482c7b1907ec6c15d61d9 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Sun, 14 Aug 2022 09:04:39 +0100 Subject: [PATCH] fix: restore open options and support old level iterators (#132) --- src/index.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index b298da0..74ddaaa 100644 --- a/src/index.js +++ b/src/index.js @@ -22,7 +22,7 @@ import { Level } from 'level' export class LevelDatastore extends BaseDatastore { /** * @param {string | LevelDb} path - * @param {import('level').DatabaseOptions} [opts] + * @param {import('level').DatabaseOptions & import('level').OpenOptions} [opts] */ constructor (path, opts = {}) { super() @@ -35,11 +35,18 @@ export class LevelDatastore extends BaseDatastore { valueEncoding: 'view' }) : path + + /** @type {import('level').OpenOptions} */ + this.opts = { + createIfMissing: true, + compression: false, // same default as go + ...opts + } } async open () { try { - await this.db.open() + await this.db.open(this.opts) } catch (/** @type {any} */ err) { throw Errors.dbOpenFailedError(err) } @@ -211,7 +218,19 @@ export class LevelDatastore extends BaseDatastore { iteratorOpts.lt = prefix + '\xFF' } - return levelIteratorToIterator(this.db.iterator(iteratorOpts)) + const iterator = this.db.iterator(iteratorOpts) + + if (iterator[Symbol.asyncIterator]) { + return levelIteratorToIterator(iterator) + } + + // @ts-expect-error support older level + if (iterator.next != null && iterator.end != null) { + // @ts-expect-error support older level + return oldLevelIteratorToIterator(iterator) + } + + throw new Error('Level returned incompatible iterator') } } @@ -226,3 +245,40 @@ async function * levelIteratorToIterator (li) { await li.close() } + +/** + * @typedef {object} LevelIterator + * @property {(cb: (err: Error, key: string | Uint8Array | null, value: any)=> void)=>void} next + * @property {(cb: (err: Error) => void) => void } end + */ + +/** + * @param {LevelIterator} li - Level iterator + * @returns {AsyncIterable} + */ +function oldLevelIteratorToIterator (li) { + return { + [Symbol.asyncIterator] () { + return { + next: () => new Promise((resolve, reject) => { + li.next((err, key, value) => { + if (err) return reject(err) + if (key == null) { + return li.end(err => { + if (err) return reject(err) + resolve({ done: true, value: undefined }) + }) + } + resolve({ done: false, value: { key: new Key(key, false), value } }) + }) + }), + return: () => new Promise((resolve, reject) => { + li.end(err => { + if (err) return reject(err) + resolve({ done: true, value: undefined }) + }) + }) + } + } + } +}