@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 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 crypto_1 = require("crypto");
4
+ const object_code_1 = require("object-code");
5
5
  const extension_1 = require("@prisma/client/extension");
6
- /**
7
- * Produce a stable cache key from model name and query arguments.
8
- */
9
- function generateComposedKey(options) {
10
- const hash = (0, crypto_1.createHash)("md5")
11
- .update(JSON.stringify(options.queryArgs))
12
- .digest("hex");
13
- return `${options.model}@${hash}`;
14
- }
15
- /**
16
- * Prefix the key with a namespace (if present).
17
- */
18
- function createKey(key, namespace) {
19
- return namespace ? `${namespace}:${key}` : key;
20
- }
21
- /**
22
- * Delete keys from cache after a write operation.
23
- */
24
- async function processUncache(cache, uncacheOption, result) {
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
- $cache: cache,
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 isWriteOp = [
79
- "create",
80
- "createMany",
81
- "updateMany",
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
- // --- Build key & ttl --------------------------------------------
96
- let cacheKey;
39
+ };
40
+ if (cOpt === undefined)
41
+ return finish(await query(queryArgs));
42
+ /* key + ttl */
43
+ let key;
97
44
  let ttl;
98
- if (["boolean", "number", "string"].includes(typeof cacheOption)) {
99
- cacheKey =
100
- typeof cacheOption === "string"
101
- ? cacheOption
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 cacheOption.key === "function") {
106
- // Key depends on DB result – run query first
50
+ else if (typeof cOpt.key === "function") {
107
51
  const res = await query(queryArgs);
108
- if (useUncache)
109
- await processUncache(cache, uncacheOption, res);
110
- cacheKey = cacheOption.key(res);
111
- ttl = cacheOption.ttl ?? defaultTTL;
112
- if (ttl && ttl > 0) {
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
- if (debug)
119
- console.log("Data cached (fn key):", cacheKey);
58
+ catch { }
120
59
  return res;
121
60
  }
122
61
  else {
123
- cacheKey =
124
- createKey(cacheOption.key, cacheOption.namespace) ||
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
- // --- Try cache for read ops -------------------------------------
129
- if (!isWriteOp) {
65
+ /* try cache for reads */
66
+ if (!WRITE_OPS.has(operation)) {
130
67
  try {
131
- const cached = await cache.get(cacheKey);
132
- if (cached !== undefined && cached !== null) {
133
- if (debug)
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
- // --- Fallback to DB ---------------------------------------------
74
+ /* DB round-trip */
146
75
  const res = await query(queryArgs);
147
- if (useUncache)
148
- await processUncache(cache, uncacheOption, res);
149
- ttl = ttl ?? defaultTTL;
76
+ await finish(res);
150
77
  try {
151
- if (ttl && ttl > 0) {
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.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",