cds-caching 1.0.0 β 1.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 +182 -25
- package/lib/CachingService.d.ts +16 -10
- package/lib/CachingService.js +69 -13
- package/lib/operations/AsyncOperations.js +179 -16
- package/lib/operations/BasicOperations.js +166 -20
- package/lib/operations/CapOperations.js +251 -45
- package/lib/support/CacheStoreManager.js +44 -11
- package/lib/support/RuntimeConfigurationManager.js +4 -2
- package/lib/support/optionalRequire.js +45 -0
- package/lib/util.js +1 -1
- package/package.json +40 -12
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# Welcome to cds-caching
|
|
2
|
+
[](https://www.npmjs.com/package/cds-caching/common)
|
|
3
|
+
[](https://www.npmjs.com/package/cds-caching)
|
|
2
4
|
|
|
3
5
|
## Overview
|
|
4
6
|
|
|
@@ -35,10 +37,36 @@ Please also read the introduction blog post in the SAP Community: [Boosting perf
|
|
|
35
37
|
> - [Metrics Guide](docs/metrics-guide.md)
|
|
36
38
|
> - [OData API Reference](docs/odata-api.md)
|
|
37
39
|
|
|
38
|
-
## π¨ Breaking Changes: Migrating
|
|
40
|
+
## π¨ Breaking Changes: Migrating cds-caching
|
|
39
41
|
|
|
40
42
|
> **β οΈ Important:** Version 1.x contains breaking changes. Please review the migration guide below.
|
|
41
43
|
|
|
44
|
+
## Upgrading from 1.1.0 to 1.2.0
|
|
45
|
+
|
|
46
|
+
From **1.2.0** onwards, storage/compression adapters are treated as **optional peer dependencies** and must be installed **explicitly in your consuming CAP project** (i.e. *your app*, not `cds-caching`). This avoids relying on transitive dependencies and makes adapter usage deterministic.
|
|
47
|
+
|
|
48
|
+
### Required adapter packages (add to your app's `package.json`)
|
|
49
|
+
|
|
50
|
+
Install the package(s) matching your configured `store` / `compression`:
|
|
51
|
+
|
|
52
|
+
| Config | Value | Install in your app |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `store` | `"redis"` | `@keyv/redis` |
|
|
55
|
+
| `store` | `"sqlite"` | `@resolid/keyv-sqlite` (recommended) **or** `@keyv/sqlite` |
|
|
56
|
+
| `store` | `"postgres"` | `@keyv/postgres` |
|
|
57
|
+
| `compression` | `"lz4"` | `@keyv/compress-lz4` |
|
|
58
|
+
| `compression` | `"gzip"` | `@keyv/compress-gzip` |
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm i @keyv/redis
|
|
64
|
+
# or: npm i @resolid/keyv-sqlite
|
|
65
|
+
# and optionally: npm i @keyv/compress-gzip
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Upgrading from 0.x to 1.x
|
|
69
|
+
|
|
42
70
|
### π API Changes for read-through methods
|
|
43
71
|
|
|
44
72
|
Version 1.x introduces new methods that provide more insights into the read-through caching as they also directly return the genrated cache `key` and some caching `metadata`. The should be preferrably used instead of the old methods.
|
|
@@ -136,44 +164,45 @@ await cache.set(data, value, {
|
|
|
136
164
|
|
|
137
165
|
For detailed API documentation, see [Programmatic API Reference](docs/programmatic-api.md).
|
|
138
166
|
|
|
139
|
-
###
|
|
167
|
+
### Example Application
|
|
140
168
|
|
|
141
|
-
|
|
169
|
+
The cds-caching plugin includes a comprehensive example application demonstrating various caching use cases and a UI5-based dashboard for monitoring cache performance.
|
|
142
170
|
|
|
143
|
-
|
|
144
|
-
npm install cds-caching
|
|
145
|
-
```
|
|
171
|
+

|
|
146
172
|
|
|
147
|
-
|
|
173
|
+
The example consists of:
|
|
174
|
+
- **Backend Application** (`examples/app/`) - A CAP application showing annotation-based and programmatic caching patterns
|
|
175
|
+
- **Dashboard** (`examples/dashboard/`) - A UI5-based monitoring interface with real-time metrics, key-level analytics, and historical data
|
|
148
176
|
|
|
149
|
-
|
|
177
|
+
[See the full Example Application Guide β](docs/example-app.md)
|
|
150
178
|
|
|
151
|
-
#### Basic Usage with TypeScript
|
|
152
179
|
|
|
153
|
-
|
|
154
|
-
import { CachingService, CacheOptions, ReadThroughResult } from 'cds-caching';
|
|
180
|
+
### Installation
|
|
155
181
|
|
|
156
|
-
|
|
182
|
+
Installing and using cds-caching is straightforward since it's a CAP plugin. Simply run:
|
|
157
183
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
184
|
+
```bash
|
|
185
|
+
npm install cds-caching
|
|
186
|
+
```
|
|
161
187
|
|
|
162
|
-
|
|
163
|
-
const { result, cacheKey, metadata } = await cache.rt.send(request, service, {
|
|
164
|
-
ttl: 1800,
|
|
165
|
-
tags: ['user-data']
|
|
166
|
-
});
|
|
188
|
+
#### Adapter packages (Redis / SQLite / Compression)
|
|
167
189
|
|
|
168
|
-
|
|
169
|
-
const cachedFunction = cache.rt.wrap('expensive-operation', async (id: string) => {
|
|
170
|
-
return await this.performExpensiveOperation(id);
|
|
171
|
-
});
|
|
190
|
+
`cds-caching` only ships with the in-memory store. If you configure a different store or compression, you must install the corresponding adapter package **in your consuming CAP project**:
|
|
172
191
|
|
|
173
|
-
|
|
192
|
+
```bash
|
|
193
|
+
# Redis store
|
|
194
|
+
npm install @keyv/redis
|
|
174
195
|
|
|
196
|
+
# SQLite store
|
|
197
|
+
npm install @resolid/keyv-sqlite # Preferred in CAP because of better-sqlite3 usage
|
|
198
|
+
npm install @keyv/sqlite # Alternative if you want to rely on the official adapter
|
|
199
|
+
|
|
200
|
+
# Compression
|
|
201
|
+
npm install @keyv/compress-lz4 # for "lz4"
|
|
202
|
+
npm install @keyv/compress-gzip # for "gzip"
|
|
175
203
|
```
|
|
176
204
|
|
|
205
|
+
If you configure an adapter but donβt have its package installed, `cds-caching` will fail fast with a clear error telling you what to install.
|
|
177
206
|
|
|
178
207
|
### Configuration
|
|
179
208
|
|
|
@@ -212,6 +241,8 @@ The cds-caching plugin supports comprehensive configuration through `package.jso
|
|
|
212
241
|
"namespace": "caching",
|
|
213
242
|
"store": "in-memory", // "in-memory", "sqlite", or "redis"
|
|
214
243
|
"compression": "lz4", // "lz4" or "gzip"
|
|
244
|
+
"throwOnErrors": false, // Whether basic operations should throw errors (default: false)
|
|
245
|
+
"transactionalOperations": false, // When true, basic ops run in a dedicated cache tx (cache.tx())
|
|
215
246
|
"credentials": {
|
|
216
247
|
// Redis configuration
|
|
217
248
|
"host": "localhost",
|
|
@@ -230,6 +261,27 @@ The cds-caching plugin supports comprehensive configuration through `package.jso
|
|
|
230
261
|
}
|
|
231
262
|
```
|
|
232
263
|
|
|
264
|
+
#### Transaction isolation for basic operations (`transactionalOperations`)
|
|
265
|
+
|
|
266
|
+
CAP can run multiple `before` handlers concurrently. If one handler fails and rolls back the request transaction, other concurrent handlers may still be running and can fail when they access the cache (typical error: βTransaction is rolled back, no subsequent .run allowedβ¦β).
|
|
267
|
+
|
|
268
|
+
To isolate **basic cache operations** (`get`, `set`, `delete`, `clear`, `deleteByTag`, `metadata`, `tags`, `getRaw`) from the request transaction, enable:
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"cds": {
|
|
273
|
+
"requires": {
|
|
274
|
+
"caching": {
|
|
275
|
+
"impl": "cds-caching",
|
|
276
|
+
"transactionalOperations": true
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
In the background, the caching service opens a dedicated cache transaction via `cache.tx()`, executes the operation via `tx.send(...)`, and commits/rolls back the cache transaction per operation. This keeps cache calls working even if the surrounding request transaction is already rolled back.
|
|
284
|
+
|
|
233
285
|
#### Read-Through (RT) Key Configuration
|
|
234
286
|
|
|
235
287
|
Configure default key templates for read-through operations:
|
|
@@ -253,6 +305,36 @@ Configure default key templates for read-through operations:
|
|
|
253
305
|
|
|
254
306
|
**Default behavior** (if not configured): All context elements are disabled by default.
|
|
255
307
|
|
|
308
|
+
#### Error Handling Configuration
|
|
309
|
+
|
|
310
|
+
Configure how the caching service handles errors:
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"cds": {
|
|
315
|
+
"requires": {
|
|
316
|
+
"caching": {
|
|
317
|
+
...
|
|
318
|
+
"throwOnErrors": true, // Basic operations (set, get, delete, has) throw errors
|
|
319
|
+
// Default: false - operations return undefined/null instead of throwing
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Error Handling Behavior:**
|
|
327
|
+
|
|
328
|
+
- **Basic Operations** (`set`, `get`, `delete`, `has`):
|
|
329
|
+
- When `throwOnErrors: false` (default): Operations return `undefined`/`null` on errors
|
|
330
|
+
- When `throwOnErrors: true`: Operations throw errors for connection issues, etc.
|
|
331
|
+
|
|
332
|
+
- **Read-Through Operations** (`rt.run`, `rt.send`, `rt.wrap`, `rt.exec`):
|
|
333
|
+
- Never throw errors, regardless of `throwOnErrors` setting
|
|
334
|
+
- Include `cacheErrors` array in response when errors occur
|
|
335
|
+
- Always fetch from remote service when cache operations fail
|
|
336
|
+
- Log errors for monitoring and debugging
|
|
337
|
+
|
|
256
338
|
#### Environment-Specific Configuration
|
|
257
339
|
|
|
258
340
|
You can override settings for different environments:
|
|
@@ -308,16 +390,19 @@ cds-caching provides 3 storage options:
|
|
|
308
390
|
- Memory on SAP BTP Cloud Foundry is limited (up to 16 GB) and produces costs
|
|
309
391
|
|
|
310
392
|
##### SQLite (for medium-size use uses)
|
|
393
|
+
- Requires installing the adapter package: `@keyv/sqlite` (in your project)
|
|
311
394
|
- Data is stored in local SQLite database
|
|
312
395
|
- Data is persited next to SAP BTP application with disk-quota up to 10 GB
|
|
313
396
|
- Cache will be removed after each deployment to SAP BTP
|
|
314
397
|
- No distributed cache between application instances (horizontal scaling)
|
|
315
398
|
|
|
316
399
|
##### Redis Cache (recommended for production)
|
|
400
|
+
- Requires installing the adapter package: `@keyv/redis` (in your project)
|
|
317
401
|
- Persistent and supports distributed caching
|
|
318
402
|
- Works across multiple app instances, making it ideal for scalable applications
|
|
319
403
|
- Available on SAP BTP via hyperscaler options (e.g., AWS, Azure, Google Cloud)
|
|
320
404
|
- Even trial accounts provide Redis access
|
|
405
|
+
- Redis will be non-blocking
|
|
321
406
|
|
|
322
407
|
#### Redis Development Setup
|
|
323
408
|
|
|
@@ -431,6 +516,31 @@ await cache.delete("bp:1000001")
|
|
|
431
516
|
await cache.clear()
|
|
432
517
|
```
|
|
433
518
|
|
|
519
|
+
**Error Handling for Basic Operations:**
|
|
520
|
+
|
|
521
|
+
```javascript
|
|
522
|
+
// With throwOnErrors: false (default)
|
|
523
|
+
try {
|
|
524
|
+
const value = await cache.get("bp:1000001")
|
|
525
|
+
if (value === undefined) {
|
|
526
|
+
// Handle cache miss or error
|
|
527
|
+
console.log("Value not found or cache error occurred")
|
|
528
|
+
}
|
|
529
|
+
} catch (error) {
|
|
530
|
+
// Only thrown for non-cache related errors
|
|
531
|
+
console.error("Unexpected error:", error)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// With throwOnErrors: true
|
|
535
|
+
try {
|
|
536
|
+
const value = await cache.get("bp:1000001")
|
|
537
|
+
// Value will be undefined if not found, but errors will be thrown
|
|
538
|
+
} catch (error) {
|
|
539
|
+
// Errors thrown for connection issues, etc.
|
|
540
|
+
console.error("Cache error:", error)
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
434
544
|
#### 2. CQN Query Caching
|
|
435
545
|
|
|
436
546
|
For more advanced CAP integration, cache CAP's CQN queries directly. By passing in the query, a dynamic key is generated based on the CQN structure of the query. Note, that passing in queries with dynamic parameters (e.g. `SELECT.from(Foo).where({id: 1})`) will result in a different key for each query execution.
|
|
@@ -463,6 +573,23 @@ Because the cache key has been dynamically created at runtime, it will also be r
|
|
|
463
573
|
const { result, cacheKey } = await cache.rt.run(query, db)
|
|
464
574
|
```
|
|
465
575
|
|
|
576
|
+
**Error Handling for Read-Through Operations:**
|
|
577
|
+
|
|
578
|
+
Read-through operations never throw errors, even when cache operations fail. Instead, they include error information in the response:
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
// Read-through operations always return a result, even on cache errors
|
|
582
|
+
const { result, cacheKey, metadata, cacheErrors } = await cache.rt.run(query, db)
|
|
583
|
+
|
|
584
|
+
if (cacheErrors && cacheErrors.length > 0) {
|
|
585
|
+
console.log("Cache errors occurred:", cacheErrors)
|
|
586
|
+
// Result will be fetched from remote service despite cache errors
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// The result is always available, regardless of cache errors
|
|
590
|
+
return result
|
|
591
|
+
```
|
|
592
|
+
|
|
466
593
|
#### 3. RemoteService Request-Level Caching
|
|
467
594
|
|
|
468
595
|
Cache entire CAP requests with context awareness (e.g. user, tenant, locale, etc.), which is useful for caching slow remote service calls or even application services. The caching service will automatically generate a key for the request based on the request object and the current user, tenant and locale (if not configured otherwise).
|
|
@@ -770,6 +897,36 @@ for await (const entry of iterator) {
|
|
|
770
897
|
|
|
771
898
|
This will return an iterator over all cache entries. You can use this to traverse all cache entries and invalidate them based on a specific condition. You should only use this for small caches (e.g. by using multiple caching services with different namespaces).
|
|
772
899
|
|
|
900
|
+
### TypeScript Support
|
|
901
|
+
|
|
902
|
+
cds-caching includes comprehensive TypeScript definitions. The library is written in JavaScript but provides full TypeScript support for better development experience.
|
|
903
|
+
|
|
904
|
+
#### Basic Usage with TypeScript
|
|
905
|
+
|
|
906
|
+
```typescript
|
|
907
|
+
import { CachingService, CacheOptions, ReadThroughResult } from 'cds-caching';
|
|
908
|
+
|
|
909
|
+
const cache = await cds.connect.to('caching') as CachingService;
|
|
910
|
+
|
|
911
|
+
// Basic cache operations
|
|
912
|
+
await cache.set('my-key', { data: 'value' }, { ttl: 3600 });
|
|
913
|
+
const value = await cache.get('my-key');
|
|
914
|
+
|
|
915
|
+
// Read-through operations with full type safety
|
|
916
|
+
const { result, cacheKey, metadata } = await cache.rt.send(request, service, {
|
|
917
|
+
ttl: 1800,
|
|
918
|
+
tags: ['user-data']
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
// Function wrapping with type inference
|
|
922
|
+
const cachedFunction = cache.rt.wrap('expensive-operation', async (id: string) => {
|
|
923
|
+
return await this.performExpensiveOperation(id);
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
const { result: operationResult } = await cachedFunction('user-123');
|
|
927
|
+
|
|
928
|
+
```
|
|
929
|
+
|
|
773
930
|
### OData Service Caching Considerations
|
|
774
931
|
|
|
775
932
|
While caching individual requests can improve performance, **caching an entire OData service is generally not recommended**. Here's why:
|
package/lib/CachingService.d.ts
CHANGED
|
@@ -124,6 +124,12 @@ export declare class CachingService extends Service {
|
|
|
124
124
|
compression: any;
|
|
125
125
|
credentials: Record<string, any>;
|
|
126
126
|
namespace?: string;
|
|
127
|
+
throwOnErrors?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* When enabled, basic operations (`get`, `set`, `delete`, ...) run in a dedicated cache transaction.
|
|
130
|
+
* This isolates cache access from the caller's request transaction (useful for concurrent BEFORE handlers).
|
|
131
|
+
*/
|
|
132
|
+
transactionalOperations?: boolean;
|
|
127
133
|
};
|
|
128
134
|
|
|
129
135
|
private cacheAnnotatedFunctions: {
|
|
@@ -146,52 +152,52 @@ export declare class CachingService extends Service {
|
|
|
146
152
|
/**
|
|
147
153
|
* Set a value in the cache
|
|
148
154
|
*/
|
|
149
|
-
set(key: string | object, value: any, options?: CacheOptions): Promise<void>;
|
|
155
|
+
set(key: string | object, value: any, options?: CacheOptions, tx?: any): Promise<void>;
|
|
150
156
|
|
|
151
157
|
/**
|
|
152
158
|
* Get a value from the cache
|
|
153
159
|
*/
|
|
154
|
-
get(key: string | object): Promise<any>;
|
|
160
|
+
get(key: string | object, tx?: any): Promise<any>;
|
|
155
161
|
|
|
156
162
|
/**
|
|
157
163
|
* Check if a key exists in the cache
|
|
158
164
|
*/
|
|
159
|
-
has(key: string | object): Promise<boolean>;
|
|
165
|
+
has(key: string | object, tx?: any): Promise<boolean>;
|
|
160
166
|
|
|
161
167
|
/**
|
|
162
168
|
* Delete a key from the cache
|
|
163
169
|
*/
|
|
164
|
-
delete(key: string | object): Promise<boolean>;
|
|
170
|
+
delete(key: string | object, tx?: any): Promise<boolean>;
|
|
165
171
|
|
|
166
172
|
/**
|
|
167
173
|
* Clear all cache entries
|
|
168
174
|
*/
|
|
169
|
-
clear(): Promise<void>;
|
|
175
|
+
clear(tx?: any): Promise<void>;
|
|
170
176
|
|
|
171
177
|
/**
|
|
172
178
|
* Delete all keys that have a specific tag
|
|
173
179
|
*/
|
|
174
|
-
deleteByTag(tag: string): Promise<void>;
|
|
180
|
+
deleteByTag(tag: string, tx?: any): Promise<void>;
|
|
175
181
|
|
|
176
182
|
/**
|
|
177
183
|
* Get metadata for a key
|
|
178
184
|
*/
|
|
179
|
-
metadata(key: string | object): Promise<CacheMetadata | null>;
|
|
185
|
+
metadata(key: string | object, tx?: any): Promise<CacheMetadata | null>;
|
|
180
186
|
|
|
181
187
|
/**
|
|
182
188
|
* Get tags for a key
|
|
183
189
|
*/
|
|
184
|
-
tags(key: string | object): Promise<string[]>;
|
|
190
|
+
tags(key: string | object, tx?: any): Promise<string[]>;
|
|
185
191
|
|
|
186
192
|
/**
|
|
187
193
|
* Iterator for all cache entries
|
|
188
194
|
*/
|
|
189
|
-
iterator(): AsyncIterableIterator<[string, CacheMetadata]>;
|
|
195
|
+
iterator(tx?: any): AsyncIterableIterator<[string, CacheMetadata]>;
|
|
190
196
|
|
|
191
197
|
/**
|
|
192
198
|
* Get a raw value from the cache without statistics tracking
|
|
193
199
|
*/
|
|
194
|
-
getRaw(key: string | object): Promise<any>;
|
|
200
|
+
getRaw(key: string | object, tx?: any): Promise<any>;
|
|
195
201
|
|
|
196
202
|
// ============================================================================
|
|
197
203
|
// Deprecated CAP Operations (for backward compatibility)
|
package/lib/CachingService.js
CHANGED
|
@@ -13,11 +13,19 @@ class CachingService extends cds.Service {
|
|
|
13
13
|
async init() {
|
|
14
14
|
super.init()
|
|
15
15
|
this.log = cds.log('cds-caching')
|
|
16
|
-
this.options =
|
|
16
|
+
this.options = {
|
|
17
17
|
store: null,
|
|
18
18
|
compression: null,
|
|
19
|
-
credentials: {}
|
|
19
|
+
credentials: {},
|
|
20
|
+
namespace: null,
|
|
21
|
+
throwOnErrors: false,
|
|
22
|
+
// When enabled, basic cache operations (`get`, `set`, `delete`, ...)
|
|
23
|
+
// will be executed in a dedicated cache transaction (`cache.tx()`),
|
|
24
|
+
// isolating them from the caller's request transaction (e.g. concurrent BEFORE handlers).
|
|
25
|
+
transactionalOperations: false,
|
|
26
|
+
...(this.options || {})
|
|
20
27
|
};
|
|
28
|
+
this.options.credentials = this.options.credentials || {};
|
|
21
29
|
|
|
22
30
|
// Initialize managers
|
|
23
31
|
this.storeManager = new CacheStoreManager();
|
|
@@ -128,15 +136,61 @@ class CachingService extends cds.Service {
|
|
|
128
136
|
|
|
129
137
|
createKey(...args) { return this.keyManager.createKey(...args); }
|
|
130
138
|
|
|
131
|
-
async set(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
async
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
async set(key, value, options = {}, tx = null) {
|
|
140
|
+
if (tx) return this.basicOperations.set(key, value, options, tx);
|
|
141
|
+
if (this.options.transactionalOperations) return this.basicOperations.setInTx(key, value, options);
|
|
142
|
+
return this.basicOperations.set(key, value, options);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async get(key, tx = null) {
|
|
146
|
+
if (tx) return this.basicOperations.get(key, tx);
|
|
147
|
+
if (this.options.transactionalOperations) return this.basicOperations.getInTx(key);
|
|
148
|
+
return this.basicOperations.get(key);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async has(key, tx = null) {
|
|
152
|
+
// `has()` bypasses CAP tx handling in BasicOperations, so the `tx` argument is ignored.
|
|
153
|
+
// It is accepted here for API symmetry.
|
|
154
|
+
return this.basicOperations.has(key, tx);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async delete(key, tx = null) {
|
|
158
|
+
if (tx) return this.basicOperations.delete(key, tx);
|
|
159
|
+
if (this.options.transactionalOperations) return this.basicOperations.deleteInTx(key);
|
|
160
|
+
return this.basicOperations.delete(key);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async clear(tx = null) {
|
|
164
|
+
if (tx) return this.basicOperations.clear(tx);
|
|
165
|
+
if (this.options.transactionalOperations) return this.basicOperations.clearInTx();
|
|
166
|
+
return this.basicOperations.clear();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async deleteByTag(tag, tx = null) {
|
|
170
|
+
if (tx) return this.basicOperations.deleteByTag(tag, tx);
|
|
171
|
+
if (this.options.transactionalOperations) return this.basicOperations.deleteByTagInTx(tag);
|
|
172
|
+
return this.basicOperations.deleteByTag(tag);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async metadata(key, tx = null) {
|
|
176
|
+
if (tx) return this.basicOperations.metadata(key, tx);
|
|
177
|
+
if (this.options.transactionalOperations) return this.basicOperations.metadataInTx(key);
|
|
178
|
+
return this.basicOperations.metadata(key);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async tags(key, tx = null) {
|
|
182
|
+
if (tx) return this.basicOperations.tags(key, tx);
|
|
183
|
+
if (this.options.transactionalOperations) return this.basicOperations.tagsInTx(key);
|
|
184
|
+
return this.basicOperations.tags(key);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async getRaw(key, tx = null) {
|
|
188
|
+
if (tx) return this.basicOperations.getRaw(key, tx);
|
|
189
|
+
if (this.options.transactionalOperations) return this.basicOperations.getRawInTx(key);
|
|
190
|
+
return this.basicOperations.getRaw(key);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async *iterator(tx = null) { return yield* this.basicOperations.iterator(tx); }
|
|
140
194
|
|
|
141
195
|
// ============================================================================
|
|
142
196
|
// PUBLIC API - Read Through Operations
|
|
@@ -164,7 +218,8 @@ class CachingService extends cds.Service {
|
|
|
164
218
|
if (typeof args[0] !== "object" || !args[1].send || typeof args[1] !== "object" || args[0].method !== "GET") {
|
|
165
219
|
return super.send(...args);
|
|
166
220
|
} else {
|
|
167
|
-
|
|
221
|
+
const result = await this.rt.send(...args);
|
|
222
|
+
return result.result;
|
|
168
223
|
}
|
|
169
224
|
}
|
|
170
225
|
|
|
@@ -177,7 +232,8 @@ class CachingService extends cds.Service {
|
|
|
177
232
|
if (typeof args[0] !== "object" && !["Request", "NoaRequest", "ODataRequest", "cds.ql"].includes(args[0].constructor.name)) {
|
|
178
233
|
return super.run(...args);
|
|
179
234
|
} else {
|
|
180
|
-
|
|
235
|
+
const result = await this.rt.run(...args);
|
|
236
|
+
return result.result;
|
|
181
237
|
}
|
|
182
238
|
}
|
|
183
239
|
|