Comparing version 4.1.1 to 4.2.0
102
package.json
{ | ||
"name": "keyv", | ||
"version": "4.1.1", | ||
"description": "Simple key-value storage with support for multiple backends", | ||
"main": "src/index.js", | ||
"scripts": { | ||
"test": "xo && nyc ava --serial", | ||
"coverage": "nyc report --reporter=text-lcov > coverage.lcov", | ||
"clean": "rm -rf node_modules && rm -rf .nyc_output && rm -rf coverage.lcov && rm -rf ./test/testdb.sqlite" | ||
}, | ||
"xo": { | ||
"extends": "xo-lukechilds", | ||
"rules": { | ||
"unicorn/prefer-module": 0 | ||
} | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/jaredwray/keyv.git" | ||
}, | ||
"keywords": [ | ||
"key", | ||
"value", | ||
"store", | ||
"cache", | ||
"ttl" | ||
], | ||
"author": "Jared Wray <me@jaredwray.com> (http://jaredwray.com)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/jaredwray/keyv/issues" | ||
}, | ||
"homepage": "https://github.com/jaredwray/keyv", | ||
"dependencies": { | ||
"json-buffer": "3.0.1" | ||
}, | ||
"devDependencies": { | ||
"@keyv/test-suite": "*", | ||
"ava": "^4.0.1", | ||
"eslint-config-xo-lukechilds": "^1.0.1", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"nyc": "^15.1.0", | ||
"pify": "5.0.0", | ||
"this": "^1.1.0", | ||
"timekeeper": "^2.2.0", | ||
"xo": "^0.47.0" | ||
} | ||
"name": "keyv", | ||
"version": "4.2.0", | ||
"description": "Simple key-value storage with support for multiple backends", | ||
"main": "src/index.js", | ||
"scripts": { | ||
"test": "xo && nyc ava --serial", | ||
"coverage": "nyc report --reporter=text-lcov > coverage.lcov", | ||
"clean": "rm -rf node_modules && rm -rf .nyc_output && rm -rf coverage.lcov && rm -rf ./test/testdb.sqlite" | ||
}, | ||
"xo": { | ||
"extends": "xo-lukechilds", | ||
"rules": { | ||
"unicorn/prefer-module": 0 | ||
} | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/jaredwray/keyv.git" | ||
}, | ||
"keywords": [ | ||
"key", | ||
"value", | ||
"store", | ||
"cache", | ||
"ttl" | ||
], | ||
"author": "Jared Wray <me@jaredwray.com> (http://jaredwray.com)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/jaredwray/keyv/issues" | ||
}, | ||
"homepage": "https://github.com/jaredwray/keyv", | ||
"dependencies": { | ||
"compress-brotli": "^1.3.6", | ||
"json-buffer": "3.0.1" | ||
}, | ||
"devDependencies": { | ||
"@keyv/test-suite": "*", | ||
"ava": "^4.1.0", | ||
"eslint-config-xo-lukechilds": "^1.0.1", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"nyc": "^15.1.0", | ||
"pify": "5.0.0", | ||
"this": "^1.1.0", | ||
"timekeeper": "^2.2.0", | ||
"tsd": "^0.20.0", | ||
"typescript": "^4.6.3", | ||
"xo": "^0.48.0" | ||
}, | ||
"tsd" : { | ||
"directory" : "test" | ||
}, | ||
"types": "./src/index.d.ts", | ||
"files": [ | ||
"src" | ||
] | ||
} |
185
src/index.js
@@ -5,8 +5,4 @@ 'use strict'; | ||
const JSONB = require('json-buffer'); | ||
const compressBrotli = require('compress-brotli'); | ||
// eslint-disable-next-line no-extend-native | ||
BigInt.prototype.toJSON = function () { | ||
return this.toString(); | ||
}; | ||
const loadStore = options => { | ||
@@ -31,20 +27,35 @@ const adapters = { | ||
const iterableAdapters = [ | ||
'sqlite', | ||
'postgres', | ||
'mysql', | ||
'mongo', | ||
'redis', | ||
]; | ||
class Keyv extends EventEmitter { | ||
constructor(uri, options) { | ||
super(); | ||
this.opts = Object.assign( | ||
{ | ||
namespace: 'keyv', | ||
serialize: JSONB.stringify, | ||
deserialize: JSONB.parse, | ||
}, | ||
(typeof uri === 'string') ? { uri } : uri, | ||
options, | ||
); | ||
this.opts = { | ||
namespace: 'keyv', | ||
serialize: JSONB.stringify, | ||
deserialize: JSONB.parse, | ||
...((typeof uri === 'string') ? { uri } : uri), | ||
...options, | ||
}; | ||
if (!this.opts.store) { | ||
const adapterOptions = Object.assign({}, this.opts); | ||
const adapterOptions = { ...this.opts }; | ||
this.opts.store = loadStore(adapterOptions); | ||
} | ||
if (this.opts.compress) { | ||
const brotli = compressBrotli(this.opts.compress.opts); | ||
this.opts.serialize = async ({ value, expires }) => brotli.serialize({ value: await brotli.compress(value), expires }); | ||
this.opts.deserialize = async data => { | ||
const { value, expires } = brotli.deserialize(data); | ||
return { value: await brotli.decompress(value), expires }; | ||
}; | ||
} | ||
if (typeof this.opts.store.on === 'function') { | ||
@@ -55,4 +66,36 @@ this.opts.store.on('error', error => this.emit('error', error)); | ||
this.opts.store.namespace = this.opts.namespace; | ||
const generateIterator = iterator => | ||
async function * () { | ||
for await (const [key, raw] of typeof iterator === 'function' | ||
? iterator(this.opts.store.namespace) | ||
: iterator) { | ||
const data = typeof raw === 'string' ? this.opts.deserialize(raw) : raw; | ||
if (this.opts.store.namespace && !key.includes(this.opts.store.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.opts.store[Symbol.iterator] === 'function' && this.opts.store instanceof Map) { | ||
this.iterator = generateIterator(this.opts.store); | ||
} else if (typeof this.opts.store.iterator === 'function' && this.opts.store.opts | ||
&& this._checkIterableAdaptar()) { | ||
this.iterator = generateIterator(this.opts.store.iterator.bind(this.opts.store)); | ||
} | ||
} | ||
_checkIterableAdaptar() { | ||
return iterableAdapters.includes(this.opts.store.opts.dialect) | ||
|| iterableAdapters.findIndex(element => this.opts.store.opts.url.includes(element)) >= 0; | ||
} | ||
_getKeyPrefix(key) { | ||
@@ -62,9 +105,55 @@ return `${this.opts.namespace}:${key}`; | ||
_getKeyPrefixArray(keys) { | ||
return keys.map(key => `${this.opts.namespace}:${key}`); | ||
} | ||
_getKeyUnprefix(key) { | ||
return this.opts.store.namespace | ||
? key | ||
.split(':') | ||
.splice(1) | ||
.join(':') | ||
: key; | ||
} | ||
get(key, options) { | ||
const keyPrefixed = this._getKeyPrefix(key); | ||
const { store } = this.opts; | ||
const isArray = Array.isArray(key); | ||
const keyPrefixed = isArray ? this._getKeyPrefixArray(key) : this._getKeyPrefix(key); | ||
if (isArray && store.getMany === undefined) { | ||
const promises = []; | ||
for (const key of keyPrefixed) { | ||
promises.push(Promise.resolve() | ||
.then(() => store.get(key)) | ||
.then(data => (typeof data === 'string') ? this.opts.deserialize(data) : data) | ||
.then(data => { | ||
if (data === undefined || data === null) { | ||
return undefined; | ||
} | ||
if (typeof data.expires === 'number' && Date.now() > data.expires) { | ||
return this.delete(key).then(() => undefined); | ||
} | ||
return (options && options.raw) ? data : data.value; | ||
}), | ||
); | ||
} | ||
return Promise.allSettled(promises) | ||
.then(values => { | ||
const data = []; | ||
for (const value of values) { | ||
data.push(value.value); | ||
} | ||
return data.every(x => x === undefined) ? [] : data; | ||
}); | ||
} | ||
return Promise.resolve() | ||
.then(() => store.get(keyPrefixed)) | ||
.then(() => isArray ? store.getMany(keyPrefixed) : store.get(keyPrefixed)) | ||
.then(data => (typeof data === 'string') ? this.opts.deserialize(data) : data) | ||
.then(data => { | ||
// Console.log('get', data); | ||
if (data === undefined || data === null) { | ||
@@ -74,5 +163,31 @@ return undefined; | ||
if (isArray) { | ||
const result = []; | ||
if (data.length === 0) { | ||
return []; | ||
} | ||
for (let row of data) { | ||
if ((typeof row === 'string')) { | ||
row = this.opts.deserialize(row); | ||
} | ||
if (row === undefined || row === null) { | ||
result.push(undefined); | ||
continue; | ||
} | ||
if (typeof row.expires === 'number' && Date.now() > row.expires) { | ||
this.delete(key).then(() => undefined); | ||
result.push(undefined); | ||
} else { | ||
result.push((options && options.raw) ? row : row.value); | ||
} | ||
} | ||
return result.every(x => x === undefined) ? [] : result; | ||
} | ||
if (typeof data.expires === 'number' && Date.now() > data.expires) { | ||
this.delete(key); | ||
return undefined; | ||
return this.delete(key).then(() => undefined); | ||
} | ||
@@ -111,4 +226,20 @@ | ||
delete(key) { | ||
const { store } = this.opts; | ||
if (Array.isArray(key)) { | ||
const keyPrefixed = this._getKeyPrefixArray(key); | ||
if (store.deleteMany === undefined) { | ||
const promises = []; | ||
for (const key of keyPrefixed) { | ||
promises.push(store.delete(key)); | ||
} | ||
return Promise.allSettled(promises) | ||
.then(values => values.every(x => x.value === true)); | ||
} | ||
return Promise.resolve() | ||
.then(() => store.deleteMany(keyPrefixed)); | ||
} | ||
const keyPrefixed = this._getKeyPrefix(key); | ||
const { store } = this.opts; | ||
return Promise.resolve() | ||
@@ -123,4 +254,18 @@ .then(() => store.delete(keyPrefixed)); | ||
} | ||
has(key) { | ||
const keyPrefixed = this._getKeyPrefix(key); | ||
const { store } = this.opts; | ||
return Promise.resolve() | ||
.then(async () => { | ||
if (typeof store.has === 'function') { | ||
return store.has(keyPrefixed); | ||
} | ||
const value = await store.get(keyPrefixed); | ||
return value !== undefined; | ||
}); | ||
} | ||
} | ||
module.exports = Keyv; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
239
22612
2
11
4
1
+ Addedcompress-brotli@^1.3.6
+ Added@types/json-buffer@3.0.2(transitive)
+ Addedcompress-brotli@1.3.12(transitive)