UNPKG

flash-store

Version:

FlashStore is a Key-Value persistent storage with easy to use ES6 Map-like API(both Async and Sync support), powered by LevelDB and TypeScript.

410 lines 15.8 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } }; import * as path from 'path'; import { path as appRoot, } from 'app-root-path'; import rimraf from 'rimraf'; // import encoding from 'encoding-down' // import leveldown from 'leveldown' // import levelup from 'levelup' import level from 'level'; import { log, VERSION, } from './config'; export class FlashStore { /** * FlashStore is a Key-Value database tool and makes using leveldb more easy for Node.js * * Creates an instance of FlashStore. * @param {string} [workdir=path.join(appRoot, 'flash-store.workdir')] * @example * import { FlashStore } from 'flash-store' * const flashStore = new FlashStore('flashstore.workdir') */ constructor(workdir = path.join(appRoot, '.flash-store')) { this.workdir = workdir; log.verbose('FlashStore', 'constructor(%s)', workdir); // https://twitter.com/juliangruber/status/908688876381892608 // const encoded = encoding<K, V>( // leveldown(workdir), // { // // FIXME: issue #2 // valueEncoding: 'json', // }, // ) this.levelDb = level(workdir); // console.log((this.levelDb as any)._db.codec) this.levelDb.setMaxListeners(17); // default is Infinity } version() { return VERSION; } /** * Put data in database * * @param {K} key * @param {V} value * @returns {Promise<void>} * @example * await flashStore.put(1, 1) */ put(key, value) { return __awaiter(this, void 0, void 0, function* () { log.warn('FlashStore', '`put()` DEPRECATED. use `set()` instead.'); yield this.set(key, value); }); } set(key, value) { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'set(%s, %s) value type: %s', key, value, typeof value); // FIXME: issue #2 yield this.levelDb.put(key, JSON.stringify(value)); return this; }); } /** * Get value from database by key * * @param {K} key * @returns {(Promise<V | null>)} * @example * console.log(await flashStore.get(1)) */ get(key) { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'get(%s)', key); try { // FIXME: issue #2 return JSON.parse(yield this.levelDb.get(key)); } catch (e) { if (/^NotFoundError/.test(e)) { return undefined; } throw e; } }); } /** * Del data by key * * @param {K} key * @returns {Promise<void>} * @example * await flashStore.del(1) */ del(key) { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', '`del()` DEPRECATED. use `delete()` instead'); yield this.delete(key); }); } delete(key) { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'delete(%s)', key); yield this.levelDb.del(key); // TODO: `del` returns `true` or `false` return true; }); } /** * @typedef IteratorOptions * * @property { any } gt - Matches values that are greater than a specified value * @property { any } gte - Matches values that are greater than or equal to a specified value. * @property { any } lt - Matches values that are less than a specified value. * @property { any } lte - Matches values that are less than or equal to a specified value. * @property { boolean } reverse - Reverse the result set * @property { number } limit - Limits the number in the result set. * @property { any } prefix - Make the same prefix key get together. */ /** * Find keys by IteratorOptions * * @param {IteratorOptions} [options={}] * @returns {AsyncIterableIterator<K>} * @example * const flashStore = new FlashStore('flashstore.workdir') * for await(const key of flashStore.keys({gte: 1})) { * console.log(key) * } */ keys(options = {}) { return __asyncGenerator(this, arguments, function* keys_1() { var e_1, _a; log.verbose('FlashStore', 'keys()'); // options = Object.assign(options, { // keys : true, // values : false, // }) if (options.prefix) { if (options.gte || options.lte) { throw new Error('can not specify `prefix` with `gte`/`lte` together.'); } options.gte = options.prefix; options.lte = options.prefix + '\xff'; } try { for (var _b = __asyncValues(this.entries(options)), _c; _c = yield __await(_b.next()), !_c.done;) { const [key] = _c.value; yield yield __await(key); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield __await(_a.call(_b)); } finally { if (e_1) throw e_1.error; } } }); } /** * Find all values * * @returns {AsyncIterableIterator<V>} * @example * const flashStore = new FlashStore('flashstore.workdir') * for await(const value of flashStore.values()) { * console.log(value) * } */ values(options = {}) { return __asyncGenerator(this, arguments, function* values_1() { var e_2, _a; log.verbose('FlashStore', 'values()'); try { // options = Object.assign(options, { // keys : false, // values : true, // }) for (var _b = __asyncValues(this.entries(options)), _c; _c = yield __await(_b.next()), !_c.done;) { const [, value] = _c.value; yield yield __await(value); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield __await(_a.call(_b)); } finally { if (e_2) throw e_2.error; } } }); } /** * Get the counts of the database * @deprecated use property `size` instead * @returns {Promise<number>} * @example * const count = await flashStore.count() * console.log(`database count: ${count}`) */ count() { return __awaiter(this, void 0, void 0, function* () { log.warn('FlashStore', '`count()` DEPRECATED. use `size()` instead.'); const size = yield this.size; return size; }); } get size() { log.verbose('FlashStore', 'size()'); /* eslint no-async-promise-executor: 0 */ // TODO: is there a better way to count all items from the db? return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { var e_3, _a; try { let count = 0; try { for (var _b = __asyncValues(this), _c; _c = yield _b.next(), !_c.done;) { const _ = _c.value; count++; } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); } finally { if (e_3) throw e_3.error; } } resolve(count); } catch (e) { reject(e); } })); } /** * FIXME: use better way to do this */ has(key) { return __awaiter(this, void 0, void 0, function* () { const val = yield this.get(key); return !!val; }); } /** * TODO: use better way to do this with leveldb */ clear() { var e_4, _a; return __awaiter(this, void 0, void 0, function* () { try { for (var _b = __asyncValues(this.keys()), _c; _c = yield _b.next(), !_c.done;) { const key = _c.value; yield this.delete(key); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); } finally { if (e_4) throw e_4.error; } } }); } get [Symbol.toStringTag]() { return Promise.resolve('FlashStore'); } [Symbol.iterator]() { log.verbose('FlashStore', '[Symbol.iterator]()'); /** * Huan(202108): what is this??? * does it equals to `entries()`? */ return this.entries(); } /** * @private */ entries(options) { return __asyncGenerator(this, arguments, function* entries_1() { log.verbose('FlashStore', '*entries(%s)', JSON.stringify(options)); const iterator = this.levelDb.db.iterator(options); while (true) { const pair = yield __await(new Promise((resolve, reject) => { iterator.next(function (err, key, val) { if (err) { reject(err); } if (!key && !val) { return resolve(null); } if (val) { // FIXME: issue #2 val = JSON.parse(val); } return resolve([key, val]); }); })); if (!pair) { break; } yield yield __await(pair); } }); } [Symbol.asyncIterator]() { return __asyncGenerator(this, arguments, function* _a() { log.verbose('FlashStore', '*[Symbol.asyncIterator]()'); yield __await(yield* __asyncDelegator(__asyncValues(this.entries()))); }); } /** * @private */ streamAsyncIterator() { return __asyncGenerator(this, arguments, function* streamAsyncIterator_1() { log.warn('FlashStore', 'DEPRECATED *[Symbol.asyncIterator]()'); const readStream = this.levelDb.createReadStream(); const endPromise = new Promise((resolve, reject) => { readStream .once('end', () => resolve(false)) .once('error', reject); }); let pair; do { const dataPromise = new Promise(resolve => { readStream.once('data', (data) => resolve([data.key, data.value])); }); pair = yield __await(Promise.race([ dataPromise, endPromise, ])); if (pair) { yield yield __await(pair); } } while (pair); }); } forEach(callbackfn, thisArg) { var e_5, _a; return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'forEach()'); try { for (var _b = __asyncValues(this), _c; _c = yield _b.next(), !_c.done;) { const [key, value] = _c.value; callbackfn.call(thisArg, value, key, this); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); } finally { if (e_5) throw e_5.error; } } }); } close() { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'close()'); yield this.levelDb.close(); }); } /** * Destroy the database * * @returns {Promise<void>} */ destroy() { return __awaiter(this, void 0, void 0, function* () { log.verbose('FlashStore', 'destroy()'); yield this.levelDb.close(); yield new Promise(resolve => rimraf(this.workdir, resolve)); }); } } FlashStore.VERSION = VERSION; export default FlashStore; //# sourceMappingURL=flash-store.js.map