@boredland/node-ts-cache 5.0.0 → 5.1.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 +24 -20
- package/dist/cache-container/cache-container-types.d.ts +7 -0
- package/dist/cache-container/cache-container.d.ts +7 -1
- package/dist/cache-container/cache-container.js +12 -9
- package/dist/decorator/cache-decorator.js +1 -1
- package/dist/withCache.d.ts +8 -4
- package/dist/withCache.js +16 -5
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
# boredland/node-ts-cache
|
|
1
|
+
# @boredland/node-ts-cache
|
|
2
2
|
|
|
3
3
|
[](https://github.com/boredland/node-ts-cache/actions/workflows/ci.yml)
|
|
4
4
|
[](http://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://coveralls.io/github/boredland/node-ts-cache?branch=main)
|
|
5
6
|
|
|
6
7
|
Simple and extensible caching module supporting decorators.
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
|
-
yarn add boredland/node-ts-cache
|
|
12
|
+
yarn add @boredland/node-ts-cache
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
_Note: The underlying storage layer must be installed separately._
|
|
@@ -17,29 +18,32 @@ _Note: The underlying storage layer must be installed separately._
|
|
|
17
18
|
|
|
18
19
|
| Storage | Install |
|
|
19
20
|
|-----------------------------------------------------------------------|-------------------------------------------------|
|
|
20
|
-
| [memory](https://www.npmjs.com/package/boredland/node-ts-cache-storage-memory)| ```yarn add boredland/node-ts-cache-storage-memory```|
|
|
21
|
-
| [node-fs](https://www.npmjs.com/package/boredland/node-ts-cache-storage-node-fs)| ```yarn add boredland/node-ts-cache-storage-node-fs```|
|
|
22
|
-
| [ioredis](https://www.npmjs.com/package/boredland/node-ts-cache-storage-ioredis)| ```yarn add boredland/node-ts-cache-storage-ioredis```|
|
|
21
|
+
| [memory](https://www.npmjs.com/package/boredland/node-ts-cache-storage-memory)| ```yarn add @boredland/node-ts-cache-storage-memory```|
|
|
22
|
+
| [node-fs](https://www.npmjs.com/package/boredland/node-ts-cache-storage-node-fs)| ```yarn add @boredland/node-ts-cache-storage-node-fs```|
|
|
23
|
+
| [ioredis](https://www.npmjs.com/package/boredland/node-ts-cache-storage-ioredis)| ```yarn add @boredland/node-ts-cache-storage-ioredis```|
|
|
23
24
|
|
|
24
25
|
## Usage
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
### withCacheFactory
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
Works with the above listed storages.
|
|
30
|
-
By default, uses all arguments to build an unique key.
|
|
29
|
+
Function wrapper factory for arbitrary functions. The cache key is caculated based on the parameters passed to the function.
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
```ts
|
|
32
|
+
import { withCacheFactory, CacheContainer } from '@boredland/node-ts-cache'
|
|
33
|
+
import { MemoryStorage } from '@boredland/node-ts-cache-storage-memory'
|
|
34
|
+
|
|
35
|
+
const doThingsCache = new CacheContainer(new MemoryStorage())
|
|
36
|
+
|
|
37
|
+
const someFn = (input: { a: string, b: number })
|
|
38
|
+
|
|
39
|
+
const wrappedFn = withCacheFactory(doThingsCache)(someFn);
|
|
40
|
+
|
|
41
|
+
const result = someFn({ a: "lala", b: 123 })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### With decorator
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
- `ttl`: _(Default: 60)_ Number of seconds to expire the cachte item
|
|
36
|
-
- `isLazy`: _(Default: true)_ If true, expired cache entries will be deleted on touch. If false, entries will be deleted after the given _ttl_.
|
|
37
|
-
- `isCachedForever`: _(Default: false)_ If true, cache entry has no expiration.
|
|
38
|
-
- `calculateKey(data => string)`: _(Default: JSON.stringify combination of className, methodName and call args)_
|
|
39
|
-
- `data`:
|
|
40
|
-
- `className`: The class name for the method being decorated
|
|
41
|
-
- `methodName`: The method name being decorated
|
|
42
|
-
- `args`: The arguments passed to the method when called
|
|
46
|
+
Caches function response using the given options. By default, uses all arguments to build an unique key.
|
|
43
47
|
|
|
44
48
|
_Note: @Cache will consider the return type of the function. If the return type is a thenable, it will stay that way, otherwise not._
|
|
45
49
|
|
|
@@ -57,7 +61,7 @@ class MyService {
|
|
|
57
61
|
}
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
### Direct usage
|
|
61
65
|
|
|
62
66
|
```ts
|
|
63
67
|
import { CacheContainer } from '@boredland/node-ts-cache'
|
|
@@ -7,12 +7,19 @@ export declare type CachedItem<T = any> = {
|
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
export declare type CachingOptions = {
|
|
10
|
+
/** (Default: 60) Number of seconds to expire the cachte item */
|
|
10
11
|
ttl: number;
|
|
12
|
+
/** (Default: true) If true, expired cache entries will be deleted on touch and returned anyway. If false, entries will be deleted after the given ttl. */
|
|
11
13
|
isLazy: boolean;
|
|
14
|
+
/** (Default: false) If true, cache entry has no expiration. */
|
|
12
15
|
isCachedForever: boolean;
|
|
16
|
+
/** (Default: JSON.stringify combination of className, methodName and call args) */
|
|
13
17
|
calculateKey: (data: {
|
|
18
|
+
/** The class name for the method being decorated */
|
|
14
19
|
className: string;
|
|
20
|
+
/** The method name being decorated */
|
|
15
21
|
methodName: string;
|
|
22
|
+
/** The arguments passed to the method when called */
|
|
16
23
|
args: any[];
|
|
17
24
|
}) => string;
|
|
18
25
|
};
|
|
@@ -3,7 +3,13 @@ import type { CachingOptions } from "./cache-container-types";
|
|
|
3
3
|
export declare class CacheContainer {
|
|
4
4
|
private storage;
|
|
5
5
|
constructor(storage: IStorage);
|
|
6
|
-
getItem<T>(key: string): Promise<
|
|
6
|
+
getItem<T>(key: string): Promise<{
|
|
7
|
+
content: T;
|
|
8
|
+
meta: {
|
|
9
|
+
expired: boolean;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
};
|
|
12
|
+
} | undefined>;
|
|
7
13
|
setItem(key: string, content: any, options: Partial<CachingOptions>): Promise<void>;
|
|
8
14
|
clear(): Promise<void>;
|
|
9
15
|
private isItemExpired;
|
|
@@ -14,11 +14,20 @@ class CacheContainer {
|
|
|
14
14
|
}
|
|
15
15
|
async getItem(key) {
|
|
16
16
|
const item = await this.storage.getItem(key);
|
|
17
|
-
if (item
|
|
17
|
+
if (!item)
|
|
18
|
+
return;
|
|
19
|
+
const result = {
|
|
20
|
+
content: item.content,
|
|
21
|
+
meta: {
|
|
22
|
+
createdAt: item.meta.createdAt,
|
|
23
|
+
expired: this.isItemExpired(item)
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
if (result.meta.expired)
|
|
18
27
|
await this.unsetKey(key);
|
|
28
|
+
if (result.meta.expired && !item.meta.isLazy)
|
|
19
29
|
return undefined;
|
|
20
|
-
|
|
21
|
-
return item ? item.content : undefined;
|
|
30
|
+
return result;
|
|
22
31
|
}
|
|
23
32
|
async setItem(key, content, options) {
|
|
24
33
|
const finalOptions = {
|
|
@@ -32,12 +41,6 @@ class CacheContainer {
|
|
|
32
41
|
isLazy: finalOptions.isLazy,
|
|
33
42
|
ttl: finalOptions.isCachedForever ? Infinity : finalOptions.ttl * 1000
|
|
34
43
|
};
|
|
35
|
-
if (!finalOptions.isCachedForever && !finalOptions.isLazy) {
|
|
36
|
-
setTimeout(() => {
|
|
37
|
-
this.unsetKey(key);
|
|
38
|
-
debug(`Expired key ${key} removed from cache`);
|
|
39
|
-
}, meta.ttl);
|
|
40
|
-
}
|
|
41
44
|
await this.storage.setItem(key, { meta, content });
|
|
42
45
|
}
|
|
43
46
|
async clear() {
|
|
@@ -46,7 +46,7 @@ function Cache(container, options) {
|
|
|
46
46
|
const entry = await container.getItem(cacheKey);
|
|
47
47
|
if (entry) {
|
|
48
48
|
debug(`Cache HIT ${cacheKey}`);
|
|
49
|
-
return entry;
|
|
49
|
+
return entry.content;
|
|
50
50
|
}
|
|
51
51
|
debug(`Cache MISS ${cacheKey}`);
|
|
52
52
|
const methodResult = await runOriginalMethod();
|
package/dist/withCache.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { CacheContainer, CachingOptions } from "./cache-container";
|
|
2
2
|
declare type WithCacheOptions<Parameters> = Partial<Omit<CachingOptions, 'calculateKey'>> & {
|
|
3
|
-
prefix
|
|
4
|
-
|
|
3
|
+
/** an optional prefix to prepend to the key */
|
|
4
|
+
prefix?: string;
|
|
5
|
+
/** an optional function to calculate a key based on the parameters of the wrapped function */
|
|
6
|
+
calculateKey?: (input: Parameters) => string;
|
|
7
|
+
/** an optional function that is called when a lazy item has expired and thus got removed */
|
|
8
|
+
afterExpired?: () => Promise<void>;
|
|
5
9
|
};
|
|
6
10
|
/**
|
|
7
11
|
* wrapped function factory
|
|
8
12
|
* @param container - cache container to create the fn for
|
|
9
|
-
* @returns
|
|
13
|
+
* @returns wrapping function
|
|
10
14
|
*/
|
|
11
|
-
export declare const withCacheFactory: (container: CacheContainer) => <Parameters_1 extends unknown[], Result extends Promise<unknown>>(operation: (...parameters: Parameters_1) => Result,
|
|
15
|
+
export declare const withCacheFactory: (container: CacheContainer) => <Parameters_1 extends unknown[], Result extends Promise<unknown>>(operation: (...parameters: Parameters_1) => Result, options?: WithCacheOptions<Parameters_1>) => (...parameters: Parameters_1) => Promise<Result>;
|
|
12
16
|
export {};
|
package/dist/withCache.js
CHANGED
|
@@ -4,18 +4,29 @@ exports.withCacheFactory = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* wrapped function factory
|
|
6
6
|
* @param container - cache container to create the fn for
|
|
7
|
-
* @returns
|
|
7
|
+
* @returns wrapping function
|
|
8
8
|
*/
|
|
9
9
|
const withCacheFactory = (container) => {
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* function wrapper
|
|
12
|
+
* @param operation - the function to be wrapped
|
|
13
|
+
* @param options - caching options
|
|
14
|
+
* @returns wrapped operation
|
|
15
|
+
*/
|
|
16
|
+
const withCache = (operation, options = {}) => {
|
|
11
17
|
return async (...parameters) => {
|
|
12
|
-
|
|
18
|
+
let { prefix, calculateKey, ...rest } = options;
|
|
19
|
+
prefix = prefix ?? 'default';
|
|
20
|
+
const key = `${operation.name}:${prefix}:${calculateKey ? calculateKey(parameters) : JSON.stringify(parameters)}`;
|
|
13
21
|
const cachedResponse = await container.getItem(key);
|
|
14
22
|
if (cachedResponse) {
|
|
15
|
-
|
|
23
|
+
if (cachedResponse.meta.expired && options.afterExpired) {
|
|
24
|
+
await options.afterExpired();
|
|
25
|
+
}
|
|
26
|
+
return cachedResponse.content;
|
|
16
27
|
}
|
|
17
28
|
const result = await operation(...parameters);
|
|
18
|
-
await container.setItem(key, result,
|
|
29
|
+
await container.setItem(key, result, rest);
|
|
19
30
|
return result;
|
|
20
31
|
};
|
|
21
32
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boredland/node-ts-cache",
|
|
3
3
|
"description": "Simple and extensible caching module supporting decorators",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.1.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"node-cache",
|
|
33
33
|
"ts-cache"
|
|
34
34
|
],
|
|
35
|
-
"author": "Himmet Avsar <avsar.himmet1@gmail.com>",
|
|
36
35
|
"license": "MIT",
|
|
37
36
|
"bugs": {
|
|
38
37
|
"url": "https://github.com/boredland/node-ts-cache/issues"
|