@extra-memoize/memory-cache 0.2.8 → 0.2.10
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 +8 -0
- package/lib/es2015/caches/cache.d.ts +8 -0
- package/lib/es2015/caches/cache.js +28 -0
- package/lib/es2015/caches/cache.js.map +1 -0
- package/lib/es2015/caches/index.d.ts +1 -0
- package/lib/es2015/caches/index.js +1 -0
- package/lib/es2015/caches/index.js.map +1 -1
- package/lib/es2018/caches/cache.d.ts +8 -0
- package/lib/es2018/caches/cache.js +28 -0
- package/lib/es2018/caches/cache.js.map +1 -0
- package/lib/es2018/caches/index.d.ts +1 -0
- package/lib/es2018/caches/index.js +1 -0
- package/lib/es2018/caches/index.js.map +1 -1
- package/package.json +2 -2
- package/src/caches/cache.ts +25 -0
- package/src/caches/expirable-cache-with-stale-if-error.ts +39 -0
- package/src/caches/expirable-cache-with-stale-while-revalidate-and-stale-if-error.ts +51 -0
- package/src/caches/expirable-cache-with-stale-while-revalidate.ts +40 -0
- package/src/caches/expirable-cache.ts +26 -0
- package/src/caches/index.ts +13 -0
- package/src/caches/lru-cache.ts +26 -0
- package/src/caches/tlru-cache-with-stale-if-error.ts +43 -0
- package/src/caches/tlru-cache-with-stale-while-revalidate-and-stale-if-error.ts +52 -0
- package/src/caches/tlru-cache-with-stale-while-revalidate.ts +44 -0
- package/src/caches/tlru-cache.ts +26 -0
- package/src/index.ts +1 -0
- package/CHANGELOG.md +0 -42
- package/dist/es2015/index.min.mjs +0 -2
- package/dist/es2015/index.min.mjs.map +0 -1
- package/dist/es2015/index.mjs +0 -22850
- package/dist/es2015/index.mjs.map +0 -1
- package/dist/es2015/index.umd.js +0 -22868
- package/dist/es2015/index.umd.js.map +0 -1
- package/dist/es2015/index.umd.min.js +0 -2
- package/dist/es2015/index.umd.min.js.map +0 -1
- package/dist/es2018/index.min.mjs +0 -2
- package/dist/es2018/index.min.mjs.map +0 -1
- package/dist/es2018/index.mjs +0 -22850
- package/dist/es2018/index.mjs.map +0 -1
- package/dist/es2018/index.umd.js +0 -22868
- package/dist/es2018/index.umd.js.map +0 -1
- package/dist/es2018/index.umd.min.js +0 -2
- package/dist/es2018/index.umd.min.js.map +0 -1
package/README.md
CHANGED
@@ -7,11 +7,19 @@ yarn add @extra-memoize/memory-cache
|
|
7
7
|
```
|
8
8
|
|
9
9
|
## API
|
10
|
+
### Cache
|
11
|
+
```ts
|
12
|
+
class Cache<T> implements ICache<T> {
|
13
|
+
clear(): void
|
14
|
+
}
|
15
|
+
```
|
16
|
+
|
10
17
|
### LRUCache
|
11
18
|
```ts
|
12
19
|
class LRUCache<T> implements ICache<T> {
|
13
20
|
constructor(limit: number)
|
14
21
|
|
22
|
+
delete(key: string): void
|
15
23
|
clear(): void
|
16
24
|
}
|
17
25
|
```
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Cache = void 0;
|
4
|
+
const extra_memoize_1 = require("extra-memoize");
|
5
|
+
class Cache {
|
6
|
+
constructor() {
|
7
|
+
this.map = new Map();
|
8
|
+
}
|
9
|
+
set(key, value) {
|
10
|
+
this.map.set(key, value);
|
11
|
+
}
|
12
|
+
get(key) {
|
13
|
+
if (this.map.has(key)) {
|
14
|
+
return [extra_memoize_1.State.Hit, this.map.get(key)];
|
15
|
+
}
|
16
|
+
else {
|
17
|
+
return [extra_memoize_1.State.Miss];
|
18
|
+
}
|
19
|
+
}
|
20
|
+
delete(key) {
|
21
|
+
this.map.delete(key);
|
22
|
+
}
|
23
|
+
clear() {
|
24
|
+
this.map.clear();
|
25
|
+
}
|
26
|
+
}
|
27
|
+
exports.Cache = Cache;
|
28
|
+
//# sourceMappingURL=cache.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/caches/cache.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAa,KAAK;IAAlB;QACU,QAAG,GAAG,IAAI,GAAG,EAAE,CAAA;IAqBzB,CAAC;IAnBC,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACrB,OAAO,CAAC,qBAAK,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;SACtC;aAAM;YACL,OAAO,CAAC,qBAAK,CAAC,IAAI,CAAC,CAAA;SACpB;IACH,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;IAClB,CAAC;CACF;AAtBD,sBAsBC"}
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./cache"), exports);
|
17
18
|
__exportStar(require("./lru-cache"), exports);
|
18
19
|
__exportStar(require("./expirable-cache"), exports);
|
19
20
|
__exportStar(require("./expirable-cache-with-stale-while-revalidate"), exports);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/caches/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B;AAE3B,oDAAiC;AACjC,gFAA6D;AAC7D,wEAAqD;AACrD,mGAAgF;AAEhF,+CAA4B;AAC5B,2EAAwD;AACxD,mEAAgD;AAChD,8FAA2E"}
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/caches/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AAEvB,8CAA2B;AAE3B,oDAAiC;AACjC,gFAA6D;AAC7D,wEAAqD;AACrD,mGAAgF;AAEhF,+CAA4B;AAC5B,2EAAwD;AACxD,mEAAgD;AAChD,8FAA2E"}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Cache = void 0;
|
4
|
+
const extra_memoize_1 = require("extra-memoize");
|
5
|
+
class Cache {
|
6
|
+
constructor() {
|
7
|
+
this.map = new Map();
|
8
|
+
}
|
9
|
+
set(key, value) {
|
10
|
+
this.map.set(key, value);
|
11
|
+
}
|
12
|
+
get(key) {
|
13
|
+
if (this.map.has(key)) {
|
14
|
+
return [extra_memoize_1.State.Hit, this.map.get(key)];
|
15
|
+
}
|
16
|
+
else {
|
17
|
+
return [extra_memoize_1.State.Miss];
|
18
|
+
}
|
19
|
+
}
|
20
|
+
delete(key) {
|
21
|
+
this.map.delete(key);
|
22
|
+
}
|
23
|
+
clear() {
|
24
|
+
this.map.clear();
|
25
|
+
}
|
26
|
+
}
|
27
|
+
exports.Cache = Cache;
|
28
|
+
//# sourceMappingURL=cache.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/caches/cache.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAa,KAAK;IAAlB;QACU,QAAG,GAAG,IAAI,GAAG,EAAE,CAAA;IAqBzB,CAAC;IAnBC,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACrB,OAAO,CAAC,qBAAK,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;SACtC;aAAM;YACL,OAAO,CAAC,qBAAK,CAAC,IAAI,CAAC,CAAA;SACpB;IACH,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;IAClB,CAAC;CACF;AAtBD,sBAsBC"}
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./cache"), exports);
|
17
18
|
__exportStar(require("./lru-cache"), exports);
|
18
19
|
__exportStar(require("./expirable-cache"), exports);
|
19
20
|
__exportStar(require("./expirable-cache-with-stale-while-revalidate"), exports);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/caches/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B;AAE3B,oDAAiC;AACjC,gFAA6D;AAC7D,wEAAqD;AACrD,mGAAgF;AAEhF,+CAA4B;AAC5B,2EAAwD;AACxD,mEAAgD;AAChD,8FAA2E"}
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/caches/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AAEvB,8CAA2B;AAE3B,oDAAiC;AACjC,gFAA6D;AAC7D,wEAAqD;AACrD,mGAAgF;AAEhF,+CAA4B;AAC5B,2EAAwD;AACxD,mEAAgD;AAChD,8FAA2E"}
|
package/package.json
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
import { ICache, State } from 'extra-memoize'
|
2
|
+
|
3
|
+
export class Cache<T> implements ICache<T> {
|
4
|
+
private map = new Map()
|
5
|
+
|
6
|
+
set(key: string, value: T): void {
|
7
|
+
this.map.set(key, value)
|
8
|
+
}
|
9
|
+
|
10
|
+
get(key: string): [State.Miss] | [State.Hit, T] {
|
11
|
+
if (this.map.has(key)) {
|
12
|
+
return [State.Hit, this.map.get(key)]
|
13
|
+
} else {
|
14
|
+
return [State.Miss]
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
delete(key: string): void {
|
19
|
+
this.map.delete(key)
|
20
|
+
}
|
21
|
+
|
22
|
+
clear(): void {
|
23
|
+
this.map.clear()
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { ExpirableCache } from './expirable-cache'
|
2
|
+
import { IStaleIfErrorCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class ExpirableCacheWithStaleIfError<T> implements IStaleIfErrorCache<T> {
|
10
|
+
private cache: ExpirableCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(private timeToLive: number, private staleIfError: number) {
|
13
|
+
this.cache = new ExpirableCache(timeToLive + staleIfError)
|
14
|
+
}
|
15
|
+
|
16
|
+
set(key: string, value: T): void {
|
17
|
+
this.cache.set(key, {
|
18
|
+
value
|
19
|
+
, updatedAt: Date.now()
|
20
|
+
})
|
21
|
+
}
|
22
|
+
|
23
|
+
get(key: string): [State.Miss] | [State.Hit | State.StaleIfError, T] {
|
24
|
+
const [state, record] = this.cache.get(key)
|
25
|
+
if (state === State.Miss) {
|
26
|
+
return [State.Miss]
|
27
|
+
} else {
|
28
|
+
const elapsed = Date.now() - record.updatedAt
|
29
|
+
if (elapsed <= this.timeToLive) {
|
30
|
+
return [State.Hit, record.value]
|
31
|
+
} else if (elapsed <= this.timeToLive + this.staleIfError) {
|
32
|
+
return [State.StaleIfError, record.value]
|
33
|
+
} else {
|
34
|
+
// just in case
|
35
|
+
return [State.Miss]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import { ExpirableCache } from './expirable-cache'
|
2
|
+
import { IStaleWhileRevalidateAndStaleIfErrorCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class ExpirableCacheWithStaleWhileRevalidateAndStaleIfError<T> implements IStaleWhileRevalidateAndStaleIfErrorCache<T> {
|
10
|
+
private cache: ExpirableCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(
|
13
|
+
private timeToLive: number
|
14
|
+
, private staleWhileRevalidate: number
|
15
|
+
, private staleIfError: number
|
16
|
+
) {
|
17
|
+
this.cache = new ExpirableCache(timeToLive + staleWhileRevalidate + staleIfError)
|
18
|
+
}
|
19
|
+
|
20
|
+
set(key: string, value: T): void {
|
21
|
+
this.cache.set(key, {
|
22
|
+
value
|
23
|
+
, updatedAt: Date.now()
|
24
|
+
})
|
25
|
+
}
|
26
|
+
|
27
|
+
get(key: string): [State.Miss]
|
28
|
+
| [
|
29
|
+
| State.Hit
|
30
|
+
| State.StaleWhileRevalidate
|
31
|
+
| State.StaleIfError
|
32
|
+
, T
|
33
|
+
] {
|
34
|
+
const [state, record] = this.cache.get(key)
|
35
|
+
if (state === State.Miss) {
|
36
|
+
return [State.Miss]
|
37
|
+
} else {
|
38
|
+
const elapsed = Date.now() - record.updatedAt
|
39
|
+
if (elapsed <= this.timeToLive) {
|
40
|
+
return [State.Hit, record.value]
|
41
|
+
} else if (elapsed <= this.timeToLive + this.staleWhileRevalidate) {
|
42
|
+
return [State.StaleWhileRevalidate, record.value]
|
43
|
+
} else if (elapsed <= this.timeToLive + this.staleWhileRevalidate + this.staleIfError) {
|
44
|
+
return [State.StaleIfError, record.value]
|
45
|
+
} else {
|
46
|
+
// just in case
|
47
|
+
return [State.Miss]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { ExpirableCache } from './expirable-cache'
|
2
|
+
import { IStaleWhileRevalidateCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class ExpirableCacheWithStaleWhileRevalidate<T> implements IStaleWhileRevalidateCache<T> {
|
10
|
+
private cache: ExpirableCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(private timeToLive: number, private staleWhileRevalidate: number) {
|
13
|
+
this.cache = new ExpirableCache(timeToLive + staleWhileRevalidate)
|
14
|
+
}
|
15
|
+
|
16
|
+
set(key: string, value: T): void {
|
17
|
+
this.cache.set(key, {
|
18
|
+
value
|
19
|
+
, updatedAt: Date.now()
|
20
|
+
})
|
21
|
+
}
|
22
|
+
|
23
|
+
get(key: string): [State.Miss] | [State.Hit | State.StaleWhileRevalidate, T] {
|
24
|
+
const [state, record] = this.cache.get(key)
|
25
|
+
if (state === State.Miss) {
|
26
|
+
return [State.Miss]
|
27
|
+
} else {
|
28
|
+
if (this.isStaleWhileRevalidate(record)) {
|
29
|
+
return [State.StaleWhileRevalidate, record.value]
|
30
|
+
} else {
|
31
|
+
return [State.Hit, record.value]
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
private isStaleWhileRevalidate(record: IRecord<T>): boolean {
|
37
|
+
return Date.now() - record.updatedAt > this.timeToLive
|
38
|
+
&& Date.now() - record.updatedAt <= this.timeToLive + this.staleWhileRevalidate
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { ExpirableMap } from '@blackglory/structures'
|
2
|
+
import { ICache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
export class ExpirableCache<T> implements ICache<T> {
|
5
|
+
private map: ExpirableMap<string, T>
|
6
|
+
|
7
|
+
constructor(private timeToLive: number) {
|
8
|
+
this.map = new ExpirableMap()
|
9
|
+
}
|
10
|
+
|
11
|
+
get(key: string): [State.Miss] | [State.Hit, T] {
|
12
|
+
if (this.map.has(key)) {
|
13
|
+
return [State.Hit, this.map.get(key)!]
|
14
|
+
} else {
|
15
|
+
return [State.Miss]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
set(key: string, value: T): void {
|
20
|
+
this.map.set(key, value, this.timeToLive)
|
21
|
+
}
|
22
|
+
|
23
|
+
clear(): void {
|
24
|
+
this.map.clear()
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export * from './cache'
|
2
|
+
|
3
|
+
export * from './lru-cache'
|
4
|
+
|
5
|
+
export * from './expirable-cache'
|
6
|
+
export * from './expirable-cache-with-stale-while-revalidate'
|
7
|
+
export * from './expirable-cache-with-stale-if-error'
|
8
|
+
export * from './expirable-cache-with-stale-while-revalidate-and-stale-if-error'
|
9
|
+
|
10
|
+
export * from './tlru-cache'
|
11
|
+
export * from './tlru-cache-with-stale-while-revalidate'
|
12
|
+
export * from './tlru-cache-with-stale-if-error'
|
13
|
+
export * from './tlru-cache-with-stale-while-revalidate-and-stale-if-error'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { LRUMap } from '@blackglory/structures'
|
2
|
+
import { ICache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
export class LRUCache<T> implements ICache<T> {
|
5
|
+
private map: LRUMap<string, T>
|
6
|
+
|
7
|
+
constructor(limit: number) {
|
8
|
+
this.map = new LRUMap(limit)
|
9
|
+
}
|
10
|
+
|
11
|
+
set(key: string, value: T): void {
|
12
|
+
this.map.set(key, value)
|
13
|
+
}
|
14
|
+
|
15
|
+
get(key: string): [State.Miss] | [State.Hit, T] {
|
16
|
+
if (this.map.has(key)) {
|
17
|
+
return [State.Hit, this.map.get(key)!]
|
18
|
+
} else {
|
19
|
+
return [State.Miss]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
clear(): void {
|
24
|
+
this.map.clear()
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { TLRUCache } from './tlru-cache'
|
2
|
+
import { IStaleIfErrorCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class TLRUCacheWithStaleIfError<T> implements IStaleIfErrorCache<T> {
|
10
|
+
private cache: TLRUCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(
|
13
|
+
limit: number
|
14
|
+
, private timeToLive: number
|
15
|
+
, private staleIfError: number
|
16
|
+
) {
|
17
|
+
this.cache = new TLRUCache(limit, timeToLive + staleIfError)
|
18
|
+
}
|
19
|
+
|
20
|
+
set(key: string, value: T): void {
|
21
|
+
this.cache.set(key, {
|
22
|
+
value
|
23
|
+
, updatedAt: Date.now()
|
24
|
+
})
|
25
|
+
}
|
26
|
+
|
27
|
+
get(key: string): [State.Miss] | [State.Hit | State.StaleIfError, T] {
|
28
|
+
const [state, record] = this.cache.get(key)
|
29
|
+
if (state === State.Miss) {
|
30
|
+
return [State.Miss]
|
31
|
+
} else {
|
32
|
+
const elapsed = Date.now() - record.updatedAt
|
33
|
+
if (elapsed <= this.timeToLive) {
|
34
|
+
return [State.Hit, record.value]
|
35
|
+
} else if (elapsed <= this.timeToLive + this.staleIfError) {
|
36
|
+
return [State.StaleIfError, record.value]
|
37
|
+
} else {
|
38
|
+
// just in case
|
39
|
+
return [State.Miss]
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { TLRUCache } from './tlru-cache'
|
2
|
+
import { IStaleWhileRevalidateAndStaleIfErrorCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class TLRUCacheWithStaleWhileRevalidateAndStaleIfError<T> implements IStaleWhileRevalidateAndStaleIfErrorCache<T> {
|
10
|
+
private cache: TLRUCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(
|
13
|
+
limit: number
|
14
|
+
, private timeToLive: number
|
15
|
+
, private staleWhileRevalidate: number
|
16
|
+
, private staleIfError: number
|
17
|
+
) {
|
18
|
+
this.cache = new TLRUCache(limit, timeToLive + staleWhileRevalidate + staleIfError)
|
19
|
+
}
|
20
|
+
|
21
|
+
set(key: string, value: T): void {
|
22
|
+
this.cache.set(key, {
|
23
|
+
value
|
24
|
+
, updatedAt: Date.now()
|
25
|
+
})
|
26
|
+
}
|
27
|
+
|
28
|
+
get(key: string): [State.Miss]
|
29
|
+
| [
|
30
|
+
| State.Hit
|
31
|
+
| State.StaleWhileRevalidate
|
32
|
+
| State.StaleIfError
|
33
|
+
, T
|
34
|
+
] {
|
35
|
+
const [state, record] = this.cache.get(key)
|
36
|
+
if (state === State.Miss) {
|
37
|
+
return [State.Miss]
|
38
|
+
} else {
|
39
|
+
const elapsed = Date.now() - record.updatedAt
|
40
|
+
if (elapsed <= this.timeToLive) {
|
41
|
+
return [State.Hit, record.value]
|
42
|
+
} else if (elapsed <= this.timeToLive + this.staleWhileRevalidate) {
|
43
|
+
return [State.StaleWhileRevalidate, record.value]
|
44
|
+
} else if (elapsed <= this.timeToLive + this.staleWhileRevalidate + this.staleIfError) {
|
45
|
+
return [State.StaleIfError, record.value]
|
46
|
+
} else {
|
47
|
+
// just in case
|
48
|
+
return [State.Miss]
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import { TLRUCache } from './tlru-cache'
|
2
|
+
import { IStaleWhileRevalidateCache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
interface IRecord<T> {
|
5
|
+
updatedAt: number
|
6
|
+
value: T
|
7
|
+
}
|
8
|
+
|
9
|
+
export class TLRUCacheWithStaleWhileRevalidate<T> implements IStaleWhileRevalidateCache<T> {
|
10
|
+
private cache: TLRUCache<IRecord<T>>
|
11
|
+
|
12
|
+
constructor(
|
13
|
+
limit: number
|
14
|
+
, private timeToLive: number
|
15
|
+
, private staleWhileRevalidate: number
|
16
|
+
) {
|
17
|
+
this.cache = new TLRUCache(limit, timeToLive + staleWhileRevalidate)
|
18
|
+
}
|
19
|
+
|
20
|
+
set(key: string, value: T): void {
|
21
|
+
this.cache.set(key, {
|
22
|
+
value
|
23
|
+
, updatedAt: Date.now()
|
24
|
+
})
|
25
|
+
}
|
26
|
+
|
27
|
+
get(key: string): [State.Miss] | [State.Hit | State.StaleWhileRevalidate, T] {
|
28
|
+
const [state, record] = this.cache.get(key)
|
29
|
+
if (state === State.Miss) {
|
30
|
+
return [State.Miss]
|
31
|
+
} else {
|
32
|
+
if (this.isStaleWhileRevalidate(record)) {
|
33
|
+
return [State.StaleWhileRevalidate, record.value]
|
34
|
+
} else {
|
35
|
+
return [State.Hit, record.value]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
isStaleWhileRevalidate(record: IRecord<T>): boolean {
|
41
|
+
return Date.now() - record.updatedAt > this.timeToLive
|
42
|
+
&& Date.now() - record.updatedAt <= this.timeToLive + this.staleWhileRevalidate
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { TLRUMap } from '@blackglory/structures'
|
2
|
+
import { ICache, State } from 'extra-memoize'
|
3
|
+
|
4
|
+
export class TLRUCache<T> implements ICache<T> {
|
5
|
+
private map: TLRUMap<string, T>
|
6
|
+
|
7
|
+
constructor(limit: number, private timeToLive: number) {
|
8
|
+
this.map = new TLRUMap(limit)
|
9
|
+
}
|
10
|
+
|
11
|
+
set(key: string, value: T): void {
|
12
|
+
this.map.set(key, value, this.timeToLive)
|
13
|
+
}
|
14
|
+
|
15
|
+
get(key: string): [State.Miss] | [State.Hit, T] {
|
16
|
+
if (this.map.has(key)) {
|
17
|
+
return [State.Hit, this.map.get(key)!]
|
18
|
+
} else {
|
19
|
+
return [State.Miss]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
clear(): void {
|
24
|
+
this.map.clear()
|
25
|
+
}
|
26
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from '@caches'
|
package/CHANGELOG.md
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
4
|
-
|
5
|
-
### [0.2.8](https://github.com/extra-memoize/memory-cache/compare/v0.2.7...v0.2.8) (2023-01-28)
|
6
|
-
|
7
|
-
|
8
|
-
### Bug Fixes
|
9
|
-
|
10
|
-
* dependencies ([814b9df](https://github.com/extra-memoize/memory-cache/commit/814b9df8512f4b4dc6470b1fa1ec1ed31dbd3f83))
|
11
|
-
|
12
|
-
### [0.2.7](https://github.com/extra-memoize/memory-cache/compare/v0.2.6...v0.2.7) (2023-01-28)
|
13
|
-
|
14
|
-
### [0.2.6](https://github.com/extra-memoize/memory-cache/compare/v0.2.5...v0.2.6) (2023-01-21)
|
15
|
-
|
16
|
-
### [0.2.5](https://github.com/extra-memoize/memory-cache/compare/v0.2.4...v0.2.5) (2022-11-03)
|
17
|
-
|
18
|
-
### [0.2.4](https://github.com/extra-memoize/memory-cache/compare/v0.2.3...v0.2.4) (2022-09-09)
|
19
|
-
|
20
|
-
### [0.2.3](https://github.com/extra-memoize/memory-cache/compare/v0.2.2...v0.2.3) (2022-08-06)
|
21
|
-
|
22
|
-
### [0.2.2](https://github.com/extra-memoize/memory-cache/compare/v0.2.1...v0.2.2) (2022-08-04)
|
23
|
-
|
24
|
-
### [0.2.1](https://github.com/extra-memoize/memory-cache/compare/v0.2.0...v0.2.1) (2022-06-26)
|
25
|
-
|
26
|
-
## [0.2.0](https://github.com/extra-memoize/memory-cache/compare/v0.1.0...v0.2.0) (2022-05-10)
|
27
|
-
|
28
|
-
|
29
|
-
### ⚠ BREAKING CHANGES
|
30
|
-
|
31
|
-
* use extra-memoize@0.6
|
32
|
-
|
33
|
-
### Features
|
34
|
-
|
35
|
-
* use extra-memoize@0.6 ([9e72236](https://github.com/extra-memoize/memory-cache/commit/9e72236114a1764166d479afe384193081c727b3))
|
36
|
-
|
37
|
-
## 0.1.0 (2022-04-08)
|
38
|
-
|
39
|
-
|
40
|
-
### Features
|
41
|
-
|
42
|
-
* init ([5c4d170](https://github.com/extra-memoize/memory-cache/commit/5c4d170569bb5aec61987ebac77f770d45a6cff7))
|