Comparing version 5.2.3 to 5.3.0
@@ -47,3 +47,3 @@ type EventListener = (...arguments_: any[]) => void; | ||
}; | ||
interface CompressionAdapter { | ||
type CompressionAdapter = { | ||
compress(value: any, options?: any): Promise<any>; | ||
@@ -53,3 +53,3 @@ decompress(value: any, options?: any): Promise<any>; | ||
deserialize<Value>(data: string): Promise<DeserializedData<Value> | undefined> | DeserializedData<Value> | undefined; | ||
} | ||
}; | ||
type Serialize = <Value>(data: DeserializedData<Value>) => Promise<string> | string; | ||
@@ -67,9 +67,23 @@ type Deserialize = <Value>(data: string) => Promise<DeserializedData<Value> | undefined> | DeserializedData<Value> | undefined; | ||
} | ||
type KeyvEntry = { | ||
/** | ||
* Key to set. | ||
*/ | ||
key: string; | ||
/** | ||
* Value to set. | ||
*/ | ||
value: any; | ||
/** | ||
* Time to live in milliseconds. | ||
*/ | ||
ttl?: number; | ||
}; | ||
type StoredDataNoRaw<Value> = Value | undefined; | ||
type StoredDataRaw<Value> = DeserializedData<Value> | undefined; | ||
type StoredData<Value> = StoredDataNoRaw<Value> | StoredDataRaw<Value>; | ||
interface IEventEmitter { | ||
on(event: string, listener: (...arguments_: any[]) => void): this; | ||
} | ||
interface KeyvStoreAdapter extends IEventEmitter { | ||
type IEventEmitter = { | ||
on(event: string, listener: (...arguments_: any[]) => void): IEventEmitter; | ||
}; | ||
type KeyvStoreAdapter = { | ||
opts: any; | ||
@@ -82,7 +96,9 @@ namespace?: string; | ||
has?(key: string): Promise<boolean>; | ||
hasMany?(keys: string[]): Promise<boolean[]>; | ||
getMany?<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>; | ||
disconnect?(): Promise<void>; | ||
deleteMany?(key: string[]): Promise<boolean>; | ||
setMany?(data: KeyvEntry[]): Promise<boolean[]>; | ||
iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>; | ||
} | ||
} & IEventEmitter; | ||
type KeyvOptions = { | ||
@@ -223,3 +239,3 @@ /** Emit errors */ | ||
* @param {string | string[]} key passing in a single key or multiple as an array | ||
* @param [options] can pass in to return the raw value by setting { raw: true } | ||
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true } | ||
*/ | ||
@@ -239,4 +255,15 @@ get<Value = GenericValue>(key: string, options?: { | ||
/** | ||
* Get many values of keys | ||
* @param {string[]} keys passing in a single key or multiple as an array | ||
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true } | ||
*/ | ||
getMany<Value = GenericValue>(keys: string[], options?: { | ||
raw: false; | ||
}): Promise<Array<StoredDataNoRaw<Value>>>; | ||
getMany<Value = GenericValue>(keys: string[], options?: { | ||
raw: true; | ||
}): Promise<Array<StoredDataRaw<Value>>>; | ||
/** | ||
* Set an item to the store | ||
* @param {string} key the key to use | ||
* @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items | ||
* @param {Value} value the value of the key | ||
@@ -246,4 +273,11 @@ * @param {number} [ttl] time to live in milliseconds | ||
*/ | ||
set<Value = GenericValue>(key: KeyvEntry[]): Promise<boolean[]>; | ||
set<Value = GenericValue>(key: string, value: Value, ttl?: number): Promise<boolean>; | ||
/** | ||
* Set many items to the store | ||
* @param {Array<KeyvEntry>} entries the entries to set | ||
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false. | ||
*/ | ||
setMany<Value = GenericValue>(entries: KeyvEntry[]): Promise<boolean[]>; | ||
/** | ||
* Delete an Entry | ||
@@ -255,2 +289,8 @@ * @param {string | string[]} key the key to be deleted. if an array it will delete many items | ||
/** | ||
* Delete many items from the store | ||
* @param {string[]} keys the keys to be deleted | ||
* @returns {boolean} will return true if item or items are deleted. false if there is an error | ||
*/ | ||
deleteMany(keys: string[]): Promise<boolean>; | ||
/** | ||
* Clear the store | ||
@@ -265,4 +305,11 @@ * @returns {void} | ||
*/ | ||
has(key: string[]): Promise<boolean[]>; | ||
has(key: string): Promise<boolean>; | ||
/** | ||
* Check if many keys exist | ||
* @param {string[]} keys the keys to check | ||
* @returns {boolean[]} will return an array of booleans if the keys exist | ||
*/ | ||
hasMany(keys: string[]): Promise<boolean[]>; | ||
/** | ||
* Will disconnect the store. This is only available if the store has a disconnect method | ||
@@ -277,2 +324,2 @@ * @returns {Promise<void>} | ||
export { type CompressionAdapter, type Deserialize, type DeserializedData, type IEventEmitter, Keyv, KeyvHooks, type KeyvOptions, type KeyvStoreAdapter, type Serialize, type StoredData, type StoredDataNoRaw, type StoredDataRaw, Keyv as default }; | ||
export { type CompressionAdapter, type Deserialize, type DeserializedData, type IEventEmitter, Keyv, type KeyvEntry, KeyvHooks, type KeyvOptions, type KeyvStoreAdapter, type Serialize, type StoredData, type StoredDataNoRaw, type StoredDataRaw, Keyv as default }; |
@@ -465,48 +465,6 @@ // src/index.ts | ||
if (isArray) { | ||
this.hooks.trigger("preGetMany" /* PRE_GET_MANY */, { keys: keyPrefixed }); | ||
if (store.getMany === void 0) { | ||
const promises = keyPrefixed.map(async (key2) => { | ||
const rawData3 = await store.get(key2); | ||
const deserializedRow = typeof rawData3 === "string" || this.opts.compression ? await this.deserializeData(rawData3) : rawData3; | ||
if (deserializedRow === void 0 || deserializedRow === null) { | ||
return void 0; | ||
} | ||
if (isDataExpired(deserializedRow)) { | ||
await this.delete(key2); | ||
return void 0; | ||
} | ||
return options?.raw ? deserializedRow : deserializedRow.value; | ||
}); | ||
const deserializedRows = await Promise.allSettled(promises); | ||
const result2 = deserializedRows.map((row) => row.value); | ||
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result2); | ||
if (result2.length > 0) { | ||
this.stats.hit(); | ||
} | ||
return result2; | ||
if (options?.raw === true) { | ||
return this.getMany(key, { raw: true }); | ||
} | ||
const rawData2 = await store.getMany(keyPrefixed); | ||
const result = []; | ||
for (const index in rawData2) { | ||
let row = rawData2[index]; | ||
if (typeof row === "string") { | ||
row = await this.deserializeData(row); | ||
} | ||
if (row === void 0 || row === null) { | ||
result.push(void 0); | ||
continue; | ||
} | ||
if (isDataExpired(row)) { | ||
await this.delete(key[index]); | ||
result.push(void 0); | ||
continue; | ||
} | ||
const value = options?.raw ? row : row.value; | ||
result.push(value); | ||
} | ||
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result); | ||
if (result.length > 0) { | ||
this.stats.hit(); | ||
} | ||
return result; | ||
return this.getMany(key, { raw: false }); | ||
} | ||
@@ -529,13 +487,60 @@ this.hooks.trigger("preGet" /* PRE_GET */, { key: keyPrefixed }); | ||
} | ||
/** | ||
* Set an item to the store | ||
* @param {string} key the key to use | ||
* @param {Value} value the value of the key | ||
* @param {number} [ttl] time to live in milliseconds | ||
* @returns {boolean} if it sets then it will return a true. On failure will return false. | ||
*/ | ||
async getMany(keys, options) { | ||
const { store } = this.opts; | ||
const keyPrefixed = this._getKeyPrefixArray(keys); | ||
const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires; | ||
this.hooks.trigger("preGetMany" /* PRE_GET_MANY */, { keys: keyPrefixed }); | ||
if (store.getMany === void 0) { | ||
const promises = keyPrefixed.map(async (key) => { | ||
const rawData2 = await store.get(key); | ||
const deserializedRow = typeof rawData2 === "string" || this.opts.compression ? await this.deserializeData(rawData2) : rawData2; | ||
if (deserializedRow === void 0 || deserializedRow === null) { | ||
return void 0; | ||
} | ||
if (isDataExpired(deserializedRow)) { | ||
await this.delete(key); | ||
return void 0; | ||
} | ||
return options?.raw ? deserializedRow : deserializedRow.value; | ||
}); | ||
const deserializedRows = await Promise.allSettled(promises); | ||
const result2 = deserializedRows.map((row) => row.value); | ||
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result2); | ||
if (result2.length > 0) { | ||
this.stats.hit(); | ||
} | ||
return result2; | ||
} | ||
const rawData = await store.getMany(keyPrefixed); | ||
const result = []; | ||
for (const index in rawData) { | ||
let row = rawData[index]; | ||
if (typeof row === "string") { | ||
row = await this.deserializeData(row); | ||
} | ||
if (row === void 0 || row === null) { | ||
result.push(void 0); | ||
continue; | ||
} | ||
if (isDataExpired(row)) { | ||
await this.delete(keys[index]); | ||
result.push(void 0); | ||
continue; | ||
} | ||
const value = options?.raw ? row : row.value; | ||
result.push(value); | ||
} | ||
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result); | ||
if (result.length > 0) { | ||
this.stats.hit(); | ||
} | ||
return result; | ||
} | ||
async set(key, value, ttl) { | ||
if (Array.isArray(key)) { | ||
return this.setMany(key); | ||
} | ||
this.hooks.trigger("preSet" /* PRE_SET */, { key, value, ttl }); | ||
const keyPrefixed = this._getKeyPrefix(key); | ||
if (typeof ttl === "undefined") { | ||
if (ttl === void 0) { | ||
ttl = this._ttl; | ||
@@ -568,2 +573,26 @@ } | ||
/** | ||
* Set many items to the store | ||
* @param {Array<KeyvEntry>} entries the entries to set | ||
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false. | ||
*/ | ||
async setMany(entries) { | ||
let results = []; | ||
try { | ||
if (this._store.setMany !== void 0) { | ||
results = await this._store.setMany(entries); | ||
return results; | ||
} | ||
const promises = []; | ||
for (const entry of entries) { | ||
promises.push(this.set(entry.key, entry.value, entry.ttl)); | ||
} | ||
const promiseResults = await Promise.allSettled(promises); | ||
results = promiseResults.map((result) => result.value); | ||
} catch (error) { | ||
this.emit("error", error); | ||
results = entries.map(() => false); | ||
} | ||
return results; | ||
} | ||
/** | ||
* Delete an Entry | ||
@@ -576,12 +605,3 @@ * @param {string | string[]} key the key to be deleted. if an array it will delete many items | ||
if (Array.isArray(key)) { | ||
const keyPrefixed2 = this._getKeyPrefixArray(key); | ||
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key: keyPrefixed2 }); | ||
if (store.deleteMany !== void 0) { | ||
return store.deleteMany(keyPrefixed2); | ||
} | ||
const promises = keyPrefixed2.map(async (key2) => store.delete(key2)); | ||
const results = await Promise.allSettled(promises); | ||
const returnResult = results.every((x) => x.value === true); | ||
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed2, value: returnResult }); | ||
return returnResult; | ||
return this.deleteMany(key); | ||
} | ||
@@ -605,2 +625,25 @@ const keyPrefixed = this._getKeyPrefix(key); | ||
/** | ||
* Delete many items from the store | ||
* @param {string[]} keys the keys to be deleted | ||
* @returns {boolean} will return true if item or items are deleted. false if there is an error | ||
*/ | ||
async deleteMany(keys) { | ||
try { | ||
const { store } = this.opts; | ||
const keyPrefixed = this._getKeyPrefixArray(keys); | ||
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key: keyPrefixed }); | ||
if (store.deleteMany !== void 0) { | ||
return await store.deleteMany(keyPrefixed); | ||
} | ||
const promises = keyPrefixed.map(async (key) => store.delete(key)); | ||
const results = await Promise.allSettled(promises); | ||
const returnResult = results.every((x) => x.value === true); | ||
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult }); | ||
return returnResult; | ||
} catch (error) { | ||
this.emit("error", error); | ||
return false; | ||
} | ||
} | ||
/** | ||
* Clear the store | ||
@@ -618,8 +661,6 @@ * @returns {void} | ||
} | ||
/** | ||
* Has a key | ||
* @param {string} key the key to check | ||
* @returns {boolean} will return true if the key exists | ||
*/ | ||
async has(key) { | ||
if (Array.isArray(key)) { | ||
return this.hasMany(key); | ||
} | ||
const keyPrefixed = this._getKeyPrefix(key); | ||
@@ -648,2 +689,19 @@ const { store } = this.opts; | ||
/** | ||
* Check if many keys exist | ||
* @param {string[]} keys the keys to check | ||
* @returns {boolean[]} will return an array of booleans if the keys exist | ||
*/ | ||
async hasMany(keys) { | ||
const keyPrefixed = this._getKeyPrefixArray(keys); | ||
const { store } = this.opts; | ||
if (store.hasMany !== void 0) { | ||
return store.hasMany(keyPrefixed); | ||
} | ||
const results = []; | ||
for (const key of keyPrefixed) { | ||
results.push(await this.has(key)); | ||
} | ||
return results; | ||
} | ||
/** | ||
* Will disconnect the store. This is only available if the store has a disconnect method | ||
@@ -688,7 +746,7 @@ * @returns {Promise<void>} | ||
}; | ||
var src_default = Keyv; | ||
var index_default = Keyv; | ||
export { | ||
Keyv, | ||
KeyvHooks, | ||
src_default as default | ||
index_default as default | ||
}; |
{ | ||
"name": "keyv", | ||
"version": "5.2.3", | ||
"version": "5.3.0", | ||
"description": "Simple key-value storage with support for multiple backends", | ||
@@ -17,23 +17,8 @@ "type": "module", | ||
"rules": { | ||
"import/no-named-as-default": "off", | ||
"unicorn/prefer-module": "off", | ||
"unicorn/prefer-node-protocol": "off", | ||
"@typescript-eslint/consistent-type-definitions": "off", | ||
"unicorn/no-typeof-undefined": "off", | ||
"unicorn/prefer-event-target": "off", | ||
"import/no-extraneous-dependencies": "off", | ||
"import/extensions": "off", | ||
"@typescript-eslint/ban-ts-comment": "off", | ||
"@typescript-eslint/no-unsafe-call": "off", | ||
"@typescript-eslint/no-for-in-array": "off", | ||
"guard-for-in": "off", | ||
"no-await-in-loop": "off", | ||
"@typescript-eslint/no-unsafe-return": "off", | ||
"@typescript-eslint/no-unsafe-assignment": "off", | ||
"@typescript-eslint/no-unsafe-argument": "off", | ||
"@typescript-eslint/naming-convention": "off", | ||
"@typescript-eslint/consistent-type-assertions": "off", | ||
"@typescript-eslint/no-confusing-void-expression": "off", | ||
"@typescript-eslint/no-var-requires": "off", | ||
"@typescript-eslint/prefer-ts-expect-error": "off" | ||
"@typescript-eslint/no-confusing-void-expression": "off" | ||
} | ||
@@ -73,15 +58,19 @@ }, | ||
"dependencies": { | ||
"@keyv/serialize": "^1.0.2" | ||
"@keyv/serialize": "^1.0.3" | ||
}, | ||
"devDependencies": { | ||
"@faker-js/faker": "^9.5.1", | ||
"@vitest/coverage-v8": "^3.0.7", | ||
"rimraf": "^6.0.1", | ||
"timekeeper": "^2.3.1", | ||
"tsd": "^0.31.2", | ||
"vitest": "^3.0.7", | ||
"xo": "^0.60.0", | ||
"@keyv/compress-brotli": "^2.0.2", | ||
"@keyv/compress-brotli": "^2.0.3", | ||
"@keyv/compress-gzip": "^2.0.2", | ||
"@keyv/memcache": "^2.0.1", | ||
"@keyv/compress-lz4": "^1.0.0", | ||
"@keyv/mongo": "^3.0.1", | ||
"@keyv/sqlite": "^4.0.1", | ||
"@keyv/test-suite": "^2.0.3" | ||
"@keyv/test-suite": "^2.0.5" | ||
}, | ||
@@ -88,0 +77,0 @@ "tsd": { |
@@ -292,3 +292,3 @@ <h1 align="center"><img width="250" src="https://jaredwray.com/images/keyv.svg" alt="keyv"></h1> | ||
Keyv supports `gzip` and `brotli` compression. To enable compression, pass the `compress` option to the constructor. | ||
Keyv supports `gzip`, `brotli` and `lz4` compression. To enable compression, pass the `compress` option to the constructor. | ||
@@ -300,5 +300,21 @@ ```js | ||
const keyvGzip = new KeyvGzip(); | ||
const keyv = new Keyv({ compression: KeyvGzip }); | ||
const keyv = new Keyv({ compression: keyvGzip }); | ||
``` | ||
```js | ||
import Keyv from 'keyv'; | ||
import KeyvBrotli from '@keyv/compress-brotli'; | ||
const keyvBrotli = new KeyvBrotli(); | ||
const keyv = new Keyv({ compression: keyvBrotli }); | ||
``` | ||
```js | ||
import Keyv from 'keyv'; | ||
import KeyvLz4 from '@keyv/compress-lz4'; | ||
const keyvLz4 = new KeyvLz4(); | ||
const keyv = new Keyv({ compression: keyvLz4 }); | ||
``` | ||
You can also pass a custom compression function to the `compression` option. Following the pattern of the official compression adapters. | ||
@@ -412,2 +428,6 @@ | ||
## .setMany(entries) | ||
Set multiple values using KeyvEntrys `{ key: string, value: any, ttl?: number }`. | ||
## .get(key, [options]) | ||
@@ -417,2 +437,6 @@ | ||
## .getMany(keys, [options]) | ||
Returns a promise which resolves to an array of retrieved values. | ||
### options.raw | ||
@@ -433,2 +457,6 @@ | ||
## .deleteMany(keys) | ||
Deletes multiple entries. | ||
Returns a promise which resolves to an array of booleans indicating if the key existed or not. | ||
## .clear() | ||
@@ -435,0 +463,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
90799
1816
596
14
Updated@keyv/serialize@^1.0.3