UNPKG

@keyvhq/core

Version:

Simple key-value storage with support for multiple backends

98 lines (81 loc) 2.67 kB
'use strict' const JSONB = require('json-buffer') class Keyv { constructor (options = {}) { Object.entries( Object.assign( { serialize: JSONB.stringify, deserialize: JSONB.parse, store: new Map() }, options ) ).forEach(([key, value]) => (this[key] = value)) const generateIterator = iterator => async function * () { for await (const [key, raw] of typeof iterator === 'function' ? iterator(this.namespace) : iterator) { const data = typeof raw === 'string' ? await this.deserialize(raw) : raw if (this.namespace && !key.includes(this.namespace)) { continue } if (typeof data.expires === 'number' && Date.now() > data.expires) { this.delete(key) continue } yield [this._getKeyUnprefix(key), data.value] } } // Attach iterators if ( typeof this.store[Symbol.iterator] === 'function' && this.store instanceof Map ) { this.iterator = generateIterator(this.store) } else if (typeof this.store.iterator === 'function') { this.iterator = generateIterator(this.store.iterator.bind(this.store)) } } _getKeyPrefix (key) { return this.namespace ? `${this.namespace}:${key}` : (key && key.toString()) || key } _getKeyUnprefix (key) { return this.namespace ? key.split(':').splice(1).join(':') : key } async get (key, { raw: asRaw = false } = {}) { const raw = await this.store.get(this._getKeyPrefix(key)) if (raw === undefined) return undefined const data = typeof raw === 'string' ? await this.deserialize(raw) : raw if (typeof data.expires === 'number' && Date.now() > data.expires) { this.delete(key) return undefined } return asRaw ? data : data.value } async has (key) { return typeof this.store.has === 'function' ? this.store.has(this._getKeyPrefix(key)) : (await this.store.get(this._getKeyPrefix(key))) !== undefined } async set (key, value, ttl) { if (value === undefined) return false if (ttl === undefined) ttl = this.ttl if (ttl === 0) ttl = undefined const expires = typeof ttl === 'number' ? Date.now() + ttl : null const valueSerialized = await this.serialize({ value, expires }) await this.store.set(this._getKeyPrefix(key), valueSerialized, ttl) return true } async delete (key) { return this.store.delete(this._getKeyPrefix(key)) } async clear (options) { return this.store.clear(this.namespace, options) } } module.exports = Keyv