diff --git a/packages/node-cache/README.md b/packages/node-cache/README.md index 25eb80a8..001e12da 100644 --- a/packages/node-cache/README.md +++ b/packages/node-cache/README.md @@ -9,13 +9,23 @@ [![npm](https://img.shields.io/npm/dm/cacheable.svg)](https://www.npmjs.com/package/cacheable) [![npm](https://img.shields.io/npm/v/cacheable)](https://www.npmjs.com/package/cacheable) -`@cacheable/node-cache` is compatible with the `node-cache` package with regular maintenance and additional functionality (async/await and storage adapters). The only thing not implemented is the `enableLegacyCallbacks` option and functions. If you need them we are happy to take a PR to add them. +`@cacheable/node-cache` is compatible with the [node-cache](https://www.npmjs.com/package/node-cache) package with regular maintenance and additional functionality (async/await and storage adapters). The only thing not implemented is the `enableLegacyCallbacks` option and functions. If you need them we are happy to take a PR to add them. * Fully Compatible with `node-cache` using `{NodeCache}` -* Async/Await functionality with `{NodeStorageCache}` -* Storage Adapters via [Keyv](https://keyv.org) with `{NodeStorageCache}` +* Async/Await functionality with `{NodeCacheStore}` +* Storage Adapters via [Keyv](https://keyv.org) with `{NodeCacheStore}` * Maintained and Updated Regularly! 🎉 +Note: `NodeCache` is ready and available for use. `NodeCacheStore` is in progress and will be available soon. Please do not use it until it is released. + +## Table of Contents +* [Getting Started](#getting-started) +* [Basic Usage](#basic-usage) +* [Advanced Usage](#advanced-usage) +* [API](#api) +* [How to Contribute](#how-to-contribute) +* [License and Copyright](#license-and-copyright) + ## Getting Started ```bash @@ -52,6 +62,197 @@ cache.getStats(); // {hits: 1, misses: 1, keys: 1, ksize: 2, vsize: 3} ## API +### `constructor(options?: NodeCacheOptions)` + +Create a new cache instance. You can pass in options to set the configuration: + +```javascript +export type NodeCacheOptions = { + stdTTL?: number; // The standard ttl as number in seconds for every generated cache element. 0 = unlimited + checkperiod?: number; // Default is 600, 0 means no periodic check + useClones?: boolean; // Default is true + deleteOnExpire?: boolean; // Default is true, if this is set to true it will delete the key when it expires. + maxKeys?: number; // Default is -1 (unlimited). If this is set it will throw and error if you try to set more keys than the max. +}; +``` + +When initializing the cache you can pass in the options to set the configuration like the example below where we set the `stdTTL` to 10 seconds and `checkperiod` to 5 seconds.: + +```javascript +const cache = new NodeCache({stdTTL: 10, checkperiod: 5}); +``` + +When setting `deleteOnExpire` to `true` it will delete the key when it expires. If you set it to `false` it will keep the key but the value on `get()` will be `undefined`. You can manage the key with `on('expired')` event. + +```javascript +const cache = new NodeCache({deleteOnExpire: false}); +cache.on('expired', (key, value) => { + console.log(`Key ${key} has expired with value ${value}`); +}); +``` + +### `.set(key: string | number, value: any, ttl?: number): boolean` + +Set a key value pair with an optional ttl (in seconds). Will return true on success. If the ttl is not set it will default to 0 (no ttl). + +```javascript +cache.set('foo', 'bar', 10); // true +``` + +### `.mset(data: Array): boolean` + +Set multiple key value pairs at once. This will take an array of objects with the key, value, and optional ttl. + +```javascript +cache.mset([{key: 'foo', value: 'bar', ttl: 10}, {key: 'bar', value: 'baz'}]); // true +``` + +the `NodeCacheItem` is defined as: + +```javascript +export type NodeCacheItem = { + key: string; + value: any; + ttl?: number; +}; +``` + +### `.get(key: string | number): any` + +Get a value from the cache by key. If the key does not exist it will return `undefined`. + +```javascript +cache.get('foo'); // 'bar' +``` + +### `mget(keys: Array): Record` + +Get multiple values from the cache by keys. This will return an object with the keys and values. + +```javascript +const obj = { my: 'value', my2: 'value2' }; +const obj2 = { special: 'value3', life: 'value4' }; +cache.set('my', obj); +cache.set('my2', obj2); +cache.mget(['my', 'my2']); // { my: { my: 'value', my2: 'value2' }, my2: { special: 'value3', life: 'value4' } } +``` + +### `take(key: string | number): any` + +Get a value from the cache by key and delete it. If the key does not exist it will return `undefined`. + +```javascript +cache.set('foo', 'bar'); +cache.take('foo'); // 'bar' +cache.get('foo'); // undefined +``` + +### `del(key: string | number | Array): number` + +Delete a key from the cache. Will return the number of deleted entries and never fail. You can also pass in an array of keys to delete multiple keys. All examples assume that you have initialized the cache like `const cache = new NodeCache();`. + +```javascript +cache.del('foo'); // true +``` + +passing in an array of keys: + +```javascript +cache.del(['foo', 'bar']); // true +``` + +### `.mdel(keys: Array): number` + +Delete multiple keys from the cache. Will return the number of deleted entries and never fail. + +```javascript +cache.mdel(['foo', 'bar']); // true +``` + +### `.ttl(key: string | number, ttl?: number): boolean` + +Redefine the ttl of a key. Returns true if the key has been found and changed. Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used. + +```javascript +cache.ttl('foo', 10); // true +``` + +### `getTtl(key: string | number): number | undefined` + +Get the ttl expiration from `Date.now()` of a key. If the key does not exist it will return `undefined`. + +```javascript +cache.getTtl('foo'); // 1725993344859 +``` + +### `has(key: string | number): boolean` + +Check if a key exists in the cache. + +```javascript +cache.set('foo', 'bar'); +cache.has('foo'); // true +``` + +### `keys(): Array` + +Get all keys from the cache. + +```javascript +cache.keys(); // ['foo', 'bar'] +``` + +### `getStats(): NodeCacheStats` + +Get the stats of the cache. + +```javascript +cache.getStats(); // {hits: 1, misses: 1, keys: 1, ksize: 2, vsize: 3} +``` + +### `flushAll(): void` + +Flush the cache. Will remove all keys and reset the stats. + +```javascript +cache.flushAll(); +cache.keys(); // [] +cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0} +``` + +### `flushStats(): void` + +Flush the stats. Will reset the stats but keep the keys. + +```javascript +cache.set('foo', 'bar'); +cache.flushStats(); +cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0} +cache.keys(); // ['foo'] +``` + +### `close(): void` + +this will stop the interval that is running for the `checkperiod` and `deleteOnExpire` options. + +```javascript +cache.close(); +``` + +### `on(event: string, callback: Function): void` + +Listen to events. Here are the events that you can listen to: +* `set` - when a key is set and it will pass in the `key` and `value`. +* `expired` - when a key is expired and it will pass in the `key` and `value`. +* `flush` - when the cache is flushed +* `flush_stats` - when the stats are flushed +* `del` - when a key is deleted and it will pass in the `key` and `value`. + +```javascript +cache.on('set', (key, value) => { + console.log(`Key ${key} has been set with value ${value}`); +}); +``` ## How to Contribute diff --git a/packages/node-cache/src/index.ts b/packages/node-cache/src/index.ts index d5811517..e0b03eab 100644 --- a/packages/node-cache/src/index.ts +++ b/packages/node-cache/src/index.ts @@ -30,9 +30,6 @@ export type NodeCacheStats = { vsize: number; // global value size count in approximately bytes }; -// eslint-disable-next-line @typescript-eslint/naming-convention -export type NodeCacheMGetReturn = Record; - export default class NodeCache extends eventemitter { public readonly options: NodeCacheOptions = { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -161,8 +158,8 @@ export default class NodeCache extends eventemitter { Gets multiple saved values from the cache. Returns an empty object {} if not found or expired. If the value was found it returns an object with the key value pair. */ - public mget(keys: Array): NodeCacheMGetReturn | Record { - const result: NodeCacheMGetReturn = {}; + public mget(keys: Array): Record { + const result: Record = {}; for (const key of keys) { const value = this.get(key); @@ -230,10 +227,11 @@ export default class NodeCache extends eventemitter { // Redefine the ttl of a key. Returns true if the key has been found and changed. // Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used. - public ttl(key: string | number, ttl: number): boolean { + public ttl(key: string | number, ttl?: number): boolean { const result = this.store.get(this.formatKey(key)); if (result) { - result.ttl = this.getExpirationTimestamp(ttl); + const ttlValue = ttl ?? this.options.stdTTL!; + result.ttl = this.getExpirationTimestamp(ttlValue); this.store.set(this.formatKey(key), result); return true; } @@ -281,6 +279,7 @@ export default class NodeCache extends eventemitter { return this.store.has(this.formatKey(key)); } + // Gets the stats of the cache. public getStats(): NodeCacheStats { return this._stats; } @@ -288,7 +287,7 @@ export default class NodeCache extends eventemitter { // Flush the whole data. public flushAll(): void { this.store.clear(); - + this.flushStats(); // Event this.emit('flush'); } diff --git a/packages/node-cache/test/index.test.ts b/packages/node-cache/test/index.test.ts index f954893c..ce8b7a6f 100644 --- a/packages/node-cache/test/index.test.ts +++ b/packages/node-cache/test/index.test.ts @@ -125,6 +125,16 @@ describe('NodeCache', () => { expect(ttl).toBe(undefined); }); + test('ttl should default to 0 if no ttl is set', () => { + const cache = new NodeCache({checkperiod: 0}); + cache.set('foo', 'bar'); // Set to 10 by stdTTL + const ttl = cache.getTtl('foo'); + expect(ttl).toBe(0); + cache.ttl('foo'); + const ttl2 = cache.getTtl('foo'); + expect(ttl2).toBeGreaterThan(ttl!); + }); + test('should return 0 if there is no key to delete', () => { const cache = new NodeCache({checkperiod: 0}); const count = cache.del('foo'); @@ -203,6 +213,7 @@ describe('NodeCache', () => { expect(cache.get('n')).toBe(1); cache.flushAll(); expect(cache.keys()).toEqual([]); + expect(cache.getStats().keys).toBe(0); }); test('should throw an error on maxKeys', () => {