@knaus94/prisma-extension-cache-manager 2.0.0 → 2.0.1
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 +0 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +56 -139
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -6,7 +6,6 @@ A caching extension for [Prisma](https://www.prisma.io/), compatible with [cache
|
|
|
6
6
|
|
|
7
7
|
- [cache-manager](https://www.npmjs.com/package/cache-manager) compatibility
|
|
8
8
|
- Only model queries can be cacheable (no $query or $queryRaw)
|
|
9
|
-
- Supported Decimal
|
|
10
9
|
|
|
11
10
|
## Installation
|
|
12
11
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { ModelExtension, PrismaRedisCacheConfig } from "./types";
|
|
2
|
-
|
|
3
|
-
* Prisma extension that adds transparent Redis caching.
|
|
4
|
-
*/
|
|
5
|
-
declare const _default: ({ cache, debug, ttl: defaultTTL }: PrismaRedisCacheConfig) => (client: any) => import("@prisma/client/extension").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {
|
|
2
|
+
declare const _default: ({ cache }: PrismaRedisCacheConfig) => (client: any) => import("@prisma/client/extension").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {
|
|
6
3
|
$allModels: ModelExtension;
|
|
7
4
|
}, {}, {
|
|
8
5
|
$cache: import("cache-manager").Cache;
|
package/dist/index.js
CHANGED
|
@@ -1,166 +1,83 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const types_1 = require("./types");
|
|
4
|
-
const
|
|
4
|
+
const object_code_1 = require("object-code");
|
|
5
5
|
const extension_1 = require("@prisma/client/extension");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
let keysToDelete = [];
|
|
26
|
-
if (typeof uncacheOption === "function") {
|
|
27
|
-
const keys = uncacheOption(result);
|
|
28
|
-
keysToDelete = Array.isArray(keys) ? keys : [keys];
|
|
29
|
-
}
|
|
30
|
-
else if (typeof uncacheOption === "string") {
|
|
31
|
-
keysToDelete = [uncacheOption];
|
|
32
|
-
}
|
|
33
|
-
else if (Array.isArray(uncacheOption)) {
|
|
34
|
-
if (typeof uncacheOption[0] === "string") {
|
|
35
|
-
keysToDelete = uncacheOption;
|
|
36
|
-
}
|
|
37
|
-
else if (typeof uncacheOption[0] === "object") {
|
|
38
|
-
keysToDelete = uncacheOption.map((obj) => obj.namespace ? `${obj.namespace}:${obj.key}` : obj.key);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (keysToDelete.length === 0)
|
|
42
|
-
return true;
|
|
43
|
-
try {
|
|
44
|
-
await cache.mdel(keysToDelete);
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Decide whether cache option is valid.
|
|
53
|
-
*/
|
|
54
|
-
const shouldUseCache = (opt) => opt !== undefined &&
|
|
55
|
-
["boolean", "object", "number", "string"].includes(typeof opt);
|
|
56
|
-
/**
|
|
57
|
-
* Decide whether uncache option is valid.
|
|
58
|
-
*/
|
|
59
|
-
const shouldUseUncache = (opt) => opt !== undefined &&
|
|
60
|
-
(typeof opt === "function" || typeof opt === "string" || Array.isArray(opt));
|
|
61
|
-
/**
|
|
62
|
-
* Prisma extension that adds transparent Redis caching.
|
|
63
|
-
*/
|
|
64
|
-
exports.default = ({ cache, debug, ttl: defaultTTL }) => extension_1.Prisma.defineExtension({
|
|
6
|
+
/* helpers -------------------------------------------------------------- */
|
|
7
|
+
const hashKey = (m, a) => `${m}@${(0, object_code_1.hash)(a)}`;
|
|
8
|
+
const ns = (k, n) => (n ? `${n}:${k}` : k);
|
|
9
|
+
const WRITE_OPS = new Set([
|
|
10
|
+
"create",
|
|
11
|
+
"createMany",
|
|
12
|
+
"updateMany",
|
|
13
|
+
"upsert",
|
|
14
|
+
"update",
|
|
15
|
+
]);
|
|
16
|
+
const toUncache = (opt, res) => !opt
|
|
17
|
+
? []
|
|
18
|
+
: typeof opt === "function"
|
|
19
|
+
? Array(opt(res))
|
|
20
|
+
: typeof opt === "string"
|
|
21
|
+
? [opt]
|
|
22
|
+
: opt.map((o) => typeof o === "string" ? o : ns(o.key, o.namespace));
|
|
23
|
+
/* extension ------------------------------------------------------------ */
|
|
24
|
+
exports.default = ({ cache }) => extension_1.Prisma.defineExtension({
|
|
65
25
|
name: "prisma-extension-cache-manager",
|
|
66
|
-
client: {
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
model: {
|
|
70
|
-
$allModels: {},
|
|
71
|
-
},
|
|
26
|
+
client: { $cache: cache },
|
|
27
|
+
model: { $allModels: {} },
|
|
72
28
|
query: {
|
|
73
29
|
$allModels: {
|
|
74
30
|
async $allOperations({ model, operation, args, query }) {
|
|
75
|
-
if (!types_1.CACHE_OPERATIONS.includes(operation))
|
|
31
|
+
if (!types_1.CACHE_OPERATIONS.includes(operation))
|
|
76
32
|
return query(args);
|
|
77
|
-
}
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"upsert",
|
|
83
|
-
"update",
|
|
84
|
-
].includes(operation);
|
|
85
|
-
const { cache: cacheOption, uncache: uncacheOption, ...queryArgs } = args;
|
|
86
|
-
const useCache = shouldUseCache(cacheOption);
|
|
87
|
-
const useUncache = shouldUseUncache(uncacheOption);
|
|
88
|
-
// --- No cache requested -----------------------------------------
|
|
89
|
-
if (!useCache) {
|
|
90
|
-
const res = await query(queryArgs);
|
|
91
|
-
if (useUncache)
|
|
92
|
-
await processUncache(cache, uncacheOption, res);
|
|
33
|
+
const { cache: cOpt, uncache, ...queryArgs } = args;
|
|
34
|
+
const finish = async (res) => {
|
|
35
|
+
const dels = toUncache(uncache, res);
|
|
36
|
+
if (dels.length)
|
|
37
|
+
cache.mdel(dels).catch(() => { });
|
|
93
38
|
return res;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
39
|
+
};
|
|
40
|
+
if (cOpt === undefined)
|
|
41
|
+
return finish(await query(queryArgs));
|
|
42
|
+
/* key + ttl */
|
|
43
|
+
let key;
|
|
97
44
|
let ttl;
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
: generateComposedKey({ model, queryArgs });
|
|
103
|
-
ttl = typeof cacheOption === "number" ? cacheOption : undefined;
|
|
45
|
+
if (typeof cOpt !== "object" || Array.isArray(cOpt)) {
|
|
46
|
+
key = typeof cOpt === "string" ? cOpt : hashKey(model, queryArgs);
|
|
47
|
+
if (typeof cOpt === "number")
|
|
48
|
+
ttl = cOpt;
|
|
104
49
|
}
|
|
105
|
-
else if (typeof
|
|
106
|
-
// Key depends on DB result – run query first
|
|
50
|
+
else if (typeof cOpt.key === "function") {
|
|
107
51
|
const res = await query(queryArgs);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
await cache.set(cacheKey, res, Math.ceil(ttl / 1000));
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
await cache.set(cacheKey, res);
|
|
52
|
+
await finish(res);
|
|
53
|
+
key = cOpt.key(res);
|
|
54
|
+
ttl = cOpt.ttl; // как есть
|
|
55
|
+
try {
|
|
56
|
+
await cache.set(key, res, ttl);
|
|
117
57
|
}
|
|
118
|
-
|
|
119
|
-
console.log("Data cached (fn key):", cacheKey);
|
|
58
|
+
catch { }
|
|
120
59
|
return res;
|
|
121
60
|
}
|
|
122
61
|
else {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
generateComposedKey({ model, queryArgs });
|
|
126
|
-
ttl = cacheOption.ttl;
|
|
62
|
+
key = ns(cOpt.key ?? hashKey(model, queryArgs), cOpt.namespace);
|
|
63
|
+
ttl = cOpt.ttl;
|
|
127
64
|
}
|
|
128
|
-
|
|
129
|
-
if (!
|
|
65
|
+
/* try cache for reads */
|
|
66
|
+
if (!WRITE_OPS.has(operation)) {
|
|
130
67
|
try {
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
console.log("Cache hit:", cacheKey);
|
|
135
|
-
return cached;
|
|
136
|
-
}
|
|
137
|
-
if (debug)
|
|
138
|
-
console.log("Cache miss:", cacheKey);
|
|
139
|
-
}
|
|
140
|
-
catch (e) {
|
|
141
|
-
if (debug)
|
|
142
|
-
console.error("Cache get failed", e);
|
|
68
|
+
const hit = await cache.get(key);
|
|
69
|
+
if (hit != null)
|
|
70
|
+
return hit;
|
|
143
71
|
}
|
|
72
|
+
catch { }
|
|
144
73
|
}
|
|
145
|
-
|
|
74
|
+
/* DB round-trip */
|
|
146
75
|
const res = await query(queryArgs);
|
|
147
|
-
|
|
148
|
-
await processUncache(cache, uncacheOption, res);
|
|
149
|
-
ttl = ttl ?? defaultTTL;
|
|
76
|
+
await finish(res);
|
|
150
77
|
try {
|
|
151
|
-
|
|
152
|
-
await cache.set(cacheKey, res, Math.ceil(ttl / 1000));
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
await cache.set(cacheKey, res);
|
|
156
|
-
}
|
|
157
|
-
if (debug)
|
|
158
|
-
console.log("Data cached:", cacheKey);
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
if (debug)
|
|
162
|
-
console.error("Cache set failed", e);
|
|
78
|
+
await cache.set(key, res, ttl);
|
|
163
79
|
}
|
|
80
|
+
catch { }
|
|
164
81
|
return res;
|
|
165
82
|
},
|
|
166
83
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knaus94/prisma-extension-cache-manager",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/knaus94/prisma-extension-cache-manager.git"
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@prisma/client": "^6.8.2",
|
|
58
|
-
"cache-manager": "^6.4.3"
|
|
58
|
+
"cache-manager": "^6.4.3",
|
|
59
|
+
"object-code": "^1.3.3"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
62
|
"@nestjs/cache-manager": "^3.0.1",
|