cds-caching 0.3.1 → 0.3.3
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 +13 -4
- package/package.json +10 -10
- package/srv/CachingService.js +35 -3
- package/srv/util.js +4 -2
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ For more control, you can specify additional options:
|
|
|
82
82
|
"host": "localhost",
|
|
83
83
|
"port": 6379,
|
|
84
84
|
"password": "optional",
|
|
85
|
-
"
|
|
85
|
+
"uri": "redis://..." // Alternative: Redis connection URI
|
|
86
86
|
|
|
87
87
|
// SQLite specific
|
|
88
88
|
"url": "sqlite://./cache.sqlite"
|
|
@@ -460,12 +460,21 @@ Templates support the following properties:
|
|
|
460
460
|
|
|
461
461
|
|
|
462
462
|
```javascript
|
|
463
|
-
|
|
464
|
-
// Store with tags
|
|
463
|
+
// Store with static tag
|
|
465
464
|
await cache.set("key", "value", {
|
|
466
465
|
tags: [{ value: "user-123" }]
|
|
467
466
|
})
|
|
468
467
|
|
|
468
|
+
// Store with template tag (will generate a tag like "tenant-global-user-anonymous")
|
|
469
|
+
await cache.set("key", "value", {
|
|
470
|
+
tags: [{ template: "tenant-{tenant}-user-{user}" }]
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
// Store with data-based tag
|
|
474
|
+
await cache.set("key", { id: 123, name: "Product" }, {
|
|
475
|
+
tags: [{ data: "id", prefix: "product-" }]
|
|
476
|
+
})
|
|
477
|
+
|
|
469
478
|
// Invalidate by tag
|
|
470
479
|
await cache.deleteByTag('user-123')
|
|
471
480
|
```
|
|
@@ -796,4 +805,4 @@ Contributions are welcome! Please read our contributing guidelines and submit pu
|
|
|
796
805
|
|
|
797
806
|
### License
|
|
798
807
|
|
|
799
|
-
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
808
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cds-caching",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "A caching plugin for SAP CAP applications supporting Redis",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,25 +32,25 @@
|
|
|
32
32
|
"release": "release-it"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@sap/cds": ">=
|
|
35
|
+
"@sap/cds": ">=9"
|
|
36
36
|
},
|
|
37
37
|
"workspaces": [
|
|
38
38
|
".",
|
|
39
39
|
"test/**"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@keyv/compress-gzip": "^2.0.
|
|
42
|
+
"@keyv/compress-gzip": "^2.0.3",
|
|
43
43
|
"@keyv/compress-lz4": "^1.0.0",
|
|
44
|
-
"@keyv/redis": "^4.
|
|
45
|
-
"@keyv/sqlite": "^4.0.
|
|
46
|
-
"keyv": "^5.3.
|
|
44
|
+
"@keyv/redis": "^4.5.0",
|
|
45
|
+
"@keyv/sqlite": "^4.0.5",
|
|
46
|
+
"keyv": "^5.3.4"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"eslint": "^9.
|
|
49
|
+
"eslint": "^9.30.1",
|
|
50
50
|
"husky": "^9.1.7",
|
|
51
|
-
"jest": "^
|
|
52
|
-
"release-it": "^
|
|
53
|
-
"@cap-js/cds-test": "^0.
|
|
51
|
+
"jest": "^30.0.4",
|
|
52
|
+
"release-it": "^19.0.3",
|
|
53
|
+
"@cap-js/cds-test": "^0.4.0"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=16"
|
package/srv/CachingService.js
CHANGED
|
@@ -21,7 +21,7 @@ class CachingService extends cds.Service {
|
|
|
21
21
|
this.options = this.options || {
|
|
22
22
|
store: null,
|
|
23
23
|
compression: null,
|
|
24
|
-
credentials: {
|
|
24
|
+
credentials: {}
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
let store;
|
|
@@ -224,6 +224,7 @@ class CachingService extends cds.Service {
|
|
|
224
224
|
switch (arg1.constructor.name) {
|
|
225
225
|
case "Request":
|
|
226
226
|
case "NoaRequest":
|
|
227
|
+
case "ODataRequest":
|
|
227
228
|
const req = arg1;
|
|
228
229
|
const next = arguments[1];
|
|
229
230
|
|
|
@@ -239,7 +240,7 @@ class CachingService extends cds.Service {
|
|
|
239
240
|
return cachedValue;
|
|
240
241
|
}
|
|
241
242
|
const response = await next();
|
|
242
|
-
req.cacheOptions.tags = this.resolveTags(req.cacheOptions.tags, response, req.params);
|
|
243
|
+
req.cacheOptions.tags = this.resolveTags(req.cacheOptions.tags, response, { ...req.params, user: req.user.id, tenant: req.tenant, locale: req.locale, hash: this.createKey(req, { template: '{hash}' }) });
|
|
243
244
|
await this.set(req.cacheKey, response, req.cacheOptions);
|
|
244
245
|
return response;
|
|
245
246
|
case "cds.ql":
|
|
@@ -259,7 +260,7 @@ class CachingService extends cds.Service {
|
|
|
259
260
|
return this.get(query.cacheKey);
|
|
260
261
|
}
|
|
261
262
|
const data = await srv.run(query);
|
|
262
|
-
options.tags = this.resolveTags(options.tags, data, query.params);
|
|
263
|
+
options.tags = this.resolveTags(options.tags, data, { ...query.params, hash: this.createKey(query, { template: '{hash}' }) });
|
|
263
264
|
await this.set(query.cacheKey, data, options);
|
|
264
265
|
return data;
|
|
265
266
|
} else {
|
|
@@ -393,6 +394,36 @@ class CachingService extends cds.Service {
|
|
|
393
394
|
return [tag];
|
|
394
395
|
}
|
|
395
396
|
|
|
397
|
+
// Handle template-based tags
|
|
398
|
+
if (config.template) {
|
|
399
|
+
const createHash = (data) => crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');
|
|
400
|
+
|
|
401
|
+
const hashParts = [
|
|
402
|
+
...(data ? [data] : []),
|
|
403
|
+
...(params ? [params] : [])
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
const contextVars = {
|
|
407
|
+
tenant: params.tenant || 'global',
|
|
408
|
+
user: params.user || 'anonymous',
|
|
409
|
+
locale: params.locale || 'en',
|
|
410
|
+
hash: createHash(hashParts)
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const value = config.template.replace(
|
|
414
|
+
/\{(tenant|user|locale|hash)\}/g,
|
|
415
|
+
(match, variable) => contextVars[variable]
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
const tag = [
|
|
419
|
+
config.prefix,
|
|
420
|
+
value,
|
|
421
|
+
config.suffix
|
|
422
|
+
].filter(Boolean).join('');
|
|
423
|
+
|
|
424
|
+
return [tag];
|
|
425
|
+
}
|
|
426
|
+
|
|
396
427
|
// Handle data-based tags
|
|
397
428
|
if (config.data && dataArray.length) {
|
|
398
429
|
return dataArray.flatMap(item => {
|
|
@@ -459,6 +490,7 @@ class CachingService extends cds.Service {
|
|
|
459
490
|
switch (keyOrObject.constructor.name) {
|
|
460
491
|
case "Request":
|
|
461
492
|
case "NoaRequest":
|
|
493
|
+
case "ODataRequest":
|
|
462
494
|
|
|
463
495
|
return this.createCacheKey((!options.value && !options.template) ? { template: '{tenant}:{user}:{locale}:{hash}' } : options, {
|
|
464
496
|
req: keyOrObject,
|
package/srv/util.js
CHANGED
|
@@ -24,7 +24,7 @@ const bindFunction = async (service, action, isBound = false) => {
|
|
|
24
24
|
const cache = await cds.connect.to(action['@cache.service'] || "caching");
|
|
25
25
|
const data = await cache.run(req, next, {
|
|
26
26
|
ttl: action['@cache.ttl'],
|
|
27
|
-
tags:
|
|
27
|
+
tags: action['@cache.tags'],
|
|
28
28
|
key: extractCacheProperties(action, 'key')
|
|
29
29
|
});
|
|
30
30
|
return data;
|
|
@@ -37,9 +37,11 @@ const bindEntity = async (service, entity) => {
|
|
|
37
37
|
service.on('READ', entity.name, async (req, next) => {
|
|
38
38
|
const cache = await cds.connect.to(entity['@cache.service'] || "caching");
|
|
39
39
|
|
|
40
|
+
console.log(entity);
|
|
41
|
+
|
|
40
42
|
const data = await cache.run(req, next, {
|
|
41
43
|
ttl: entity['@cache.ttl'],
|
|
42
|
-
tags:
|
|
44
|
+
tags: entity['@cache.tags'],
|
|
43
45
|
key: extractCacheProperties(entity, 'key')
|
|
44
46
|
});
|
|
45
47
|
return data;
|