cds-caching 0.3.3 → 1.0.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/cds-plugin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const cds = require('@sap/cds')
2
- const CachingService = require('./srv/CachingService')
3
- const { scanCachingAnnotations } = require('./srv/util')
2
+ const CachingService = require('./lib/CachingService')
3
+ const { scanCachingAnnotations } = require('./lib/util')
4
4
 
5
5
  cds.on('served', scanCachingAnnotations)
6
6
 
package/index.cds CHANGED
@@ -1,21 +1,166 @@
1
- namespace cds_caching;
2
-
3
- entity Statistics {
4
- key ID : String; // e.g., 'daily:2024-03-20' or 'hourly:2024-03-20-15'
5
- key cache : String;
6
- timestamp : DateTime;
7
- period : String enum {
8
- hourly;
9
- daily;
10
- monthly;
11
- }; // Granularity
12
- hits : Integer default 0;
13
- misses : Integer default 0;
14
- sets : Integer default 0;
15
- deletes : Integer default 0;
16
- errors : Integer default 0;
17
- avgLatency : Double; // in milliseconds
18
- p95Latency : Double; // 95th percentile latency
19
- memoryUsage : Integer; // in bytes
20
- itemCount : Integer;
1
+ context plugin.cds_caching {
2
+
3
+ entity Caches {
4
+ key name : String;
5
+ config : String;
6
+ metricsEnabled : Boolean default false;
7
+ keyMetricsEnabled : Boolean default false;
8
+ metrics : Composition of many Metrics
9
+ on metrics.cache = $self.name;
10
+ keyMetrics : Composition of many KeyMetrics
11
+ on keyMetrics.cache = $self.name;
12
+ }
13
+
14
+ entity Metrics {
15
+ key ID : String; // e.g., 'daily:2024-03-20' or 'hourly:2024-03-20-15'
16
+ key cache : String;
17
+ timestamp : DateTime;
18
+ period : String enum {
19
+ hourly;
20
+ daily;
21
+ monthly;
22
+ }; // Granularity
23
+
24
+ // Read-through metrics (hits and misses only)
25
+ hits : Integer default 0;
26
+ misses : Integer default 0;
27
+ errors : Integer default 0;
28
+ totalRequests : Integer default 0;
29
+ // Read-through latency metrics
30
+ avgHitLatency : Double; // average hit latency in milliseconds
31
+ minHitLatency : Double; // minimum hit latency
32
+ maxHitLatency : Double; // maximum hit latency
33
+ avgMissLatency : Double; // average miss latency in milliseconds
34
+ minMissLatency : Double; // minimum miss latency
35
+ maxMissLatency : Double; // maximum miss latency
36
+ avgReadThroughLatency : Double; // average read through latency in milliseconds
37
+
38
+ // Read-through performance metrics
39
+ hitRatio : Double; // hit ratio as percentage
40
+ throughput : Double; // requests per second
41
+ errorRate : Double; // error rate as percentage
42
+ cacheEfficiency : Double; // ratio of miss latency to hit latency
43
+
44
+ // Native function metrics (basic counts only)
45
+ nativeSets : Integer default 0;
46
+ nativeGets : Integer default 0;
47
+ nativeDeletes : Integer default 0;
48
+ nativeClears : Integer default 0;
49
+ nativeDeleteByTags : Integer default 0;
50
+ nativeErrors : Integer default 0;
51
+ totalNativeOperations : Integer default 0;
52
+ // Native function performance metrics
53
+ nativeThroughput : Double; // native operations per second
54
+ nativeErrorRate : Double; // native operation error rate
55
+
56
+ // Common metrics
57
+ memoryUsage : Integer; // in bytes
58
+ itemCount : Integer;
59
+ uptimeMs : Integer; // uptime in milliseconds
60
+ }
61
+
62
+ entity KeyMetrics {
63
+ key ID : String;
64
+ key cache : String;
65
+ key keyName : String;
66
+ lastAccess : DateTime;
67
+ period : String enum {
68
+ current;
69
+ hourly;
70
+ daily;
71
+ };
72
+
73
+ // Operation type tracking
74
+ operationType : String enum {
75
+ read_through;
76
+ native;
77
+ mixed;
78
+ };
79
+
80
+ // Read-through metrics (hits and misses only)
81
+ hits : Integer default 0;
82
+ misses : Integer default 0;
83
+ errors : Integer default 0;
84
+ totalRequests : Integer default 0;
85
+ hitRatio : Double; // hit ratio as percentage
86
+ cacheEfficiency : Double; // ratio of miss latency to hit latency
87
+
88
+ // Read-through latency metrics
89
+ avgHitLatency : Double; // average hit latency in milliseconds
90
+ minHitLatency : Double; // minimum hit latency
91
+ maxHitLatency : Double; // maximum hit latency
92
+ avgMissLatency : Double; // average miss latency in milliseconds
93
+ minMissLatency : Double; // minimum miss latency
94
+ maxMissLatency : Double; // maximum miss latency
95
+ avgReadThroughLatency : Double; // average read through latency in milliseconds
96
+
97
+ // Read-through performance metrics
98
+ throughput : Double; // requests per second
99
+ errorRate : Double; // error rate as percentage
100
+
101
+ // Native function metrics (counts only)
102
+ nativeHits : Integer default 0;
103
+ nativeMisses : Integer default 0;
104
+ nativeSets : Integer default 0;
105
+ nativeDeletes : Integer default 0;
106
+ nativeClears : Integer default 0;
107
+ nativeDeleteByTags : Integer default 0;
108
+ nativeErrors : Integer default 0;
109
+ totalNativeOperations : Integer default 0;
110
+ // Native function performance metrics
111
+ nativeThroughput : Double; // native operations per second
112
+ nativeErrorRate : Double; // native operation error rate
113
+
114
+ // Metadata fields
115
+ dataType : String;
116
+ operation : String; // concatenated cache service operations (e.g., SET, GET, WRAP, RUN...)
117
+ metadata : LargeString; // JSON string for additional metadata
118
+ // Enhanced context information
119
+ context : String; // JSON string with detailed context
120
+ query : LargeString; // CQL query text if applicable
121
+ subject : LargeString; // JSON string with subject information
122
+ target : String; // Target information
123
+ tenant : String; // Tenant information
124
+ user : String; // User information
125
+ locale : String; // Locale information
126
+ timestamp : DateTime; // When this key was first accessed
127
+ cacheOptions : String; // JSON string with cache options
128
+ }
129
+
130
+
131
+ @impl: 'cds-caching/srv/caching-api-service'
132
+ service CachingApiService {
133
+
134
+ entity Caches as projection on plugin.cds_caching.Caches
135
+ actions {
136
+
137
+ function getEntries() returns array of {
138
+ entryKey : String;
139
+ value : String;
140
+ timestamp : DateTime;
141
+ tags : array of String;
142
+ };
143
+
144
+ function getEntry(key : String) returns {
145
+ value : String;
146
+ timestamp : DateTime;
147
+ tags : array of String;
148
+ };
149
+
150
+ action setEntry(key : String, value : String, ttl : Integer) returns Boolean;
151
+ action deleteEntry(key : String) returns Boolean;
152
+ action clear() returns Boolean;
153
+ action clearMetrics() returns Boolean;
154
+ action clearKeyMetrics() returns Boolean;
155
+ action setMetricsEnabled(enabled : Boolean) returns Boolean;
156
+ action setKeyMetricsEnabled(enabled : Boolean) returns Boolean;
157
+ };
158
+
159
+ @readonly
160
+ entity Metrics as projection on plugin.cds_caching.Metrics;
161
+
162
+ @readonly
163
+ entity KeyMetrics as projection on plugin.cds_caching.KeyMetrics;
164
+
165
+ }
21
166
  }
@@ -0,0 +1,328 @@
1
+ import { Service, cds } from '@sap/cds';
2
+
3
+ // ============================================================================
4
+ // Type Definitions
5
+ // ============================================================================
6
+
7
+ export interface CacheTag {
8
+ template: string;
9
+ data?: string;
10
+ prefix?: string;
11
+ suffix?: string;
12
+ value?: string;
13
+ }
14
+
15
+ export interface CacheOptions {
16
+ ttl?: number;
17
+ tags?: CacheTag[] | string[];
18
+ key?: string | object;
19
+ params?: Record<string, any>;
20
+ }
21
+
22
+ export interface CacheMetadata {
23
+ value: any;
24
+ tags: CacheTag[];
25
+ timestamp: number;
26
+ }
27
+
28
+ export interface StatisticsMetadata {
29
+ dataType: string;
30
+ serviceName: string;
31
+ operation: string;
32
+ metadata: string;
33
+ entityName?: string;
34
+ queryInfo?: string;
35
+ }
36
+
37
+ export interface RuntimeConfiguration {
38
+ enableStatistics: boolean;
39
+ enableKeyTracking: boolean;
40
+ }
41
+
42
+ export interface CacheStatistics {
43
+ hits: number;
44
+ misses: number;
45
+ totalRequests: number;
46
+ hitRate: number;
47
+ averageLatency: number;
48
+ totalLatency: number;
49
+ }
50
+
51
+ export interface CacheKeyMetrics {
52
+ key: string;
53
+ hits: number;
54
+ misses: number;
55
+ totalRequests: number;
56
+ hitRate: number;
57
+ averageLatency: number;
58
+ lastAccessed: Date;
59
+ }
60
+
61
+ export interface CachableFunctionOptions {
62
+ '@cache.ttl'?: number;
63
+ '@cache.key'?: string | object;
64
+ '@cache.tags'?: string[];
65
+ }
66
+
67
+ export interface ReadThroughResult<T = any> {
68
+ result: T;
69
+ cacheKey: string;
70
+ metadata: {
71
+ hit: boolean;
72
+ latency: number;
73
+ };
74
+ }
75
+
76
+ export interface CacheAnnotatedFunction {
77
+ name: string;
78
+ options: CachableFunctionOptions;
79
+ }
80
+
81
+ // ============================================================================
82
+ // Read Through Operations Interface
83
+ // ============================================================================
84
+
85
+ export interface ReadThroughOperations {
86
+ /**
87
+ * Send a request with caching with read-through capabilities
88
+ */
89
+ send(request: any, service: Service, options?: CacheOptions): Promise<ReadThroughResult>;
90
+
91
+ /**
92
+ * Run a cached operation with automatic key generation
93
+ */
94
+ run(req: any, service: Service, options?: CacheOptions): Promise<ReadThroughResult>;
95
+
96
+ /**
97
+ * Wraps an async function and caches the result
98
+ */
99
+ wrap<T extends (...args: any[]) => Promise<any>>(
100
+ key: string,
101
+ asyncFunction: T,
102
+ options?: CacheOptions
103
+ ): (...args: Parameters<T>) => Promise<ReadThroughResult<Awaited<ReturnType<T>>>>;
104
+
105
+ /**
106
+ * Executes an async function and caches its result
107
+ */
108
+ exec<T>(
109
+ key: string,
110
+ asyncFunction: () => Promise<T>,
111
+ options?: CacheOptions
112
+ ): Promise<ReadThroughResult<T>>;
113
+ }
114
+
115
+ // ============================================================================
116
+ // CachingService Class Definition
117
+ // ============================================================================
118
+
119
+ export declare class CachingService extends Service {
120
+ // Properties
121
+ readonly name: string;
122
+ readonly options: {
123
+ store: any;
124
+ compression: any;
125
+ credentials: Record<string, any>;
126
+ namespace?: string;
127
+ };
128
+
129
+ private cacheAnnotatedFunctions: {
130
+ bound: CacheAnnotatedFunction[];
131
+ unbound: CacheAnnotatedFunction[];
132
+ };
133
+
134
+ // Read-through operations
135
+ readonly rt: ReadThroughOperations;
136
+
137
+ // ============================================================================
138
+ // Core Cache Operations
139
+ // ============================================================================
140
+
141
+ /**
142
+ * Create a cache key from various inputs
143
+ */
144
+ createKey(...args: any[]): string;
145
+
146
+ /**
147
+ * Set a value in the cache
148
+ */
149
+ set(key: string | object, value: any, options?: CacheOptions): Promise<void>;
150
+
151
+ /**
152
+ * Get a value from the cache
153
+ */
154
+ get(key: string | object): Promise<any>;
155
+
156
+ /**
157
+ * Check if a key exists in the cache
158
+ */
159
+ has(key: string | object): Promise<boolean>;
160
+
161
+ /**
162
+ * Delete a key from the cache
163
+ */
164
+ delete(key: string | object): Promise<boolean>;
165
+
166
+ /**
167
+ * Clear all cache entries
168
+ */
169
+ clear(): Promise<void>;
170
+
171
+ /**
172
+ * Delete all keys that have a specific tag
173
+ */
174
+ deleteByTag(tag: string): Promise<void>;
175
+
176
+ /**
177
+ * Get metadata for a key
178
+ */
179
+ metadata(key: string | object): Promise<CacheMetadata | null>;
180
+
181
+ /**
182
+ * Get tags for a key
183
+ */
184
+ tags(key: string | object): Promise<string[]>;
185
+
186
+ /**
187
+ * Iterator for all cache entries
188
+ */
189
+ iterator(): AsyncIterableIterator<[string, CacheMetadata]>;
190
+
191
+ /**
192
+ * Get a raw value from the cache without statistics tracking
193
+ */
194
+ getRaw(key: string | object): Promise<any>;
195
+
196
+ // ============================================================================
197
+ // Deprecated CAP Operations (for backward compatibility)
198
+ // ============================================================================
199
+
200
+ /**
201
+ * @deprecated Use cache.rt.send() instead. The rt.send() method provides enhanced functionality including read-through metadata, dynamic cache keys, and detailed mode options.
202
+ */
203
+ send(arg1: any, service: any, options?: CacheOptions): Promise<any>;
204
+
205
+ /**
206
+ * @deprecated Use cache.rt.run() instead. The rt.run() method provides enhanced functionality including read-through metadata, dynamic cache keys, and detailed mode options.
207
+ */
208
+ run(req: any, handler?: Function, options?: CacheOptions): Promise<any>;
209
+
210
+ /**
211
+ * @deprecated Use cache.rt.wrap() instead. The rt.wrap() method provides enhanced functionality including read-through metadata, dynamic cache keys, and detailed mode options.
212
+ */
213
+ wrap<T extends (...args: any[]) => Promise<any>>(
214
+ key: string,
215
+ asyncFunction: T,
216
+ options?: CacheOptions
217
+ ): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
218
+
219
+ /**
220
+ * @deprecated Use cache.rt.exec() instead. The rt.exec() method provides enhanced functionality including read-through metadata, dynamic cache keys, and detailed mode options.
221
+ */
222
+ exec<T>(
223
+ key: string,
224
+ asyncFunction: () => Promise<T>,
225
+ options?: CacheOptions
226
+ ): Promise<T>;
227
+
228
+ // ============================================================================
229
+ // Tag Resolution
230
+ // ============================================================================
231
+
232
+ /**
233
+ * Resolve tags for a given query
234
+ */
235
+ resolveTags(...args: any[]): Promise<any>;
236
+
237
+ // ============================================================================
238
+ // Statistics and Metrics
239
+ // ============================================================================
240
+
241
+ /**
242
+ * Get statistics for a specific period
243
+ */
244
+ getMetrics(from: Date, to: Date): Promise<CacheStatistics>;
245
+
246
+ /**
247
+ * Get key-specific metrics for a specific period
248
+ */
249
+ getKeyMetrics(key: string, from: Date, to: Date): Promise<CacheKeyMetrics>;
250
+
251
+ /**
252
+ * Get current statistics
253
+ */
254
+ getCurrentMetrics(): Promise<CacheStatistics>;
255
+
256
+ /**
257
+ * Get current key metrics
258
+ */
259
+ getCurrentKeyMetrics(): Promise<CacheKeyMetrics>;
260
+
261
+ /**
262
+ * Clear all metrics
263
+ */
264
+ clearMetrics(): Promise<void>;
265
+
266
+ /**
267
+ * Clear key metrics
268
+ */
269
+ clearKeyMetrics(): Promise<void>;
270
+
271
+ /**
272
+ * Enable or disable statistics at runtime
273
+ */
274
+ setMetricsEnabled(enabled: boolean): Promise<void>;
275
+
276
+ /**
277
+ * Enable or disable key tracking at runtime
278
+ */
279
+ setKeyMetricsEnabled(enabled: boolean): Promise<void>;
280
+
281
+ /**
282
+ * Persist metrics to database
283
+ */
284
+ persistMetrics(): Promise<void>;
285
+
286
+ // ============================================================================
287
+ // Configuration Management
288
+ // ============================================================================
289
+
290
+ /**
291
+ * Get current runtime configuration
292
+ */
293
+ getRuntimeConfiguration(): Promise<RuntimeConfiguration>;
294
+
295
+ /**
296
+ * Reload runtime configuration from database
297
+ */
298
+ reloadRuntimeConfiguration(): Promise<void>;
299
+
300
+ /**
301
+ * Add a cachable function
302
+ */
303
+ addCachableFunction(
304
+ name: string,
305
+ options: CachableFunctionOptions,
306
+ isBound?: boolean
307
+ ): void;
308
+
309
+ /**
310
+ * Dispose of the service
311
+ */
312
+ dispose(): Promise<void>;
313
+
314
+ // ============================================================================
315
+ // Private Methods (for internal use)
316
+ // ============================================================================
317
+
318
+ private setupStatisticsHooks(): void;
319
+ private loadRuntimeConfiguration(): Promise<void>;
320
+ private getElapsedMs(startTime: [number, number]): number;
321
+ private _getRaw(key: string | object): Promise<any>;
322
+ }
323
+
324
+ // ============================================================================
325
+ // Module Export
326
+ // ============================================================================
327
+
328
+ export default CachingService;