ts-cache-mongoose 2.0.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 +68 -16
- package/dist/index.cjs +154 -132
- package/dist/index.d.cts +52 -10
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +52 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +154 -132
- package/dist/nest/index.cjs +4 -1
- package/dist/nest/index.mjs +4 -1
- package/package.json +22 -24
- package/biome.json +0 -47
- package/src/cache/Cache.ts +0 -72
- package/src/cache/engine/MemoryCacheEngine.ts +0 -41
- package/src/cache/engine/RedisCacheEngine.ts +0 -52
- package/src/extend/aggregate.ts +0 -52
- package/src/extend/query.ts +0 -82
- package/src/index.ts +0 -68
- package/src/key.ts +0 -10
- package/src/ms.ts +0 -55
- package/src/nest/cache.module.ts +0 -79
- package/src/nest/cache.service.ts +0 -37
- package/src/nest/index.ts +0 -4
- package/src/nest/interfaces.ts +0 -17
- package/src/sort-keys.ts +0 -38
- package/src/types.ts +0 -20
- package/src/version.ts +0 -18
- package/tests/cache-debug.test.ts +0 -73
- package/tests/cache-memory.test.ts +0 -217
- package/tests/cache-options.test.ts +0 -83
- package/tests/cache-redis.test.ts +0 -521
- package/tests/key.test.ts +0 -103
- package/tests/models/Story.ts +0 -29
- package/tests/models/User.ts +0 -39
- package/tests/mongo/.gitignore +0 -3
- package/tests/mongo/server.ts +0 -29
- package/tests/ms.test.ts +0 -93
- package/tests/nest.test.ts +0 -158
- package/tests/sort-keys.test.ts +0 -80
- package/tsconfig.json +0 -34
- package/vite.config.mts +0 -23
package/dist/index.d.cts
CHANGED
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
import { Mongoose } from 'mongoose';
|
|
2
2
|
import { RedisOptions } from 'ioredis';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
declare const UNITS: {
|
|
5
|
+
readonly milliseconds: 1;
|
|
6
|
+
readonly millisecond: 1;
|
|
7
|
+
readonly msecs: 1;
|
|
8
|
+
readonly msec: 1;
|
|
9
|
+
readonly ms: 1;
|
|
10
|
+
readonly seconds: 1000;
|
|
11
|
+
readonly second: 1000;
|
|
12
|
+
readonly secs: 1000;
|
|
13
|
+
readonly sec: 1000;
|
|
14
|
+
readonly s: 1000;
|
|
15
|
+
readonly minutes: number;
|
|
16
|
+
readonly minute: number;
|
|
17
|
+
readonly mins: number;
|
|
18
|
+
readonly min: number;
|
|
19
|
+
readonly m: number;
|
|
20
|
+
readonly hours: number;
|
|
21
|
+
readonly hour: number;
|
|
22
|
+
readonly hrs: number;
|
|
23
|
+
readonly hr: number;
|
|
24
|
+
readonly h: number;
|
|
25
|
+
readonly days: number;
|
|
26
|
+
readonly day: number;
|
|
27
|
+
readonly d: number;
|
|
28
|
+
readonly weeks: number;
|
|
29
|
+
readonly week: number;
|
|
30
|
+
readonly w: number;
|
|
31
|
+
readonly months: number;
|
|
32
|
+
readonly month: number;
|
|
33
|
+
readonly mo: number;
|
|
34
|
+
readonly years: number;
|
|
35
|
+
readonly year: number;
|
|
36
|
+
readonly yrs: number;
|
|
37
|
+
readonly yr: number;
|
|
38
|
+
readonly y: number;
|
|
39
|
+
};
|
|
40
|
+
type Unit = keyof typeof UNITS;
|
|
41
|
+
type Duration = number | `${number}` | `${number}${Unit}` | `${number} ${Unit}`;
|
|
42
|
+
|
|
5
43
|
type CacheData = Record<string, unknown> | Record<string, unknown>[] | unknown[] | number | undefined;
|
|
6
44
|
type CacheOptions = {
|
|
7
45
|
engine: 'memory' | 'redis';
|
|
8
46
|
engineOptions?: RedisOptions;
|
|
9
|
-
defaultTTL?:
|
|
47
|
+
defaultTTL?: Duration;
|
|
10
48
|
debug?: boolean;
|
|
49
|
+
onError?: (error: Error) => void;
|
|
50
|
+
maxEntries?: number;
|
|
51
|
+
maxBytes?: number;
|
|
52
|
+
sizeCalculation?: (value: CacheData) => number;
|
|
11
53
|
};
|
|
12
54
|
interface CacheEngine {
|
|
13
55
|
get: (key: string) => Promise<CacheData> | CacheData;
|
|
14
|
-
set: (key: string, value: CacheData, ttl?:
|
|
56
|
+
set: (key: string, value: CacheData, ttl?: Duration) => Promise<void> | void;
|
|
15
57
|
del: (key: string) => Promise<void> | void;
|
|
16
58
|
clear: () => Promise<void> | void;
|
|
17
59
|
close: () => Promise<void> | void;
|
|
@@ -19,11 +61,11 @@ interface CacheEngine {
|
|
|
19
61
|
|
|
20
62
|
declare module 'mongoose' {
|
|
21
63
|
interface Query<ResultType, DocType, THelpers, RawDocType> {
|
|
22
|
-
cache: (this: Query<ResultType, DocType, THelpers, RawDocType>, ttl?:
|
|
64
|
+
cache: (this: Query<ResultType, DocType, THelpers, RawDocType>, ttl?: Duration, customKey?: string) => this;
|
|
23
65
|
_key: string | null;
|
|
24
66
|
getCacheKey: (this: Query<ResultType, DocType, THelpers, RawDocType>) => string;
|
|
25
|
-
_ttl:
|
|
26
|
-
|
|
67
|
+
_ttl: Duration | null;
|
|
68
|
+
getDuration: (this: Query<ResultType, DocType, THelpers, RawDocType>) => Duration | null;
|
|
27
69
|
op?: string;
|
|
28
70
|
_path?: unknown;
|
|
29
71
|
_fields?: unknown;
|
|
@@ -31,11 +73,11 @@ declare module 'mongoose' {
|
|
|
31
73
|
_conditions?: unknown;
|
|
32
74
|
}
|
|
33
75
|
interface Aggregate<ResultType> {
|
|
34
|
-
cache: (this: Aggregate<ResultType>, ttl?:
|
|
76
|
+
cache: (this: Aggregate<ResultType>, ttl?: Duration, customKey?: string) => this;
|
|
35
77
|
_key: string | null;
|
|
36
78
|
getCacheKey: (this: Aggregate<ResultType>) => string;
|
|
37
|
-
_ttl:
|
|
38
|
-
|
|
79
|
+
_ttl: Duration | null;
|
|
80
|
+
getDuration: (this: Aggregate<ResultType>) => Duration | null;
|
|
39
81
|
}
|
|
40
82
|
}
|
|
41
83
|
declare class CacheMongoose {
|
|
@@ -48,5 +90,5 @@ declare class CacheMongoose {
|
|
|
48
90
|
}
|
|
49
91
|
|
|
50
92
|
export { CacheMongoose as default };
|
|
51
|
-
export type { CacheData, CacheEngine, CacheOptions,
|
|
93
|
+
export type { CacheData, CacheEngine, CacheOptions, Duration };
|
|
52
94
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sources":["../src/types.ts","../src/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","sources":["../src/ms.ts","../src/types.ts","../src/index.ts"],"mappings":";;;AAQA,cAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCZ,KAAM,IAAI,gBAAgB,KAAK;AAE/B,KAAM,QAAQ,sCAAsC,IAAI,kBAAkB,IAAI;;AC1C9E,KAAM,SAAS,GAAG,MAAM,oBAAoB,MAAM;AAElD,KAAM,YAAY;;oBAEN,YAAY;iBACf,QAAQ;;sBAEH,KAAK;;;8BAGG,SAAS;;AAG/B,UAAW,WAAW;0BACJ,OAAO,CAAC,SAAS,IAAI,SAAS;8BAC1B,SAAS,QAAQ,QAAQ,KAAK,OAAO;0BACzC,OAAO;iBAChB,OAAO;iBACP,OAAO;;;ACdtB;;8EAE0E,QAAQ;;;cAGxE,QAAQ;iFAC2D,QAAQ;;;;;;;;mDAStC,QAAQ;;;cAG7C,QAAQ;sDACgC,QAAQ;;;AAI1D,cAAM,aAAa;;;;0BAQY,QAAQ,gBAAgB,YAAY,GAAG,aAAa;+BAczC,OAAO;aAQzB,OAAO","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
import { Mongoose } from 'mongoose';
|
|
2
2
|
import { RedisOptions } from 'ioredis';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
declare const UNITS: {
|
|
5
|
+
readonly milliseconds: 1;
|
|
6
|
+
readonly millisecond: 1;
|
|
7
|
+
readonly msecs: 1;
|
|
8
|
+
readonly msec: 1;
|
|
9
|
+
readonly ms: 1;
|
|
10
|
+
readonly seconds: 1000;
|
|
11
|
+
readonly second: 1000;
|
|
12
|
+
readonly secs: 1000;
|
|
13
|
+
readonly sec: 1000;
|
|
14
|
+
readonly s: 1000;
|
|
15
|
+
readonly minutes: number;
|
|
16
|
+
readonly minute: number;
|
|
17
|
+
readonly mins: number;
|
|
18
|
+
readonly min: number;
|
|
19
|
+
readonly m: number;
|
|
20
|
+
readonly hours: number;
|
|
21
|
+
readonly hour: number;
|
|
22
|
+
readonly hrs: number;
|
|
23
|
+
readonly hr: number;
|
|
24
|
+
readonly h: number;
|
|
25
|
+
readonly days: number;
|
|
26
|
+
readonly day: number;
|
|
27
|
+
readonly d: number;
|
|
28
|
+
readonly weeks: number;
|
|
29
|
+
readonly week: number;
|
|
30
|
+
readonly w: number;
|
|
31
|
+
readonly months: number;
|
|
32
|
+
readonly month: number;
|
|
33
|
+
readonly mo: number;
|
|
34
|
+
readonly years: number;
|
|
35
|
+
readonly year: number;
|
|
36
|
+
readonly yrs: number;
|
|
37
|
+
readonly yr: number;
|
|
38
|
+
readonly y: number;
|
|
39
|
+
};
|
|
40
|
+
type Unit = keyof typeof UNITS;
|
|
41
|
+
type Duration = number | `${number}` | `${number}${Unit}` | `${number} ${Unit}`;
|
|
42
|
+
|
|
5
43
|
type CacheData = Record<string, unknown> | Record<string, unknown>[] | unknown[] | number | undefined;
|
|
6
44
|
type CacheOptions = {
|
|
7
45
|
engine: 'memory' | 'redis';
|
|
8
46
|
engineOptions?: RedisOptions;
|
|
9
|
-
defaultTTL?:
|
|
47
|
+
defaultTTL?: Duration;
|
|
10
48
|
debug?: boolean;
|
|
49
|
+
onError?: (error: Error) => void;
|
|
50
|
+
maxEntries?: number;
|
|
51
|
+
maxBytes?: number;
|
|
52
|
+
sizeCalculation?: (value: CacheData) => number;
|
|
11
53
|
};
|
|
12
54
|
interface CacheEngine {
|
|
13
55
|
get: (key: string) => Promise<CacheData> | CacheData;
|
|
14
|
-
set: (key: string, value: CacheData, ttl?:
|
|
56
|
+
set: (key: string, value: CacheData, ttl?: Duration) => Promise<void> | void;
|
|
15
57
|
del: (key: string) => Promise<void> | void;
|
|
16
58
|
clear: () => Promise<void> | void;
|
|
17
59
|
close: () => Promise<void> | void;
|
|
@@ -19,11 +61,11 @@ interface CacheEngine {
|
|
|
19
61
|
|
|
20
62
|
declare module 'mongoose' {
|
|
21
63
|
interface Query<ResultType, DocType, THelpers, RawDocType> {
|
|
22
|
-
cache: (this: Query<ResultType, DocType, THelpers, RawDocType>, ttl?:
|
|
64
|
+
cache: (this: Query<ResultType, DocType, THelpers, RawDocType>, ttl?: Duration, customKey?: string) => this;
|
|
23
65
|
_key: string | null;
|
|
24
66
|
getCacheKey: (this: Query<ResultType, DocType, THelpers, RawDocType>) => string;
|
|
25
|
-
_ttl:
|
|
26
|
-
|
|
67
|
+
_ttl: Duration | null;
|
|
68
|
+
getDuration: (this: Query<ResultType, DocType, THelpers, RawDocType>) => Duration | null;
|
|
27
69
|
op?: string;
|
|
28
70
|
_path?: unknown;
|
|
29
71
|
_fields?: unknown;
|
|
@@ -31,11 +73,11 @@ declare module 'mongoose' {
|
|
|
31
73
|
_conditions?: unknown;
|
|
32
74
|
}
|
|
33
75
|
interface Aggregate<ResultType> {
|
|
34
|
-
cache: (this: Aggregate<ResultType>, ttl?:
|
|
76
|
+
cache: (this: Aggregate<ResultType>, ttl?: Duration, customKey?: string) => this;
|
|
35
77
|
_key: string | null;
|
|
36
78
|
getCacheKey: (this: Aggregate<ResultType>) => string;
|
|
37
|
-
_ttl:
|
|
38
|
-
|
|
79
|
+
_ttl: Duration | null;
|
|
80
|
+
getDuration: (this: Aggregate<ResultType>) => Duration | null;
|
|
39
81
|
}
|
|
40
82
|
}
|
|
41
83
|
declare class CacheMongoose {
|
|
@@ -48,5 +90,5 @@ declare class CacheMongoose {
|
|
|
48
90
|
}
|
|
49
91
|
|
|
50
92
|
export { CacheMongoose as default };
|
|
51
|
-
export type { CacheData, CacheEngine, CacheOptions,
|
|
93
|
+
export type { CacheData, CacheEngine, CacheOptions, Duration };
|
|
52
94
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sources":["../src/types.ts","../src/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","sources":["../src/ms.ts","../src/types.ts","../src/index.ts"],"mappings":";;;AAQA,cAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCZ,KAAM,IAAI,gBAAgB,KAAK;AAE/B,KAAM,QAAQ,sCAAsC,IAAI,kBAAkB,IAAI;;AC1C9E,KAAM,SAAS,GAAG,MAAM,oBAAoB,MAAM;AAElD,KAAM,YAAY;;oBAEN,YAAY;iBACf,QAAQ;;sBAEH,KAAK;;;8BAGG,SAAS;;AAG/B,UAAW,WAAW;0BACJ,OAAO,CAAC,SAAS,IAAI,SAAS;8BAC1B,SAAS,QAAQ,QAAQ,KAAK,OAAO;0BACzC,OAAO;iBAChB,OAAO;iBACP,OAAO;;;ACdtB;;8EAE0E,QAAQ;;;cAGxE,QAAQ;iFAC2D,QAAQ;;;;;;;;mDAStC,QAAQ;;;cAG7C,QAAQ;sDACgC,QAAQ;;;AAI1D,cAAM,aAAa;;;;0BAQY,QAAQ,gBAAgB,YAAY,GAAG,aAAa;+BAczC,OAAO;aAQzB,OAAO","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serialize } from 'node:v8';
|
|
1
2
|
import { EJSON } from 'bson';
|
|
2
3
|
import IORedis from 'ioredis';
|
|
3
4
|
import mongoose from 'mongoose';
|
|
@@ -9,89 +10,119 @@ const h = m * 60;
|
|
|
9
10
|
const d = h * 24;
|
|
10
11
|
const w = d * 7;
|
|
11
12
|
const y = d * 365.25;
|
|
12
|
-
const
|
|
13
|
+
const mo = y / 12;
|
|
13
14
|
const UNITS = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
weeks: w,
|
|
20
|
-
week: w,
|
|
21
|
-
w,
|
|
22
|
-
days: d,
|
|
23
|
-
day: d,
|
|
24
|
-
d,
|
|
25
|
-
hours: h,
|
|
26
|
-
hour: h,
|
|
27
|
-
hrs: h,
|
|
28
|
-
hr: h,
|
|
29
|
-
h,
|
|
30
|
-
minutes: m,
|
|
31
|
-
minute: m,
|
|
32
|
-
mins: m,
|
|
33
|
-
min: m,
|
|
34
|
-
m,
|
|
15
|
+
milliseconds: 1,
|
|
16
|
+
millisecond: 1,
|
|
17
|
+
msecs: 1,
|
|
18
|
+
msec: 1,
|
|
19
|
+
ms: 1,
|
|
35
20
|
seconds: s,
|
|
36
21
|
second: s,
|
|
37
22
|
secs: s,
|
|
38
23
|
sec: s,
|
|
39
24
|
s,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
minutes: m,
|
|
26
|
+
minute: m,
|
|
27
|
+
mins: m,
|
|
28
|
+
min: m,
|
|
29
|
+
m,
|
|
30
|
+
hours: h,
|
|
31
|
+
hour: h,
|
|
32
|
+
hrs: h,
|
|
33
|
+
hr: h,
|
|
34
|
+
h,
|
|
35
|
+
days: d,
|
|
36
|
+
day: d,
|
|
37
|
+
d,
|
|
38
|
+
weeks: w,
|
|
39
|
+
week: w,
|
|
40
|
+
w,
|
|
41
|
+
months: mo,
|
|
42
|
+
month: mo,
|
|
43
|
+
mo,
|
|
44
|
+
years: y,
|
|
45
|
+
year: y,
|
|
46
|
+
yrs: y,
|
|
47
|
+
yr: y,
|
|
48
|
+
y
|
|
45
49
|
};
|
|
50
|
+
const unitPattern = Object.keys(UNITS).sort((a, b) => b.length - a.length).join("|");
|
|
51
|
+
const RE = new RegExp(String.raw`^(-?(?:\d+)?\.?\d+)\s*(${unitPattern})?$`, "i");
|
|
46
52
|
const ms = (val) => {
|
|
47
53
|
const str = String(val);
|
|
48
|
-
if (str.length > 100) return
|
|
54
|
+
if (str.length > 100) return Number.NaN;
|
|
49
55
|
const match = RE.exec(str);
|
|
50
|
-
if (!match) return
|
|
56
|
+
if (!match) return Number.NaN;
|
|
51
57
|
const n = Number.parseFloat(match[1] ?? "");
|
|
52
58
|
const type = (match[2] ?? "ms").toLowerCase();
|
|
53
59
|
return n * (UNITS[type] ?? 0);
|
|
54
60
|
};
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
throw TypeError(msg);
|
|
58
|
-
};
|
|
59
|
-
var __accessCheck$3 = (obj, member, msg) => member.has(obj) || __typeError$3("Cannot " + msg);
|
|
60
|
-
var __privateGet$3 = (obj, member, getter) => (__accessCheck$3(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
61
|
-
var __privateAdd$3 = (obj, member, value) => member.has(obj) ? __typeError$3("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
62
|
-
var __privateSet$3 = (obj, member, value, setter) => (__accessCheck$3(obj, member, "write to private field"), member.set(obj, value), value);
|
|
63
|
-
var _cache;
|
|
62
|
+
const defaultSizer = (value) => serialize(value).byteLength;
|
|
64
63
|
class MemoryCacheEngine {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
#cache;
|
|
65
|
+
#maxEntries;
|
|
66
|
+
#maxBytes;
|
|
67
|
+
#sizeOf;
|
|
68
|
+
#totalBytes;
|
|
69
|
+
constructor(options) {
|
|
70
|
+
this.#cache = /* @__PURE__ */ new Map();
|
|
71
|
+
this.#maxEntries = options?.maxEntries != null && options.maxEntries > 0 ? options.maxEntries : Number.POSITIVE_INFINITY;
|
|
72
|
+
this.#maxBytes = options?.maxBytes != null && options.maxBytes > 0 ? options.maxBytes : Number.POSITIVE_INFINITY;
|
|
73
|
+
this.#sizeOf = options?.sizeCalculation ?? defaultSizer;
|
|
74
|
+
this.#totalBytes = 0;
|
|
75
|
+
}
|
|
76
|
+
get totalBytes() {
|
|
77
|
+
return this.#totalBytes;
|
|
78
|
+
}
|
|
79
|
+
get size() {
|
|
80
|
+
return this.#cache.size;
|
|
68
81
|
}
|
|
69
82
|
get(key) {
|
|
70
|
-
const item =
|
|
71
|
-
if (!item
|
|
72
|
-
|
|
83
|
+
const item = this.#cache.get(key);
|
|
84
|
+
if (!item) return void 0;
|
|
85
|
+
if (item.expiresAt < Date.now()) {
|
|
86
|
+
this.#cache.delete(key);
|
|
87
|
+
this.#totalBytes -= item.bytes;
|
|
73
88
|
return void 0;
|
|
74
89
|
}
|
|
90
|
+
this.#cache.delete(key);
|
|
91
|
+
this.#cache.set(key, item);
|
|
75
92
|
return item.value;
|
|
76
93
|
}
|
|
77
94
|
set(key, value, ttl) {
|
|
78
|
-
const givenTTL =
|
|
95
|
+
const givenTTL = ttl == null ? void 0 : ms(ttl);
|
|
79
96
|
const actualTTL = givenTTL ?? Number.POSITIVE_INFINITY;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
const existing = this.#cache.get(key);
|
|
98
|
+
if (existing) {
|
|
99
|
+
this.#cache.delete(key);
|
|
100
|
+
this.#totalBytes -= existing.bytes;
|
|
101
|
+
}
|
|
102
|
+
const bytes = this.#sizeOf(value);
|
|
103
|
+
this.#cache.set(key, { value, expiresAt: Date.now() + actualTTL, bytes });
|
|
104
|
+
this.#totalBytes += bytes;
|
|
105
|
+
while ((this.#cache.size > this.#maxEntries || this.#totalBytes > this.#maxBytes) && this.#cache.size > 1) {
|
|
106
|
+
const oldestKey = this.#cache.keys().next().value;
|
|
107
|
+
if (oldestKey === void 0 || oldestKey === key) break;
|
|
108
|
+
const oldest = this.#cache.get(oldestKey);
|
|
109
|
+
this.#cache.delete(oldestKey);
|
|
110
|
+
if (oldest) this.#totalBytes -= oldest.bytes;
|
|
111
|
+
}
|
|
84
112
|
}
|
|
85
113
|
del(key) {
|
|
86
|
-
|
|
114
|
+
const item = this.#cache.get(key);
|
|
115
|
+
if (!item) return;
|
|
116
|
+
this.#cache.delete(key);
|
|
117
|
+
this.#totalBytes -= item.bytes;
|
|
87
118
|
}
|
|
88
119
|
clear() {
|
|
89
|
-
|
|
120
|
+
this.#cache.clear();
|
|
121
|
+
this.#totalBytes = 0;
|
|
90
122
|
}
|
|
91
123
|
close() {
|
|
92
124
|
}
|
|
93
125
|
}
|
|
94
|
-
_cache = new WeakMap();
|
|
95
126
|
|
|
96
127
|
const isMongooseLessThan7 = Number.parseInt(mongoose.version, 10) < 7;
|
|
97
128
|
const convertToObject = (value) => {
|
|
@@ -106,120 +137,120 @@ const convertToObject = (value) => {
|
|
|
106
137
|
return value;
|
|
107
138
|
};
|
|
108
139
|
|
|
109
|
-
var __typeError$2 = (msg) => {
|
|
110
|
-
throw TypeError(msg);
|
|
111
|
-
};
|
|
112
|
-
var __accessCheck$2 = (obj, member, msg) => member.has(obj) || __typeError$2("Cannot " + msg);
|
|
113
|
-
var __privateGet$2 = (obj, member, getter) => (__accessCheck$2(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
114
|
-
var __privateAdd$2 = (obj, member, value) => member.has(obj) ? __typeError$2("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
115
|
-
var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$2(obj, member, "write to private field"), member.set(obj, value), value);
|
|
116
|
-
var _client;
|
|
117
140
|
class RedisCacheEngine {
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
#client;
|
|
142
|
+
#onError;
|
|
143
|
+
constructor(options, onError) {
|
|
120
144
|
options.keyPrefix ??= "cache-mongoose:";
|
|
121
|
-
|
|
145
|
+
this.#client = new IORedis(options);
|
|
146
|
+
this.#onError = onError;
|
|
122
147
|
}
|
|
123
148
|
async get(key) {
|
|
124
149
|
try {
|
|
125
|
-
const value = await
|
|
150
|
+
const value = await this.#client.get(key);
|
|
126
151
|
if (value === null) {
|
|
127
152
|
return void 0;
|
|
128
153
|
}
|
|
129
154
|
return EJSON.parse(value);
|
|
130
155
|
} catch (err) {
|
|
131
|
-
|
|
156
|
+
this.#onError(err);
|
|
132
157
|
return void 0;
|
|
133
158
|
}
|
|
134
159
|
}
|
|
135
160
|
async set(key, value, ttl) {
|
|
136
161
|
try {
|
|
137
|
-
const
|
|
162
|
+
const converted = convertToObject(value);
|
|
163
|
+
if (converted === void 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const givenTTL = ttl == null ? void 0 : ms(ttl);
|
|
138
167
|
const actualTTL = givenTTL ?? Number.POSITIVE_INFINITY;
|
|
139
|
-
const serializedValue = EJSON.stringify(
|
|
140
|
-
await
|
|
168
|
+
const serializedValue = EJSON.stringify(converted);
|
|
169
|
+
await this.#client.setex(key, Math.ceil(actualTTL / 1e3), serializedValue);
|
|
141
170
|
} catch (err) {
|
|
142
|
-
|
|
171
|
+
this.#onError(err);
|
|
143
172
|
}
|
|
144
173
|
}
|
|
145
174
|
async del(key) {
|
|
146
|
-
await
|
|
175
|
+
await this.#client.del(key);
|
|
147
176
|
}
|
|
148
177
|
async clear() {
|
|
149
|
-
await
|
|
178
|
+
await this.#client.flushdb();
|
|
150
179
|
}
|
|
151
180
|
async close() {
|
|
152
|
-
await
|
|
181
|
+
await this.#client.quit();
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
|
-
_client = new WeakMap();
|
|
156
184
|
|
|
157
|
-
var __typeError$1 = (msg) => {
|
|
158
|
-
throw TypeError(msg);
|
|
159
|
-
};
|
|
160
|
-
var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Cannot " + msg);
|
|
161
|
-
var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
162
|
-
var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
163
|
-
var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
|
|
164
|
-
var _engine, _defaultTTL, _debug, _engines;
|
|
165
185
|
class Cache {
|
|
186
|
+
#engine;
|
|
187
|
+
#defaultTTL;
|
|
188
|
+
#debug;
|
|
189
|
+
#onError;
|
|
190
|
+
#engines = ["memory", "redis"];
|
|
166
191
|
constructor(cacheOptions) {
|
|
167
|
-
|
|
168
|
-
__privateAdd$1(this, _defaultTTL);
|
|
169
|
-
__privateAdd$1(this, _debug);
|
|
170
|
-
__privateAdd$1(this, _engines, ["memory", "redis"]);
|
|
171
|
-
if (!__privateGet$1(this, _engines).includes(cacheOptions.engine)) {
|
|
192
|
+
if (!this.#engines.includes(cacheOptions.engine)) {
|
|
172
193
|
throw new Error(`Invalid engine name: ${cacheOptions.engine}`);
|
|
173
194
|
}
|
|
174
195
|
if (cacheOptions.engine === "redis" && !cacheOptions.engineOptions) {
|
|
175
196
|
throw new Error(`Engine options are required for ${cacheOptions.engine} engine`);
|
|
176
197
|
}
|
|
177
198
|
cacheOptions.defaultTTL ??= "1 minute";
|
|
178
|
-
|
|
199
|
+
this.#defaultTTL = ms(cacheOptions.defaultTTL);
|
|
200
|
+
this.#onError = cacheOptions.onError ?? console.error;
|
|
179
201
|
if (cacheOptions.engine === "redis" && cacheOptions.engineOptions) {
|
|
180
|
-
|
|
202
|
+
this.#engine = new RedisCacheEngine(cacheOptions.engineOptions, this.#onError);
|
|
181
203
|
}
|
|
182
204
|
if (cacheOptions.engine === "memory") {
|
|
183
|
-
|
|
205
|
+
this.#engine = new MemoryCacheEngine({
|
|
206
|
+
maxEntries: cacheOptions.maxEntries,
|
|
207
|
+
maxBytes: cacheOptions.maxBytes,
|
|
208
|
+
sizeCalculation: cacheOptions.sizeCalculation
|
|
209
|
+
});
|
|
184
210
|
}
|
|
185
|
-
|
|
211
|
+
this.#debug = cacheOptions.debug === true;
|
|
212
|
+
}
|
|
213
|
+
get onError() {
|
|
214
|
+
return this.#onError;
|
|
186
215
|
}
|
|
187
216
|
async get(key) {
|
|
188
|
-
const cacheEntry = await
|
|
189
|
-
if (
|
|
217
|
+
const cacheEntry = await this.#engine.get(key);
|
|
218
|
+
if (this.#debug) {
|
|
190
219
|
const cacheHit = cacheEntry == null ? "MISS" : "HIT";
|
|
191
220
|
console.log(`[ts-cache-mongoose] GET '${key}' - ${cacheHit}`);
|
|
192
221
|
}
|
|
193
222
|
return cacheEntry;
|
|
194
223
|
}
|
|
195
224
|
async set(key, value, ttl) {
|
|
196
|
-
const givenTTL =
|
|
197
|
-
const actualTTL = givenTTL ??
|
|
198
|
-
|
|
199
|
-
|
|
225
|
+
const givenTTL = ttl == null ? null : ms(ttl);
|
|
226
|
+
const actualTTL = givenTTL ?? this.#defaultTTL;
|
|
227
|
+
if (Number.isNaN(actualTTL) || actualTTL <= 0) {
|
|
228
|
+
if (this.#debug) {
|
|
229
|
+
console.log(`[ts-cache-mongoose] SET '${key}' - skipped (non-positive ttl: ${String(actualTTL)} ms)`);
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
await this.#engine.set(key, value, actualTTL);
|
|
234
|
+
if (this.#debug) {
|
|
200
235
|
console.log(`[ts-cache-mongoose] SET '${key}' - ttl: ${actualTTL.toFixed(0)} ms`);
|
|
201
236
|
}
|
|
202
237
|
}
|
|
203
238
|
async del(key) {
|
|
204
|
-
await
|
|
205
|
-
if (
|
|
239
|
+
await this.#engine.del(key);
|
|
240
|
+
if (this.#debug) {
|
|
206
241
|
console.log(`[ts-cache-mongoose] DEL '${key}'`);
|
|
207
242
|
}
|
|
208
243
|
}
|
|
209
244
|
async clear() {
|
|
210
|
-
await
|
|
211
|
-
if (
|
|
245
|
+
await this.#engine.clear();
|
|
246
|
+
if (this.#debug) {
|
|
212
247
|
console.log("[ts-cache-mongoose] CLEAR");
|
|
213
248
|
}
|
|
214
249
|
}
|
|
215
250
|
async close() {
|
|
216
|
-
return
|
|
251
|
+
return this.#engine.close();
|
|
217
252
|
}
|
|
218
253
|
}
|
|
219
|
-
_engine = new WeakMap();
|
|
220
|
-
_defaultTTL = new WeakMap();
|
|
221
|
-
_debug = new WeakMap();
|
|
222
|
-
_engines = new WeakMap();
|
|
223
254
|
|
|
224
255
|
const isPlainObject = (value) => {
|
|
225
256
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -271,7 +302,7 @@ function extendAggregate(mongoose, cache) {
|
|
|
271
302
|
pipeline: this.pipeline()
|
|
272
303
|
});
|
|
273
304
|
};
|
|
274
|
-
mongoose.Aggregate.prototype.
|
|
305
|
+
mongoose.Aggregate.prototype.getDuration = function() {
|
|
275
306
|
return this._ttl;
|
|
276
307
|
};
|
|
277
308
|
mongoose.Aggregate.prototype.cache = function(ttl, customKey) {
|
|
@@ -280,20 +311,20 @@ function extendAggregate(mongoose, cache) {
|
|
|
280
311
|
return this;
|
|
281
312
|
};
|
|
282
313
|
mongoose.Aggregate.prototype.exec = async function(...args) {
|
|
283
|
-
if (!Object.
|
|
314
|
+
if (!Object.hasOwn(this, "_ttl")) {
|
|
284
315
|
return mongooseExec.apply(this, args);
|
|
285
316
|
}
|
|
286
317
|
const key = this.getCacheKey();
|
|
287
|
-
const ttl = this.
|
|
318
|
+
const ttl = this.getDuration();
|
|
288
319
|
const resultCache = await cache.get(key).catch((err) => {
|
|
289
|
-
|
|
320
|
+
cache.onError(err);
|
|
290
321
|
});
|
|
291
322
|
if (resultCache) {
|
|
292
323
|
return resultCache;
|
|
293
324
|
}
|
|
294
325
|
const result = await mongooseExec.call(this);
|
|
295
326
|
await cache.set(key, result, ttl).catch((err) => {
|
|
296
|
-
|
|
327
|
+
cache.onError(err);
|
|
297
328
|
});
|
|
298
329
|
return result;
|
|
299
330
|
};
|
|
@@ -320,7 +351,7 @@ function extendQuery(mongoose, cache) {
|
|
|
320
351
|
_conditions: this._conditions
|
|
321
352
|
});
|
|
322
353
|
};
|
|
323
|
-
mongoose.Query.prototype.
|
|
354
|
+
mongoose.Query.prototype.getDuration = function() {
|
|
324
355
|
return this._ttl;
|
|
325
356
|
};
|
|
326
357
|
mongoose.Query.prototype.cache = function(ttl, customKey) {
|
|
@@ -329,17 +360,17 @@ function extendQuery(mongoose, cache) {
|
|
|
329
360
|
return this;
|
|
330
361
|
};
|
|
331
362
|
mongoose.Query.prototype.exec = async function(...args) {
|
|
332
|
-
if (!Object.
|
|
363
|
+
if (!Object.hasOwn(this, "_ttl")) {
|
|
333
364
|
return mongooseExec.apply(this, args);
|
|
334
365
|
}
|
|
335
366
|
const key = this.getCacheKey();
|
|
336
|
-
const ttl = this.
|
|
367
|
+
const ttl = this.getDuration();
|
|
337
368
|
const mongooseOptions = this.mongooseOptions();
|
|
338
369
|
const isCount = this.op?.includes("count") ?? false;
|
|
339
370
|
const isDistinct = this.op === "distinct";
|
|
340
371
|
const model = this.model.modelName;
|
|
341
372
|
const resultCache = await cache.get(key).catch((err) => {
|
|
342
|
-
|
|
373
|
+
cache.onError(err);
|
|
343
374
|
});
|
|
344
375
|
if (resultCache) {
|
|
345
376
|
if (isCount || isDistinct || mongooseOptions.lean) {
|
|
@@ -355,32 +386,26 @@ function extendQuery(mongoose, cache) {
|
|
|
355
386
|
}
|
|
356
387
|
const result = await mongooseExec.call(this);
|
|
357
388
|
await cache.set(key, result, ttl).catch((err) => {
|
|
358
|
-
|
|
389
|
+
cache.onError(err);
|
|
359
390
|
});
|
|
360
391
|
return result;
|
|
361
392
|
};
|
|
362
393
|
}
|
|
363
394
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
368
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
369
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
370
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
371
|
-
var _instance;
|
|
372
|
-
const _CacheMongoose = class _CacheMongoose {
|
|
395
|
+
class CacheMongoose {
|
|
396
|
+
static #instance;
|
|
397
|
+
cache;
|
|
373
398
|
constructor() {
|
|
374
399
|
}
|
|
375
400
|
static init(mongoose, cacheOptions) {
|
|
376
|
-
if (!
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const cache =
|
|
401
|
+
if (!CacheMongoose.#instance) {
|
|
402
|
+
CacheMongoose.#instance = new CacheMongoose();
|
|
403
|
+
CacheMongoose.#instance.cache = new Cache(cacheOptions);
|
|
404
|
+
const cache = CacheMongoose.#instance.cache;
|
|
380
405
|
extendQuery(mongoose, cache);
|
|
381
406
|
extendAggregate(mongoose, cache);
|
|
382
407
|
}
|
|
383
|
-
return
|
|
408
|
+
return CacheMongoose.#instance;
|
|
384
409
|
}
|
|
385
410
|
async clear(customKey) {
|
|
386
411
|
if (customKey == null) {
|
|
@@ -392,9 +417,6 @@ const _CacheMongoose = class _CacheMongoose {
|
|
|
392
417
|
async close() {
|
|
393
418
|
await this.cache.close();
|
|
394
419
|
}
|
|
395
|
-
}
|
|
396
|
-
_instance = new WeakMap();
|
|
397
|
-
__privateAdd(_CacheMongoose, _instance);
|
|
398
|
-
let CacheMongoose = _CacheMongoose;
|
|
420
|
+
}
|
|
399
421
|
|
|
400
422
|
export { CacheMongoose as default };
|