cds-caching 0.3.3 → 1.1.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 +691 -278
- package/cds-plugin.js +2 -2
- package/index.cds +165 -20
- package/lib/CachingService.d.ts +328 -0
- package/lib/CachingService.js +373 -0
- package/lib/operations/AsyncOperations.js +335 -0
- package/lib/operations/BasicOperations.js +211 -0
- package/lib/operations/CapOperations.js +540 -0
- package/lib/support/CacheStatisticsHandler.js +1124 -0
- package/lib/support/CacheStoreManager.js +120 -0
- package/lib/support/KeyManager.js +132 -0
- package/lib/support/RuntimeConfigurationManager.js +148 -0
- package/lib/support/StatisticsPersistenceManager.js +375 -0
- package/lib/support/TagResolver.js +125 -0
- package/lib/util.js +201 -0
- package/package.json +18 -13
- package/srv/caching-api-service.js +124 -0
- package/srv/CacheStatisticsHandler.js +0 -213
- package/srv/CachingService.js +0 -587
- package/srv/statistics-service.cds +0 -37
- package/srv/statistics-service.js +0 -72
- package/srv/util.js +0 -101
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages basic cache operations with statistics tracking
|
|
3
|
+
*/
|
|
4
|
+
class BasicOperations {
|
|
5
|
+
constructor(cache, keyManager, tagResolver, statistics) {
|
|
6
|
+
this.cache = cache;
|
|
7
|
+
this.keyManager = keyManager;
|
|
8
|
+
this.tagResolver = tagResolver;
|
|
9
|
+
this.statistics = statistics;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Set a value in the cache
|
|
14
|
+
* @param {string|object} key - the key to set
|
|
15
|
+
* @param {any} value - the value to cache
|
|
16
|
+
* @param {object} options - cache options
|
|
17
|
+
* @returns {Promise<void>}
|
|
18
|
+
*/
|
|
19
|
+
async set(key, value, options = {}) {
|
|
20
|
+
const wrappedValue = {
|
|
21
|
+
value,
|
|
22
|
+
tags: this.tagResolver.resolveTags(options.tags, value, options.params) || [],
|
|
23
|
+
timestamp: Date.now()
|
|
24
|
+
};
|
|
25
|
+
const createdKey = this.keyManager.createKey(key, {}, options.key);
|
|
26
|
+
await this.cache.send('SET', {
|
|
27
|
+
key: createdKey,
|
|
28
|
+
value: wrappedValue,
|
|
29
|
+
ttl: options.ttl || 0
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const metadata = {
|
|
33
|
+
dataType: 'Operation',
|
|
34
|
+
operation: 'SET',
|
|
35
|
+
operationType: 'BASIC',
|
|
36
|
+
metadata: JSON.stringify({ key: createdKey, ttl: options.ttl || 0 }),
|
|
37
|
+
cacheOptions: JSON.stringify(options)
|
|
38
|
+
};
|
|
39
|
+
this.statistics.recordNativeSet(createdKey, metadata);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get a value from the cache
|
|
44
|
+
* @param {string|object} key - the key to get
|
|
45
|
+
* @returns {Promise<any>} - the cached value
|
|
46
|
+
*/
|
|
47
|
+
async get(key) {
|
|
48
|
+
const createdKey = this.keyManager.createKey(key);
|
|
49
|
+
const wrappedValue = await this.cache.send('GET', {
|
|
50
|
+
key: createdKey
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Record the native get operation
|
|
54
|
+
const metadata = {
|
|
55
|
+
dataType: 'Operation',
|
|
56
|
+
operation: 'GET',
|
|
57
|
+
operationType: 'BASIC',
|
|
58
|
+
metadata: JSON.stringify({ key: createdKey })
|
|
59
|
+
};
|
|
60
|
+
const isHit = wrappedValue !== undefined && wrappedValue !== null;
|
|
61
|
+
this.statistics.recordNativeGet(createdKey, isHit, metadata);
|
|
62
|
+
|
|
63
|
+
return wrappedValue?.value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if a key exists in the cache
|
|
68
|
+
* @param {string|object} key - the key to check
|
|
69
|
+
* @returns {Promise<boolean>} - whether the key exists
|
|
70
|
+
*/
|
|
71
|
+
async has(key) {
|
|
72
|
+
const createdKey = this.keyManager.createKey(key);
|
|
73
|
+
try {
|
|
74
|
+
return await this.cache.cache.has(createdKey);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (this.cache.options.throwOnErrors) {
|
|
77
|
+
throw error;
|
|
78
|
+
} else {
|
|
79
|
+
return false; // We don't want to throw errors here
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Delete a key from the cache
|
|
86
|
+
* @param {string|object} key - the key to delete
|
|
87
|
+
* @returns {Promise<boolean>} - whether the key was deleted
|
|
88
|
+
*/
|
|
89
|
+
async delete(key) {
|
|
90
|
+
const createdKey = this.keyManager.createKey(key);
|
|
91
|
+
const result = await this.cache.send('DELETE', {
|
|
92
|
+
key: createdKey
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Record the native delete operation
|
|
96
|
+
const metadata = {
|
|
97
|
+
dataType: 'Operation',
|
|
98
|
+
operation: 'DELETE',
|
|
99
|
+
operationType: 'BASIC',
|
|
100
|
+
metadata: JSON.stringify({ key: createdKey })
|
|
101
|
+
};
|
|
102
|
+
this.statistics.recordNativeDelete(createdKey, metadata);
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Clear all cache entries
|
|
109
|
+
* @returns {Promise<void>}
|
|
110
|
+
*/
|
|
111
|
+
async clear() {
|
|
112
|
+
await this.cache.send('CLEAR', {
|
|
113
|
+
deleteAll: true
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Record the native clear operation
|
|
117
|
+
const metadata = {
|
|
118
|
+
dataType: 'Operation',
|
|
119
|
+
operation: 'CLEAR',
|
|
120
|
+
operationType: 'BASIC',
|
|
121
|
+
metadata: JSON.stringify({ cache: this.cache.name })
|
|
122
|
+
};
|
|
123
|
+
this.statistics.recordNativeClear(metadata);
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Delete all keys that have a specific tag
|
|
129
|
+
* @param {string} tag - the tag to match
|
|
130
|
+
* @returns {Promise<void>}
|
|
131
|
+
*/
|
|
132
|
+
async deleteByTag(tag) {
|
|
133
|
+
for await (const [key, wrappedValue] of this.iterator()) {
|
|
134
|
+
if (wrappedValue?.tags?.includes(tag)) {
|
|
135
|
+
await this.delete(key);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Record the native deleteByTag operation
|
|
140
|
+
const metadata = {
|
|
141
|
+
dataType: 'Operation',
|
|
142
|
+
operation: 'DELETE_BY_TAG',
|
|
143
|
+
operationType: 'BASIC',
|
|
144
|
+
metadata: JSON.stringify({ tag: tag, cache: this.cache.name })
|
|
145
|
+
};
|
|
146
|
+
this.statistics.recordNativeDeleteByTag(tag, metadata);
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get metadata for a key
|
|
152
|
+
* @param {string|object} key - the key to get metadata for
|
|
153
|
+
* @returns {Promise<object|null>} - the metadata or null if not found
|
|
154
|
+
*/
|
|
155
|
+
async metadata(key) {
|
|
156
|
+
const createdKey = this.keyManager.createKey(key);
|
|
157
|
+
const wrappedValue = await this.cache.send('GET', {
|
|
158
|
+
key: createdKey
|
|
159
|
+
});
|
|
160
|
+
if (!wrappedValue) return null;
|
|
161
|
+
|
|
162
|
+
const { value, ...metadata } = wrappedValue;
|
|
163
|
+
return metadata;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get tags for a key
|
|
168
|
+
* @param {string|object} key - the key to get tags for
|
|
169
|
+
* @returns {Promise<string[]>} - the tags
|
|
170
|
+
*/
|
|
171
|
+
async tags(key) {
|
|
172
|
+
const createdKey = this.keyManager.createKey(key);
|
|
173
|
+
const wrappedValue = await this.cache.send('GET', {
|
|
174
|
+
key: createdKey
|
|
175
|
+
});
|
|
176
|
+
return wrappedValue?.tags || [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get a raw value from the cache without statistics tracking
|
|
181
|
+
* @param {string|object} key - the key to get
|
|
182
|
+
* @returns {Promise<any>} - the raw cached value
|
|
183
|
+
*/
|
|
184
|
+
async getRaw(key) {
|
|
185
|
+
const createdKey = this.keyManager.createKey(key);
|
|
186
|
+
const wrappedValue = await this.cache.send('GET', {
|
|
187
|
+
key: createdKey
|
|
188
|
+
});
|
|
189
|
+
return wrappedValue?.value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Iterator for all cache entries
|
|
194
|
+
* @returns {AsyncIterator} - iterator for cache entries
|
|
195
|
+
*/
|
|
196
|
+
async *iterator() {
|
|
197
|
+
for await (const [key, value] of this.cache.cache.iterator()) {
|
|
198
|
+
if (typeof value === "string") {
|
|
199
|
+
try {
|
|
200
|
+
yield [key, JSON.parse(value)];
|
|
201
|
+
} catch (error) {
|
|
202
|
+
yield [key, value];
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
yield [key, value];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = BasicOperations;
|