cacheable 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -8
- package/dist/index.cjs +1087 -1
- package/dist/index.d.cts +16 -8
- package/dist/index.d.ts +16 -8
- package/dist/index.js +1071 -1
- package/package.json +19 -20
package/README.md
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
* [Storage Tiering and Caching](#storage-tiering-and-caching)
|
|
33
33
|
* [TTL Propagation and Storage Tiering](#ttl-propagation-and-storage-tiering)
|
|
34
34
|
* [Shorthand for Time to Live (ttl)](#shorthand-for-time-to-live-ttl)
|
|
35
|
+
* [Iteration on Primary and Secondary Stores](#iteration-on-primary-and-secondary-stores)
|
|
35
36
|
* [Non-Blocking Operations](#non-blocking-operations)
|
|
36
37
|
* [Non-Blocking with @keyv/redis](#non-blocking-with-keyvredis)
|
|
37
38
|
* [CacheableSync - Distributed Updates](#cacheablesync---distributed-updates)
|
|
@@ -279,6 +280,110 @@ raws.forEach((entry, idx) => {
|
|
|
279
280
|
});
|
|
280
281
|
```
|
|
281
282
|
|
|
283
|
+
## Checking multiple keys with hasMany
|
|
284
|
+
|
|
285
|
+
The `hasMany` method allows you to efficiently check if multiple keys exist in the cache. It leverages Keyv's native `hasMany` support for optimal performance:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { Cacheable } from 'cacheable';
|
|
289
|
+
|
|
290
|
+
const cache = new Cacheable();
|
|
291
|
+
|
|
292
|
+
// set some values
|
|
293
|
+
await cache.set('user:1', { name: 'Alice' });
|
|
294
|
+
await cache.set('user:2', { name: 'Bob' });
|
|
295
|
+
|
|
296
|
+
// check if multiple keys exist
|
|
297
|
+
const exists = await cache.hasMany(['user:1', 'user:2', 'user:3']);
|
|
298
|
+
console.log(exists); // [true, true, false]
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The `hasMany` method returns an array of booleans in the same order as the input keys. This is particularly useful when you need to verify the existence of multiple cache entries before performing batch operations.
|
|
302
|
+
|
|
303
|
+
# Iteration on Primary and Secondary Stores
|
|
304
|
+
|
|
305
|
+
The `Cacheable` class exposes both `primary` and `secondary` Keyv instances, which support iteration over their stored entries using the `iterator()` method. This allows you to access and process all keys and values in either storage layer.
|
|
306
|
+
|
|
307
|
+
**Important Notes:**
|
|
308
|
+
- Not all storage adapters support iteration. Always check if `iterator` exists before using it.
|
|
309
|
+
- The iterator automatically filters by namespace, skips expired entries (and deletes them), and deserializes values.
|
|
310
|
+
- **Performance Warning:** Be careful when using `iterator()` as it can cause performance issues with large datasets.
|
|
311
|
+
|
|
312
|
+
## Basic Iteration Example
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import { Cacheable } from 'cacheable';
|
|
316
|
+
import KeyvRedis from '@keyv/redis';
|
|
317
|
+
|
|
318
|
+
// Create cache with primary (in-memory) and secondary (Redis) stores
|
|
319
|
+
const secondary = new KeyvRedis('redis://user:pass@localhost:6379');
|
|
320
|
+
const cache = new Cacheable({ secondary });
|
|
321
|
+
|
|
322
|
+
// Add some data
|
|
323
|
+
await cache.set('user:1', { name: 'Alice', role: 'admin' });
|
|
324
|
+
await cache.set('user:2', { name: 'Bob', role: 'user' });
|
|
325
|
+
await cache.set('session:abc', { userId: '1', active: true });
|
|
326
|
+
|
|
327
|
+
// Iterate over primary store (in-memory)
|
|
328
|
+
console.log('Primary store contents:');
|
|
329
|
+
if (cache.primary.iterator) {
|
|
330
|
+
for await (const [key, value] of cache.primary.iterator()) {
|
|
331
|
+
console.log(` ${key}:`, JSON.stringify(value));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Iterate over secondary store (Redis)
|
|
336
|
+
console.log('\nSecondary store contents:');
|
|
337
|
+
if (cache.secondary?.iterator) {
|
|
338
|
+
for await (const [key, value] of cache.secondary.iterator()) {
|
|
339
|
+
console.log(` ${key}:`, JSON.stringify(value));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Safe Iteration Helper
|
|
345
|
+
|
|
346
|
+
Here's a recommended helper function for safe iteration that checks for store availability and iterator support:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { Cacheable } from 'cacheable';
|
|
350
|
+
import type { Keyv } from 'keyv';
|
|
351
|
+
|
|
352
|
+
async function iterateStore(store: Keyv | undefined, storeName: string) {
|
|
353
|
+
if (!store) {
|
|
354
|
+
console.log(`${storeName} store not configured`);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!store.iterator) {
|
|
359
|
+
console.log(`${storeName} store does not support iteration`);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
console.log(`${storeName} store entries:`);
|
|
364
|
+
for await (const [key, value] of store.iterator()) {
|
|
365
|
+
console.log(` ${key}:`, value);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Usage
|
|
370
|
+
const cache = new Cacheable({ /* options */ });
|
|
371
|
+
await iterateStore(cache.primary, 'Primary');
|
|
372
|
+
await iterateStore(cache.secondary, 'Secondary');
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Storage Adapter Support
|
|
376
|
+
|
|
377
|
+
The `iterator()` method is available when:
|
|
378
|
+
- The store is a Map instance (has Symbol.iterator)
|
|
379
|
+
- The store implements an `iterator()` method (e.g., Redis, Valkey, etc.)
|
|
380
|
+
- The store is a supported iterable adapter
|
|
381
|
+
|
|
382
|
+
Common stores that support iteration:
|
|
383
|
+
- In-memory (Map-based stores)
|
|
384
|
+
- @keyv/redis
|
|
385
|
+
- @keyv/valkey
|
|
386
|
+
- Other Keyv adapters that implement the iterator interface
|
|
282
387
|
|
|
283
388
|
# Non-Blocking Operations
|
|
284
389
|
|
|
@@ -517,7 +622,8 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
|
|
|
517
622
|
* `removeHook(hook)`: Removes a hook.
|
|
518
623
|
* `on(event, callback)`: Listens for an event.
|
|
519
624
|
* `removeListener(event, callback)`: Removes a listener.
|
|
520
|
-
* `hash(object: any, algorithm = '
|
|
625
|
+
* `hash(object: any, algorithm = 'SHA-256'): Promise<string>`: Asynchronously hashes an object with a cryptographic algorithm (SHA-256, SHA-384, SHA-512). Default is `SHA-256`.
|
|
626
|
+
* `hashSync(object: any, algorithm = 'djb2'): string`: Synchronously hashes an object with a non-cryptographic algorithm (djb2, fnv1, murmer, crc32). Default is `djb2`.
|
|
521
627
|
* `primary`: The primary store for the cache (layer 1) defaults to in-memory by Keyv.
|
|
522
628
|
* `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
|
|
523
629
|
* `namespace`: The namespace for the cache. Default is `undefined`. This will set the namespace for the primary and secondary stores.
|
|
@@ -544,7 +650,7 @@ To learn more go to [@cacheable/memory](https://cacheable.org/docs/memory/)
|
|
|
544
650
|
|
|
545
651
|
# Wrap / Memoization for Sync and Async Functions
|
|
546
652
|
|
|
547
|
-
`Cacheable` and `CacheableMemory` has a feature called `wrap` that comes from [@cacheable/
|
|
653
|
+
`Cacheable` and `CacheableMemory` has a feature called `wrap` that comes from [@cacheable/utils](https://cacheable.org/docs/utils/) and allows you to wrap a function in a cache. This is useful for memoization and caching the results of a function. You can wrap a `sync` or `async` function in a cache. Here is an example of how to use the `wrap` function:
|
|
548
654
|
|
|
549
655
|
```javascript
|
|
550
656
|
import { Cacheable } from 'cacheable';
|
|
@@ -637,11 +743,11 @@ If you would like to generate your own key for the wrapped function you can set
|
|
|
637
743
|
|
|
638
744
|
We will pass in the `function` that is being wrapped, the `arguments` passed to the function, and the `options` used to wrap the function. You can then use these to generate a custom key for the cache.
|
|
639
745
|
|
|
640
|
-
To learn more visit [@cacheable/
|
|
746
|
+
To learn more visit [@cacheable/utils](https://cacheable.org/docs/utils/)
|
|
641
747
|
|
|
642
748
|
# Get Or Set Memoization Function
|
|
643
749
|
|
|
644
|
-
The `getOrSet` method that comes from [@cacheable/
|
|
750
|
+
The `getOrSet` method that comes from [@cacheable/utils](https://cacheable.org/docs/utils/) provides a convenient way to implement the cache-aside pattern. It attempts to retrieve a value from cache, and if not found, calls the provided function to compute the value and store it in cache before returning it. Here are the options:
|
|
645
751
|
|
|
646
752
|
```typescript
|
|
647
753
|
export type GetOrSetFunctionOptions = {
|
|
@@ -677,17 +783,17 @@ const function_ = async () => Math.random() * 100;
|
|
|
677
783
|
const value = await cache.getOrSet(generateKey(), function_, { ttl: '1h' });
|
|
678
784
|
```
|
|
679
785
|
|
|
680
|
-
To learn more go to [@cacheable/
|
|
786
|
+
To learn more go to [@cacheable/utils](https://cacheable.org/docs/utils/)
|
|
681
787
|
|
|
682
788
|
# v1 to v2 Changes
|
|
683
789
|
|
|
684
|
-
`cacheable` is now using `@cacheable/utils
|
|
790
|
+
`cacheable` is now using `@cacheable/utils` and `@cacheable/memory` for its core functionality as we are moving to this modular architecture and plan to eventually have these modules across `cache-manager` and `flat-cache`. In addition there are some breaking changes:
|
|
685
791
|
|
|
686
792
|
* `get()` and `getMany()` no longer have the `raw` option but instead we have built out `getRaw()` and `getManyRaw()` to use.
|
|
687
793
|
* All `get` related functions now support `nonBlocking` which means if `nonBlocking: true` the primary store will return what it has and then in the background will work to sync from secondary storage for any misses. You can disable this by setting at the `get` function level the option `nonBlocking: false` which will look for any missing keys in the secondary.
|
|
688
|
-
* `Keyv` v5.5+ is now the recommended supported version as we are using its native `getMany
|
|
794
|
+
* `Keyv` v5.5+ is now the recommended supported version as we are using its native `getMany*`, `getRaw*`, and `hasMany` methods for improved performance
|
|
689
795
|
* `Wrap` and `getOrSet` have been updated with more robust options including the ability to use your own `serialize` function for creating the key in `wrap`.
|
|
690
|
-
* `hash` has
|
|
796
|
+
* `hash` has been split into async (`hash()` and `hashToNumber()`) and sync (`hashSync()` and `hashToNumberSync()`) methods. MD5 support has been removed. Now uses Hashery library with support for additional algorithms (SHA-384, FNV1, MURMER, CRC32).
|
|
691
797
|
|
|
692
798
|
# How to Contribute
|
|
693
799
|
|