@naturalcycles/js-lib 14.83.1 → 14.85.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/dist/decorators/asyncMemo.decorator.d.ts +32 -9
- package/dist/decorators/asyncMemo.decorator.js +35 -33
- package/dist/decorators/decorator.util.d.ts +1 -1
- package/dist/decorators/decorator.util.js +2 -2
- package/dist/decorators/logMethod.decorator.d.ts +6 -4
- package/dist/decorators/logMethod.decorator.js +3 -3
- package/dist/decorators/memo.decorator.d.ts +27 -30
- package/dist/decorators/memo.decorator.js +31 -56
- package/dist/decorators/memo.util.d.ts +6 -6
- package/dist/decorators/memoFn.d.ts +5 -0
- package/dist/decorators/memoFn.js +21 -40
- package/dist/decorators/memoFnAsync.d.ts +10 -0
- package/dist/decorators/memoFnAsync.js +66 -0
- package/dist/decorators/memoSimple.decorator.d.ts +1 -1
- package/dist/decorators/memoSimple.decorator.js +3 -3
- package/dist/error/assert.d.ts +4 -4
- package/dist/error/error.model.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/promise/pRetry.d.ts +5 -1
- package/dist/promise/pRetry.js +6 -1
- package/dist/promise/pTimeout.d.ts +5 -0
- package/dist/promise/pTimeout.js +5 -1
- package/dist-esm/decorators/asyncMemo.decorator.js +36 -46
- package/dist-esm/decorators/decorator.util.js +2 -2
- package/dist-esm/decorators/logMethod.decorator.js +3 -3
- package/dist-esm/decorators/memo.decorator.js +30 -56
- package/dist-esm/decorators/memoFn.js +21 -40
- package/dist-esm/decorators/memoFnAsync.js +62 -0
- package/dist-esm/decorators/memoSimple.decorator.js +3 -3
- package/dist-esm/index.js +1 -0
- package/dist-esm/promise/pRetry.js +3 -1
- package/dist-esm/promise/pTimeout.js +2 -1
- package/package.json +1 -1
- package/src/decorators/asyncMemo.decorator.ts +80 -60
- package/src/decorators/decorator.util.ts +2 -2
- package/src/decorators/logMethod.decorator.ts +16 -7
- package/src/decorators/memo.decorator.ts +51 -103
- package/src/decorators/memo.util.ts +7 -7
- package/src/decorators/memoFn.ts +21 -52
- package/src/decorators/memoFnAsync.ts +87 -0
- package/src/decorators/memoSimple.decorator.ts +4 -4
- package/src/error/assert.ts +4 -4
- package/src/error/error.model.ts +2 -0
- package/src/index.ts +1 -0
- package/src/promise/pRetry.ts +12 -2
- package/src/promise/pTimeout.ts +14 -1
|
@@ -27,7 +27,7 @@ export async function pRetry(fn, opt = {}) {
|
|
|
27
27
|
return await new Promise((resolve, reject) => {
|
|
28
28
|
const rejectWithTimeout = () => {
|
|
29
29
|
timedOut = true; // to prevent more tries
|
|
30
|
-
const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms
|
|
30
|
+
const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms`, opt.errorData);
|
|
31
31
|
if (fakeError) {
|
|
32
32
|
// keep original stack
|
|
33
33
|
err.stack = fakeError.stack.replace('Error: RetryError', 'TimeoutError');
|
|
@@ -71,6 +71,8 @@ export async function pRetry(fn, opt = {}) {
|
|
|
71
71
|
fakeError.stack.replace('Error: RetryError', ''),
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
+
;
|
|
75
|
+
err.data = Object.assign(Object.assign({}, err.data), opt.errorData);
|
|
74
76
|
reject(err);
|
|
75
77
|
}
|
|
76
78
|
else {
|
|
@@ -32,11 +32,12 @@ export async function pTimeout(promise, opt) {
|
|
|
32
32
|
catch (err) {
|
|
33
33
|
if (fakeError)
|
|
34
34
|
err.stack = fakeError.stack; // keep original stack
|
|
35
|
+
err.data = Object.assign(Object.assign({}, err.data), opt.errorData);
|
|
35
36
|
reject(err);
|
|
36
37
|
}
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
|
-
const err = new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms
|
|
40
|
+
const err = new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms`, opt.errorData);
|
|
40
41
|
if (fakeError)
|
|
41
42
|
err.stack = fakeError.stack; // keep original stack
|
|
42
43
|
reject(err);
|
package/package.json
CHANGED
|
@@ -1,25 +1,51 @@
|
|
|
1
|
+
import { CommonLogger } from '../log/commonLogger'
|
|
1
2
|
import { _since } from '../time/time.util'
|
|
2
|
-
import { Merge } from '../typeFest'
|
|
3
3
|
import { AnyObject } from '../types'
|
|
4
4
|
import { _getArgsSignature, _getMethodSignature, _getTargetMethodSignature } from './decorator.util'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
5
|
+
import { AsyncMemoCache, jsonMemoSerializer, MapMemoCache } from './memo.util'
|
|
6
|
+
|
|
7
|
+
export interface AsyncMemoOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Provide a custom implementation of MemoCache.
|
|
10
|
+
* Function that creates an instance of `MemoCache`.
|
|
11
|
+
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
|
|
12
|
+
*/
|
|
13
|
+
cacheFactory?: () => AsyncMemoCache
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Provide a custom implementation of CacheKey function.
|
|
17
|
+
*/
|
|
18
|
+
cacheKeyFn?: (args: any[]) => any
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Set to `true` to cache rejected promises (errors).
|
|
22
|
+
*
|
|
23
|
+
* Default false.
|
|
24
|
+
*/
|
|
25
|
+
cacheRejections?: boolean
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Default to false
|
|
29
|
+
*/
|
|
30
|
+
logHit?: boolean
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Default to false
|
|
34
|
+
*/
|
|
35
|
+
logMiss?: boolean
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Set to `false` to skip logging method arguments.
|
|
39
|
+
*
|
|
40
|
+
* Defaults to true.
|
|
41
|
+
*/
|
|
42
|
+
logArgs?: boolean
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default to `console`
|
|
46
|
+
*/
|
|
47
|
+
logger?: CommonLogger
|
|
48
|
+
}
|
|
23
49
|
|
|
24
50
|
/**
|
|
25
51
|
* Like @_Memo, but allowing async MemoCache implementation.
|
|
@@ -29,7 +55,7 @@ export type AsyncMemoOptions = Merge<
|
|
|
29
55
|
*/
|
|
30
56
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
31
57
|
export const _AsyncMemo =
|
|
32
|
-
(opt: AsyncMemoOptions): MethodDecorator =>
|
|
58
|
+
(opt: AsyncMemoOptions = {}): MethodDecorator =>
|
|
33
59
|
(target, key, descriptor) => {
|
|
34
60
|
if (typeof descriptor.value !== 'function') {
|
|
35
61
|
throw new TypeError('Memoization can be applied only to methods')
|
|
@@ -38,17 +64,16 @@ export const _AsyncMemo =
|
|
|
38
64
|
const originalFn = descriptor.value
|
|
39
65
|
|
|
40
66
|
// Map from "instance" of the Class where @_AsyncMemo is applied to AsyncMemoCache instance.
|
|
41
|
-
const cache = new Map<AnyObject, AsyncMemoCache
|
|
67
|
+
const cache = new Map<AnyObject, AsyncMemoCache>()
|
|
42
68
|
|
|
43
69
|
const {
|
|
44
70
|
logHit = false,
|
|
45
71
|
logMiss = false,
|
|
46
|
-
|
|
72
|
+
logArgs = true,
|
|
47
73
|
logger = console,
|
|
48
|
-
cacheFactory,
|
|
74
|
+
cacheFactory = () => new MapMemoCache(),
|
|
49
75
|
cacheKeyFn = jsonMemoSerializer,
|
|
50
|
-
|
|
51
|
-
noCacheResolved = false,
|
|
76
|
+
cacheRejections = false,
|
|
52
77
|
} = opt
|
|
53
78
|
|
|
54
79
|
const keyStr = String(key)
|
|
@@ -65,29 +90,10 @@ export const _AsyncMemo =
|
|
|
65
90
|
// UPD: no! AsyncMemo supports "persistent caches" (e.g Database-backed cache)
|
|
66
91
|
}
|
|
67
92
|
|
|
68
|
-
if (args.length === 1 && args[0] === CACHE_DROP) {
|
|
69
|
-
// Special event - CACHE_DROP
|
|
70
|
-
// Function will return undefined
|
|
71
|
-
logger.log(`${methodSignature} @_AsyncMemo.dropCache()`)
|
|
72
|
-
try {
|
|
73
|
-
await Promise.all(cache.get(ctx)!.map(c => c.clear()))
|
|
74
|
-
} catch (err) {
|
|
75
|
-
logger.error(err)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
93
|
let value: any
|
|
82
94
|
|
|
83
95
|
try {
|
|
84
|
-
|
|
85
|
-
value = await cacheLayer.get(cacheKey)
|
|
86
|
-
if (value !== undefined) {
|
|
87
|
-
// it's a hit!
|
|
88
|
-
break
|
|
89
|
-
}
|
|
90
|
-
}
|
|
96
|
+
value = await cache.get(ctx)!.get(cacheKey)
|
|
91
97
|
} catch (err) {
|
|
92
98
|
// log error, but don't throw, treat it as a "miss"
|
|
93
99
|
logger.error(err)
|
|
@@ -99,7 +105,7 @@ export const _AsyncMemo =
|
|
|
99
105
|
logger.log(
|
|
100
106
|
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
|
|
101
107
|
args,
|
|
102
|
-
|
|
108
|
+
logArgs,
|
|
103
109
|
)}) @_AsyncMemo hit`,
|
|
104
110
|
)
|
|
105
111
|
}
|
|
@@ -113,25 +119,30 @@ export const _AsyncMemo =
|
|
|
113
119
|
try {
|
|
114
120
|
value = await originalFn.apply(ctx, args)
|
|
115
121
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// Save the value in the Cache, without awaiting it
|
|
123
|
+
// This is to support both sync and async functions
|
|
124
|
+
void (async () => {
|
|
125
|
+
try {
|
|
126
|
+
await cache.get(ctx)!.set(cacheKey, value)
|
|
127
|
+
} catch (err) {
|
|
128
|
+
// log and ignore the error
|
|
129
|
+
logger.error(err)
|
|
130
|
+
}
|
|
131
|
+
})()
|
|
124
132
|
|
|
125
133
|
return value
|
|
126
134
|
} catch (err) {
|
|
127
|
-
if (
|
|
135
|
+
if (cacheRejections) {
|
|
128
136
|
// We put it to cache as raw Error, not Promise.reject(err)
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
// This is to support both sync and async functions
|
|
138
|
+
void (async () => {
|
|
139
|
+
try {
|
|
140
|
+
await cache.get(ctx)!.set(cacheKey, err)
|
|
141
|
+
} catch (err) {
|
|
131
142
|
// log and ignore the error
|
|
132
143
|
logger.error(err)
|
|
133
|
-
}
|
|
134
|
-
)
|
|
144
|
+
}
|
|
145
|
+
})()
|
|
135
146
|
}
|
|
136
147
|
|
|
137
148
|
throw err
|
|
@@ -140,12 +151,21 @@ export const _AsyncMemo =
|
|
|
140
151
|
logger.log(
|
|
141
152
|
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
|
|
142
153
|
args,
|
|
143
|
-
|
|
154
|
+
logArgs,
|
|
144
155
|
)}) @_AsyncMemo miss (${_since(started)})`,
|
|
145
156
|
)
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
} as any
|
|
160
|
+
;(descriptor.value as any).dropCache = async () => {
|
|
161
|
+
logger.log(`${methodSignature} @_AsyncMemo.dropCache()`)
|
|
162
|
+
try {
|
|
163
|
+
await Promise.all([...cache.values()].map(c => c.clear()))
|
|
164
|
+
cache.clear()
|
|
165
|
+
} catch (err) {
|
|
166
|
+
logger.error(err)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
149
169
|
|
|
150
170
|
return descriptor
|
|
151
171
|
}
|
|
@@ -23,8 +23,8 @@ export function _getTargetMethodSignature(target: AnyObject, keyStr: string): st
|
|
|
23
23
|
* returns:
|
|
24
24
|
* a, b, c
|
|
25
25
|
*/
|
|
26
|
-
export function _getArgsSignature(args: any[] = [],
|
|
27
|
-
if (
|
|
26
|
+
export function _getArgsSignature(args: any[] = [], logArgs = true): string {
|
|
27
|
+
if (!logArgs) return ''
|
|
28
28
|
|
|
29
29
|
return args
|
|
30
30
|
.map(arg => {
|
|
@@ -16,14 +16,16 @@ export interface LogMethodOptions {
|
|
|
16
16
|
avg?: number
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Defaults to true.
|
|
20
|
+
* Set to false to skip logging method arguments
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
+
logArgs?: boolean
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
*
|
|
25
|
+
* Defaults to true.
|
|
26
|
+
* Set to false to skip logging result length when result is an array.
|
|
25
27
|
*/
|
|
26
|
-
|
|
28
|
+
logResultLength?: boolean
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Also log on method start.
|
|
@@ -74,12 +76,19 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
74
76
|
const originalFn = descriptor.value
|
|
75
77
|
const keyStr = String(key)
|
|
76
78
|
|
|
77
|
-
const {
|
|
79
|
+
const {
|
|
80
|
+
avg,
|
|
81
|
+
logArgs = true,
|
|
82
|
+
logStart,
|
|
83
|
+
logResult,
|
|
84
|
+
logResultLength = true,
|
|
85
|
+
logger = console,
|
|
86
|
+
} = opt
|
|
78
87
|
let { logResultFn } = opt
|
|
79
88
|
if (!logResultFn) {
|
|
80
89
|
if (logResult) {
|
|
81
90
|
logResultFn = r => ['result:', _stringifyAny(r)]
|
|
82
|
-
} else if (
|
|
91
|
+
} else if (logResultLength) {
|
|
83
92
|
logResultFn = r => (Array.isArray(r) ? [`result: ${r.length} items`] : [])
|
|
84
93
|
}
|
|
85
94
|
}
|
|
@@ -94,7 +103,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
94
103
|
// e.g `NameOfYourClass.methodName`
|
|
95
104
|
// or `NameOfYourClass(instanceId).methodName`
|
|
96
105
|
const methodSignature = _getMethodSignature(ctx, keyStr)
|
|
97
|
-
const argsStr = _getArgsSignature(args,
|
|
106
|
+
const argsStr = _getArgsSignature(args, logArgs)
|
|
98
107
|
const callSignature = `${methodSignature}(${argsStr}) #${++count}`
|
|
99
108
|
if (logStart) logger.log(`>> ${callSignature}`)
|
|
100
109
|
|
|
@@ -1,67 +1,47 @@
|
|
|
1
|
-
// Based on:
|
|
2
|
-
// https://github.com/mgechev/memo-decorator/blob/master/index.ts
|
|
3
|
-
// http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
|
|
4
|
-
// http://inlehmansterms.net/2015/03/01/javascript-memoization/
|
|
5
|
-
// https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
|
|
6
|
-
|
|
7
1
|
import { CommonLogger } from '../log/commonLogger'
|
|
8
2
|
import { _since } from '../time/time.util'
|
|
9
3
|
import { AnyObject } from '../types'
|
|
10
4
|
import { _getArgsSignature, _getMethodSignature, _getTargetMethodSignature } from './decorator.util'
|
|
11
5
|
import { jsonMemoSerializer, MapMemoCache, MemoCache } from './memo.util'
|
|
12
6
|
|
|
13
|
-
/**
|
|
14
|
-
* Symbol to indicate that the Cache should be dropped.
|
|
15
|
-
*/
|
|
16
|
-
export const CACHE_DROP = Symbol('CACHE_DROP')
|
|
17
|
-
|
|
18
7
|
export interface MemoOptions {
|
|
19
8
|
/**
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Default to false
|
|
9
|
+
* Provide a custom implementation of MemoCache.
|
|
10
|
+
* Function that creates an instance of `MemoCache`.
|
|
11
|
+
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
|
|
25
12
|
*/
|
|
26
|
-
|
|
13
|
+
cacheFactory?: () => MemoCache
|
|
27
14
|
|
|
28
15
|
/**
|
|
29
|
-
*
|
|
16
|
+
* Provide a custom implementation of CacheKey function.
|
|
30
17
|
*/
|
|
31
|
-
|
|
18
|
+
cacheKeyFn?: (args: any[]) => any
|
|
32
19
|
|
|
33
20
|
/**
|
|
34
|
-
*
|
|
21
|
+
* Defaults to false.
|
|
22
|
+
* Set to true to cache thrown errors.
|
|
35
23
|
*/
|
|
36
|
-
|
|
24
|
+
cacheErrors?: boolean
|
|
37
25
|
|
|
38
26
|
/**
|
|
39
|
-
*
|
|
40
|
-
* Function that creates an instance of `MemoCache`.
|
|
41
|
-
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
|
|
27
|
+
* Default to false
|
|
42
28
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
logHit?: boolean
|
|
45
30
|
/**
|
|
46
|
-
*
|
|
31
|
+
* Default to false
|
|
47
32
|
*/
|
|
48
|
-
|
|
33
|
+
logMiss?: boolean
|
|
49
34
|
|
|
50
35
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* Default false.
|
|
36
|
+
* Defaults to true.
|
|
37
|
+
* Set to false to skip logging method arguments.
|
|
55
38
|
*/
|
|
56
|
-
|
|
39
|
+
logArgs?: boolean
|
|
57
40
|
|
|
58
41
|
/**
|
|
59
|
-
*
|
|
60
|
-
* Setting this to `true` will make the decorator to await the result.
|
|
61
|
-
*
|
|
62
|
-
* Default false.
|
|
42
|
+
* Default to `console`
|
|
63
43
|
*/
|
|
64
|
-
|
|
44
|
+
logger?: CommonLogger
|
|
65
45
|
}
|
|
66
46
|
|
|
67
47
|
/**
|
|
@@ -73,6 +53,15 @@ export interface MemoOptions {
|
|
|
73
53
|
* If you don't want it that way - you can use a static method, then there will be only one "instance".
|
|
74
54
|
*
|
|
75
55
|
* Supports dropping it's cache by calling .dropCache() method of decorated function (useful in unit testing).
|
|
56
|
+
*
|
|
57
|
+
* Doesn't support Async functions, use @_AsyncMemo instead!
|
|
58
|
+
* (or, it will simply return the [unresolved] Promise further, without awaiting it)
|
|
59
|
+
*
|
|
60
|
+
* Based on:
|
|
61
|
+
* https://github.com/mgechev/memo-decorator/blob/master/index.ts
|
|
62
|
+
* http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
|
|
63
|
+
* http://inlehmansterms.net/2015/03/01/javascript-memoization/
|
|
64
|
+
* https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
|
|
76
65
|
*/
|
|
77
66
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
78
67
|
export const _Memo =
|
|
@@ -96,28 +85,19 @@ export const _Memo =
|
|
|
96
85
|
const {
|
|
97
86
|
logHit = false,
|
|
98
87
|
logMiss = false,
|
|
99
|
-
|
|
88
|
+
logArgs = true,
|
|
100
89
|
logger = console,
|
|
101
90
|
cacheFactory = () => new MapMemoCache(),
|
|
102
91
|
cacheKeyFn = jsonMemoSerializer,
|
|
103
|
-
|
|
104
|
-
noCacheResolved = false,
|
|
92
|
+
cacheErrors = false,
|
|
105
93
|
} = opt
|
|
106
94
|
|
|
107
|
-
const awaitPromise = Boolean(noCacheRejected || noCacheResolved)
|
|
108
95
|
const keyStr = String(key)
|
|
109
96
|
const methodSignature = _getTargetMethodSignature(target, keyStr)
|
|
110
97
|
|
|
111
98
|
descriptor.value = function (this: typeof target, ...args: any[]): any {
|
|
112
99
|
const ctx = this
|
|
113
100
|
|
|
114
|
-
if (args.length === 1 && args[0] === CACHE_DROP) {
|
|
115
|
-
// Special event - CACHE_DROP
|
|
116
|
-
// Function will return undefined
|
|
117
|
-
logger.log(`${methodSignature} @_Memo.CACHE_DROP`)
|
|
118
|
-
return cache.get(ctx)?.clear()
|
|
119
|
-
}
|
|
120
|
-
|
|
121
101
|
const cacheKey = cacheKeyFn(args)
|
|
122
102
|
|
|
123
103
|
if (!cache.has(ctx)) {
|
|
@@ -125,76 +105,44 @@ export const _Memo =
|
|
|
125
105
|
} else if (cache.get(ctx)!.has(cacheKey)) {
|
|
126
106
|
if (logHit) {
|
|
127
107
|
logger.log(
|
|
128
|
-
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(args,
|
|
108
|
+
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(args, logArgs)}) @_Memo hit`,
|
|
129
109
|
)
|
|
130
110
|
}
|
|
131
111
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (awaitPromise) {
|
|
135
|
-
return res instanceof Error ? Promise.reject(res) : Promise.resolve(res)
|
|
136
|
-
} else {
|
|
137
|
-
return res
|
|
138
|
-
}
|
|
112
|
+
return cache.get(ctx)!.get(cacheKey)
|
|
139
113
|
}
|
|
140
114
|
|
|
141
115
|
const started = Date.now()
|
|
116
|
+
let value: any
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
value = originalFn.apply(ctx, args)
|
|
142
120
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
noLogArgs,
|
|
154
|
-
)}) @_Memo miss resolved (${_since(started)})`,
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!noCacheResolved) {
|
|
159
|
-
cache.get(ctx)!.set(cacheKey, res)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return res
|
|
163
|
-
})
|
|
164
|
-
.catch(err => {
|
|
165
|
-
// console.log('REJECTED', err)
|
|
166
|
-
if (logMiss) {
|
|
167
|
-
logger.log(
|
|
168
|
-
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
|
|
169
|
-
args,
|
|
170
|
-
noLogArgs,
|
|
171
|
-
)}) @_Memo miss rejected (${_since(started)})`,
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (!noCacheRejected) {
|
|
176
|
-
// We put it to cache as raw Error, not Promise.reject(err)
|
|
177
|
-
// So, we'll need to check if it's instanceof Error to reject it or resolve
|
|
178
|
-
// Wrap as Error if it's not Error
|
|
179
|
-
cache.get(ctx)!.set(cacheKey, err instanceof Error ? err : new Error(err))
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
throw err
|
|
183
|
-
})
|
|
184
|
-
} else {
|
|
121
|
+
cache.get(ctx)!.set(cacheKey, value)
|
|
122
|
+
|
|
123
|
+
return value
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (cacheErrors) {
|
|
126
|
+
cache.get(ctx)!.set(cacheKey, err)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
throw err
|
|
130
|
+
} finally {
|
|
185
131
|
if (logMiss) {
|
|
186
132
|
logger.log(
|
|
187
133
|
`${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
|
|
188
134
|
args,
|
|
189
|
-
|
|
135
|
+
logArgs,
|
|
190
136
|
)}) @_Memo miss (${_since(started)})`,
|
|
191
137
|
)
|
|
192
138
|
}
|
|
193
|
-
|
|
194
|
-
cache.get(ctx)!.set(cacheKey, res)
|
|
195
|
-
return res
|
|
196
139
|
}
|
|
197
140
|
} as any
|
|
141
|
+
;(descriptor.value as any).dropCache = () => {
|
|
142
|
+
logger.log(`${methodSignature} @_Memo.dropCache()`)
|
|
143
|
+
cache.forEach(memoCache => memoCache.clear())
|
|
144
|
+
cache.clear()
|
|
145
|
+
}
|
|
198
146
|
|
|
199
147
|
return descriptor
|
|
200
148
|
}
|
|
@@ -11,8 +11,8 @@ export const jsonMemoSerializer: MemoSerializer = args => {
|
|
|
11
11
|
|
|
12
12
|
export interface MemoCache<KEY = any, VALUE = any> {
|
|
13
13
|
has(k: KEY): boolean
|
|
14
|
-
get(k: KEY): VALUE | undefined
|
|
15
|
-
set(k: KEY, v: VALUE): void
|
|
14
|
+
get(k: KEY): VALUE | Error | undefined
|
|
15
|
+
set(k: KEY, v: VALUE | Error): void
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Clear is only called when `.dropCache()` is called.
|
|
@@ -29,8 +29,8 @@ export interface AsyncMemoCache<KEY = any, VALUE = any> {
|
|
|
29
29
|
* This also means that you CANNOT store `undefined` value in the Cache, as it'll be treated as a MISS.
|
|
30
30
|
* You CAN store `null` value instead, it will be treated as a HIT.
|
|
31
31
|
*/
|
|
32
|
-
get(k: KEY): Promisable<VALUE | undefined>
|
|
33
|
-
set(k: KEY, v: VALUE): Promisable<void>
|
|
32
|
+
get(k: KEY): Promisable<VALUE | Error | undefined>
|
|
33
|
+
set(k: KEY, v: VALUE | Error): Promisable<void>
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Clear is only called when `.dropCache()` is called.
|
|
@@ -88,17 +88,17 @@ export class ObjectMemoCache implements MemoCache {
|
|
|
88
88
|
export class MapMemoCache<KEY = any, VALUE = any>
|
|
89
89
|
implements MemoCache<KEY, VALUE>, AsyncMemoCache<KEY, VALUE>
|
|
90
90
|
{
|
|
91
|
-
private m = new Map<KEY, VALUE>()
|
|
91
|
+
private m = new Map<KEY, VALUE | Error>()
|
|
92
92
|
|
|
93
93
|
has(k: KEY): boolean {
|
|
94
94
|
return this.m.has(k)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
get(k: KEY): VALUE | undefined {
|
|
97
|
+
get(k: KEY): VALUE | Error | undefined {
|
|
98
98
|
return this.m.get(k)
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
set(k: KEY, v: VALUE): void {
|
|
101
|
+
set(k: KEY, v: VALUE | Error): void {
|
|
102
102
|
this.m.set(k, v)
|
|
103
103
|
}
|
|
104
104
|
|