@knaus94/prisma-extension-cache-manager 2.0.0 → 2.0.2

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,167 +1,70 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const object_code_1 = require("object-code");
3
4
  const types_1 = require("./types");
4
- const crypto_1 = require("crypto");
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 composedKey = (m, a) => `${m}@${(0, object_code_1.hash)(a)}`;
8
+ const ns = (k, n) => (n ? `${n}:${k}` : k);
9
+ const isWrite = (op) => ["create", "createMany", "updateMany", "upsert", "update"].includes(op);
10
+ /* uncache массив строк */
11
+ const toUncache = (opt, res) => !opt
12
+ ? []
13
+ : typeof opt === "function"
14
+ ? [].concat(opt(res))
15
+ : typeof opt === "string"
16
+ ? [opt]
17
+ : opt.map((o) => typeof o === "string" ? o : ns(o.key, o.namespace));
18
+ const processUncache = async (cache, opt, res) => {
19
+ const keys = toUncache(opt, res);
20
+ if (keys.length)
21
+ await cache.mdel(keys).catch(() => { });
22
+ };
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);
33
+ const { cache: cOpt, uncache, ...queryArgs } = args;
34
+ if (cOpt === undefined) {
35
+ const db = await query(queryArgs);
36
+ await processUncache(cache, uncache, db);
37
+ return db;
77
38
  }
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);
93
- return res;
94
- }
95
- // --- Build key & ttl --------------------------------------------
96
- let cacheKey;
97
- 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;
39
+ let key;
40
+ let ttlMs;
41
+ if (typeof cOpt !== "object" || Array.isArray(cOpt)) {
42
+ key =
43
+ typeof cOpt === "string" ? cOpt : composedKey(model, queryArgs);
44
+ if (typeof cOpt === "number")
45
+ ttlMs = cOpt;
104
46
  }
105
- else if (typeof cacheOption.key === "function") {
106
- // Key depends on DB result – run query first
107
- 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);
117
- }
118
- if (debug)
119
- console.log("Data cached (fn key):", cacheKey);
120
- return res;
47
+ else if (typeof cOpt.key === "function") {
48
+ const db = await query(queryArgs);
49
+ await processUncache(cache, uncache, db);
50
+ key = cOpt.key(db);
51
+ ttlMs = cOpt.ttl ?? undefined;
52
+ await cache.set(key, db, Math.ceil((ttlMs ?? 0) / 1000));
53
+ return db;
121
54
  }
122
55
  else {
123
- cacheKey =
124
- createKey(cacheOption.key, cacheOption.namespace) ||
125
- generateComposedKey({ model, queryArgs });
126
- ttl = cacheOption.ttl;
127
- }
128
- // --- Try cache for read ops -------------------------------------
129
- if (!isWriteOp) {
130
- 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);
143
- }
144
- }
145
- // --- Fallback to DB ---------------------------------------------
146
- const res = await query(queryArgs);
147
- if (useUncache)
148
- await processUncache(cache, uncacheOption, res);
149
- ttl = ttl ?? defaultTTL;
150
- 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);
56
+ key = ns(cOpt.key ?? composedKey(model, queryArgs), cOpt.namespace);
57
+ ttlMs = cOpt.ttl ?? undefined;
159
58
  }
160
- catch (e) {
161
- if (debug)
162
- console.error("Cache set failed", e);
59
+ if (!isWrite(operation)) {
60
+ const hit = await cache.get(key).catch(() => undefined);
61
+ if (hit !== undefined && hit !== null)
62
+ return hit;
163
63
  }
164
- return res;
64
+ const db = await query(queryArgs);
65
+ await processUncache(cache, uncache, db);
66
+ await cache.set(key, db, ttlMs !== undefined ? Math.ceil(ttlMs / 1000) : undefined);
67
+ return db;
165
68
  },
166
69
  },
167
70
  },
package/dist/types.d.ts CHANGED
@@ -35,7 +35,5 @@ export interface PrismaCacheArgs<T, A, O extends RequiredArgsOperation | Optiona
35
35
  }
36
36
  export interface PrismaRedisCacheConfig {
37
37
  cache: Cache;
38
- debug?: boolean;
39
- ttl?: number;
40
38
  }
41
39
  export {};
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.2",
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",