UNPKG

2.72 kBJavaScriptView Raw
1'use strict';
2
3const EventEmitter = require('events');
4const JSONB = require('json-buffer');
5
6// eslint-disable-next-line no-extend-native
7BigInt.prototype.toJSON = function () {
8 return this.toString();
9};
10
11const loadStore = options => {
12 const adapters = {
13 redis: '@keyv/redis',
14 mongodb: '@keyv/mongo',
15 mongo: '@keyv/mongo',
16 sqlite: '@keyv/sqlite',
17 postgresql: '@keyv/postgres',
18 postgres: '@keyv/postgres',
19 mysql: '@keyv/mysql',
20 etcd: '@keyv/etcd',
21 };
22 if (options.adapter || options.uri) {
23 const adapter = options.adapter || /^[^:]*/.exec(options.uri)[0];
24 return new (require(adapters[adapter]))(options);
25 }
26
27 return new Map();
28};
29
30class Keyv extends EventEmitter {
31 constructor(uri, options) {
32 super();
33 this.opts = Object.assign(
34 {
35 namespace: 'keyv',
36 serialize: JSONB.stringify,
37 deserialize: JSONB.parse,
38 },
39 (typeof uri === 'string') ? { uri } : uri,
40 options,
41 );
42
43 if (!this.opts.store) {
44 const adapterOptions = Object.assign({}, this.opts);
45 this.opts.store = loadStore(adapterOptions);
46 }
47
48 if (typeof this.opts.store.on === 'function') {
49 this.opts.store.on('error', error => this.emit('error', error));
50 }
51
52 this.opts.store.namespace = this.opts.namespace;
53 }
54
55 _getKeyPrefix(key) {
56 return `${this.opts.namespace}:${key}`;
57 }
58
59 get(key, options) {
60 const keyPrefixed = this._getKeyPrefix(key);
61 const { store } = this.opts;
62 return Promise.resolve()
63 .then(() => store.get(keyPrefixed))
64 .then(data => (typeof data === 'string') ? this.opts.deserialize(data) : data)
65 .then(data => {
66 if (data === undefined || data === null) {
67 return undefined;
68 }
69
70 if (typeof data.expires === 'number' && Date.now() > data.expires) {
71 this.delete(key);
72 return undefined;
73 }
74
75 return (options && options.raw) ? data : data.value;
76 });
77 }
78
79 set(key, value, ttl) {
80 const keyPrefixed = this._getKeyPrefix(key);
81 if (typeof ttl === 'undefined') {
82 ttl = this.opts.ttl;
83 }
84
85 if (ttl === 0) {
86 ttl = undefined;
87 }
88
89 const { store } = this.opts;
90
91 return Promise.resolve()
92 .then(() => {
93 const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : null;
94 if (typeof value === 'symbol') {
95 this.emit('error', 'symbol cannot be serialized');
96 }
97
98 value = { value, expires };
99 return this.opts.serialize(value);
100 })
101 .then(value => store.set(keyPrefixed, value, ttl))
102 .then(() => true);
103 }
104
105 delete(key) {
106 const keyPrefixed = this._getKeyPrefix(key);
107 const { store } = this.opts;
108 return Promise.resolve()
109 .then(() => store.delete(keyPrefixed));
110 }
111
112 clear() {
113 const { store } = this.opts;
114 return Promise.resolve()
115 .then(() => store.clear());
116 }
117}
118
119module.exports = Keyv;