cacheable 0.8.0 → 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 +38 -8
- package/dist/index.cjs +380 -14
- package/dist/index.d.cts +49 -2
- package/dist/index.d.ts +49 -2
- package/dist/index.js +377 -13
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -15,10 +15,12 @@
|
|
|
15
15
|
* Not bloated with additional modules
|
|
16
16
|
* Extendable to your own caching engine
|
|
17
17
|
* Scalable and trusted storage engine by Keyv
|
|
18
|
+
* Memory Caching with LRU and Expiration `CacheableMemory`
|
|
18
19
|
* Resilient to failures with try/catch and offline
|
|
19
20
|
* Hooks and Events to extend functionality
|
|
20
21
|
* Comprehensive testing and code coverage
|
|
21
22
|
* Distributed Caching Sync via Pub/Sub (coming soon)
|
|
23
|
+
* ESM and CommonJS support with TypeScript
|
|
22
24
|
* Maintained and supported regularly
|
|
23
25
|
|
|
24
26
|
## Getting Started
|
|
@@ -129,11 +131,11 @@ The following options are available for you to configure `cacheable`:
|
|
|
129
131
|
* `primary`: The primary store for the cache (layer 1) defaults to in-memory by Keyv.
|
|
130
132
|
* `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
|
|
131
133
|
* `nonBlocking`: If the secondary store is non-blocking. Default is `false`.
|
|
132
|
-
* `
|
|
134
|
+
* `stats`: To enable statistics for this instance. Default is `false`.
|
|
133
135
|
|
|
134
136
|
## Cacheable Statistics (Instance Only)
|
|
135
137
|
|
|
136
|
-
If you want to enable statistics for your instance you can set the `
|
|
138
|
+
If you want to enable statistics for your instance you can set the `.stats.enabled` property to `true` in the options. This will enable statistics for your instance and you can get the statistics by calling the `stats` property. Here are the following property statistics:
|
|
137
139
|
|
|
138
140
|
* `hits`: The number of hits in the cache.
|
|
139
141
|
* `misses`: The number of misses in the cache.
|
|
@@ -145,7 +147,7 @@ If you want to enable statistics for your instance you can set the `enableStats`
|
|
|
145
147
|
* `vsize`: The estimated byte size of the values in the cache.
|
|
146
148
|
* `ksize`: The estimated byte size of the keys in the cache.
|
|
147
149
|
|
|
148
|
-
You can clear the stats by calling the
|
|
150
|
+
You can clear / reset the stats by calling the `.stats.reset()` method.
|
|
149
151
|
|
|
150
152
|
_This does not enable statistics for your layer 2 cache as that is a distributed cache_.
|
|
151
153
|
|
|
@@ -157,13 +159,11 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
|
|
|
157
159
|
* `getMany([keys])`: Gets multiple values from the cache.
|
|
158
160
|
* `has(key | [key])`: Checks if a value exists in the cache.
|
|
159
161
|
* `hasMany([keys])`: Checks if multiple values exist in the cache.
|
|
160
|
-
* `take(key)`: Takes a value from the cache and deletes it.
|
|
161
|
-
* `takeMany([keys])`: Takes multiple values from the cache and deletes them.
|
|
162
|
+
* `take(key)`: Takes a value from the cache and deletes it.
|
|
163
|
+
* `takeMany([keys])`: Takes multiple values from the cache and deletes them.
|
|
162
164
|
* `delete(key | [key])`: Deletes a value from the cache.
|
|
163
165
|
* `deleteMany([keys])`: Deletes multiple values from the cache.
|
|
164
166
|
* `clear()`: Clears the cache stores. Be careful with this as it will clear both layer 1 and layer 2.
|
|
165
|
-
* `clearPrimary()`: Clears the primary store. (coming soon)
|
|
166
|
-
* `clearSecondary()`: Clears the secondary store. (coming soon)
|
|
167
167
|
* `wrap(function, options)`: Wraps a function in a cache. (coming soon)
|
|
168
168
|
* `disconnect()`: Disconnects from the cache stores.
|
|
169
169
|
* `onHook(hook, callback)`: Sets a hook.
|
|
@@ -174,7 +174,37 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
|
|
|
174
174
|
* `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
|
|
175
175
|
* `nonBlocking`: If the secondary store is non-blocking. Default is `false`.
|
|
176
176
|
* `stats`: The statistics for this instance which includes `hits`, `misses`, `sets`, `deletes`, `clears`, `errors`, `count`, `vsize`, `ksize`.
|
|
177
|
-
|
|
177
|
+
|
|
178
|
+
## CacheableMemory - In-Memory Cache
|
|
179
|
+
|
|
180
|
+
`cacheable` comes with a built-in in-memory cache called `CacheableMemory`. This is a simple in-memory cache that is used as the primary store for `cacheable`. You can use this as a standalone cache or as a primary store for `cacheable`. Here is an example of how to use `CacheableMemory`:
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
import { CacheableMemory } from 'cacheable';
|
|
184
|
+
const options = {
|
|
185
|
+
ttl: 60 * 60 * 1000, // 1 hour
|
|
186
|
+
useClones: true, // use clones for the values (default is true)
|
|
187
|
+
lruSize: 1000, // the size of the LRU cache (default is 0 which is unlimited)
|
|
188
|
+
}
|
|
189
|
+
const cache = new CacheableMemory(options);
|
|
190
|
+
await cache.set('key', 'value');
|
|
191
|
+
const value = await cache.get('key'); // value
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
You can use `CacheableMemory` as a standalone cache or as a primary store for `cacheable`. You can also set the `useClones` property to `false` if you want to use the same reference for the values. This is useful if you are using large objects and want to save memory. The `lruSize` property is the size of the LRU cache and is set to `0` by default which is unlimited. When setting the `lruSize` property it will limit the number of keys in the cache.
|
|
195
|
+
|
|
196
|
+
This simple in-memory cache uses multiple Map objects and a with `expiration` and `lru` policies if set to manage the in memory cache at scale.
|
|
197
|
+
|
|
198
|
+
### CacheableMemory API
|
|
199
|
+
|
|
200
|
+
* `set(key, value, ttl?)`: Sets a value in the cache.
|
|
201
|
+
* `get(key)`: Gets a value from the cache.
|
|
202
|
+
* `has(key)`: Checks if a value exists in the cache.
|
|
203
|
+
* `delete(key)`: Deletes a value from the cache.
|
|
204
|
+
* `clear()`: Clears the cache.
|
|
205
|
+
* `size()`: The number of keys in the cache.
|
|
206
|
+
* `keys()`: The keys in the cache.
|
|
207
|
+
|
|
178
208
|
|
|
179
209
|
## How to Contribute
|
|
180
210
|
|
package/dist/index.cjs
CHANGED
|
@@ -22,7 +22,9 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
Cacheable: () => Cacheable,
|
|
24
24
|
CacheableEvents: () => CacheableEvents,
|
|
25
|
-
CacheableHooks: () => CacheableHooks
|
|
25
|
+
CacheableHooks: () => CacheableHooks,
|
|
26
|
+
CacheableMemory: () => CacheableMemory,
|
|
27
|
+
CacheableStats: () => CacheableStats
|
|
26
28
|
});
|
|
27
29
|
module.exports = __toCommonJS(src_exports);
|
|
28
30
|
var import_keyv = require("keyv");
|
|
@@ -148,7 +150,7 @@ var CacheableStats = class {
|
|
|
148
150
|
}
|
|
149
151
|
this._count++;
|
|
150
152
|
}
|
|
151
|
-
|
|
153
|
+
decreaseCount() {
|
|
152
154
|
if (!this._enabled) {
|
|
153
155
|
return;
|
|
154
156
|
}
|
|
@@ -196,6 +198,304 @@ var CacheableStats = class {
|
|
|
196
198
|
this._ksize = 0;
|
|
197
199
|
this._count = 0;
|
|
198
200
|
}
|
|
201
|
+
resetStoreValues() {
|
|
202
|
+
this._vsize = 0;
|
|
203
|
+
this._ksize = 0;
|
|
204
|
+
this._count = 0;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// src/memory-lru.ts
|
|
209
|
+
var ListNode = class {
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/parameter-properties
|
|
211
|
+
value;
|
|
212
|
+
prev = void 0;
|
|
213
|
+
next = void 0;
|
|
214
|
+
constructor(value) {
|
|
215
|
+
this.value = value;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var DoublyLinkedList = class {
|
|
219
|
+
head = void 0;
|
|
220
|
+
tail = void 0;
|
|
221
|
+
nodesMap = /* @__PURE__ */ new Map();
|
|
222
|
+
// Add a new node to the front (most recently used)
|
|
223
|
+
addToFront(value) {
|
|
224
|
+
const newNode = new ListNode(value);
|
|
225
|
+
if (this.head) {
|
|
226
|
+
newNode.next = this.head;
|
|
227
|
+
this.head.prev = newNode;
|
|
228
|
+
this.head = newNode;
|
|
229
|
+
} else {
|
|
230
|
+
this.head = this.tail = newNode;
|
|
231
|
+
}
|
|
232
|
+
this.nodesMap.set(value, newNode);
|
|
233
|
+
}
|
|
234
|
+
// Move an existing node to the front (most recently used)
|
|
235
|
+
moveToFront(value) {
|
|
236
|
+
const node = this.nodesMap.get(value);
|
|
237
|
+
if (!node || this.head === node) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (node.prev) {
|
|
241
|
+
node.prev.next = node.next;
|
|
242
|
+
}
|
|
243
|
+
if (node.next) {
|
|
244
|
+
node.next.prev = node.prev;
|
|
245
|
+
}
|
|
246
|
+
if (node === this.tail) {
|
|
247
|
+
this.tail = node.prev;
|
|
248
|
+
}
|
|
249
|
+
node.prev = void 0;
|
|
250
|
+
node.next = this.head;
|
|
251
|
+
if (this.head) {
|
|
252
|
+
this.head.prev = node;
|
|
253
|
+
}
|
|
254
|
+
this.head = node;
|
|
255
|
+
this.tail ||= node;
|
|
256
|
+
}
|
|
257
|
+
// Get the oldest node (tail)
|
|
258
|
+
getOldest() {
|
|
259
|
+
return this.tail ? this.tail.value : void 0;
|
|
260
|
+
}
|
|
261
|
+
// Remove the oldest node (tail)
|
|
262
|
+
removeOldest() {
|
|
263
|
+
if (!this.tail) {
|
|
264
|
+
return void 0;
|
|
265
|
+
}
|
|
266
|
+
const oldValue = this.tail.value;
|
|
267
|
+
if (this.tail.prev) {
|
|
268
|
+
this.tail = this.tail.prev;
|
|
269
|
+
this.tail.next = void 0;
|
|
270
|
+
} else {
|
|
271
|
+
this.head = this.tail = void 0;
|
|
272
|
+
}
|
|
273
|
+
this.nodesMap.delete(oldValue);
|
|
274
|
+
return oldValue;
|
|
275
|
+
}
|
|
276
|
+
get size() {
|
|
277
|
+
return this.nodesMap.size;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// src/memory.ts
|
|
282
|
+
var CacheableMemory = class {
|
|
283
|
+
_hashCache = /* @__PURE__ */ new Map();
|
|
284
|
+
_hash0 = /* @__PURE__ */ new Map();
|
|
285
|
+
_hash1 = /* @__PURE__ */ new Map();
|
|
286
|
+
_hash2 = /* @__PURE__ */ new Map();
|
|
287
|
+
_hash3 = /* @__PURE__ */ new Map();
|
|
288
|
+
_hash4 = /* @__PURE__ */ new Map();
|
|
289
|
+
_hash5 = /* @__PURE__ */ new Map();
|
|
290
|
+
_hash6 = /* @__PURE__ */ new Map();
|
|
291
|
+
_hash7 = /* @__PURE__ */ new Map();
|
|
292
|
+
_hash8 = /* @__PURE__ */ new Map();
|
|
293
|
+
_hash9 = /* @__PURE__ */ new Map();
|
|
294
|
+
_lru = new DoublyLinkedList();
|
|
295
|
+
_ttl = 0;
|
|
296
|
+
_useClone = true;
|
|
297
|
+
_lruSize = 0;
|
|
298
|
+
constructor(options) {
|
|
299
|
+
if (options?.ttl) {
|
|
300
|
+
this._ttl = options.ttl;
|
|
301
|
+
}
|
|
302
|
+
if (options?.useClone !== void 0) {
|
|
303
|
+
this._useClone = options.useClone;
|
|
304
|
+
}
|
|
305
|
+
if (options?.lruSize) {
|
|
306
|
+
this._lruSize = options.lruSize;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
get ttl() {
|
|
310
|
+
return this._ttl;
|
|
311
|
+
}
|
|
312
|
+
set ttl(value) {
|
|
313
|
+
this._ttl = value;
|
|
314
|
+
}
|
|
315
|
+
get useClone() {
|
|
316
|
+
return this._useClone;
|
|
317
|
+
}
|
|
318
|
+
set useClone(value) {
|
|
319
|
+
this._useClone = value;
|
|
320
|
+
}
|
|
321
|
+
get lruSize() {
|
|
322
|
+
return this._lruSize;
|
|
323
|
+
}
|
|
324
|
+
set lruSize(value) {
|
|
325
|
+
this._lruSize = value;
|
|
326
|
+
this.lruResize();
|
|
327
|
+
}
|
|
328
|
+
get size() {
|
|
329
|
+
return this._hash0.size + this._hash1.size + this._hash2.size + this._hash3.size + this._hash4.size + this._hash5.size + this._hash6.size + this._hash7.size + this._hash8.size + this._hash9.size;
|
|
330
|
+
}
|
|
331
|
+
get keys() {
|
|
332
|
+
return this.concatStores().keys();
|
|
333
|
+
}
|
|
334
|
+
get(key) {
|
|
335
|
+
const store = this.getStore(key);
|
|
336
|
+
const item = store.get(key);
|
|
337
|
+
if (!item) {
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
if (item.expires && item.expires && Date.now() > item.expires) {
|
|
341
|
+
store.delete(key);
|
|
342
|
+
return void 0;
|
|
343
|
+
}
|
|
344
|
+
this.lruMoveToFront(key);
|
|
345
|
+
if (!this._useClone) {
|
|
346
|
+
return item.value;
|
|
347
|
+
}
|
|
348
|
+
return this.clone(item.value);
|
|
349
|
+
}
|
|
350
|
+
set(key, value, ttl) {
|
|
351
|
+
const store = this.getStore(key);
|
|
352
|
+
let expires;
|
|
353
|
+
if (ttl !== void 0 || this._ttl !== 0) {
|
|
354
|
+
expires = Date.now() + (ttl ?? this._ttl);
|
|
355
|
+
}
|
|
356
|
+
if (this._lruSize > 0) {
|
|
357
|
+
if (store.has(key)) {
|
|
358
|
+
this.lruMoveToFront(key);
|
|
359
|
+
} else {
|
|
360
|
+
this.lruAddToFront(key);
|
|
361
|
+
if (this._lru.size > this._lruSize) {
|
|
362
|
+
const oldestKey = this._lru.getOldest();
|
|
363
|
+
if (oldestKey) {
|
|
364
|
+
this._lru.removeOldest();
|
|
365
|
+
this.delete(oldestKey);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
store.set(key, {
|
|
371
|
+
key,
|
|
372
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
373
|
+
value,
|
|
374
|
+
expires
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
has(key) {
|
|
378
|
+
const item = this.get(key);
|
|
379
|
+
return Boolean(item);
|
|
380
|
+
}
|
|
381
|
+
take(key) {
|
|
382
|
+
const item = this.get(key);
|
|
383
|
+
if (!item) {
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
this.delete(key);
|
|
387
|
+
return item;
|
|
388
|
+
}
|
|
389
|
+
delete(key) {
|
|
390
|
+
const store = this.getStore(key);
|
|
391
|
+
store.delete(key);
|
|
392
|
+
}
|
|
393
|
+
clear() {
|
|
394
|
+
this._hash0.clear();
|
|
395
|
+
this._hash1.clear();
|
|
396
|
+
this._hash2.clear();
|
|
397
|
+
this._hash3.clear();
|
|
398
|
+
this._hash4.clear();
|
|
399
|
+
this._hash5.clear();
|
|
400
|
+
this._hash6.clear();
|
|
401
|
+
this._hash7.clear();
|
|
402
|
+
this._hash8.clear();
|
|
403
|
+
this._hash9.clear();
|
|
404
|
+
this._hashCache.clear();
|
|
405
|
+
}
|
|
406
|
+
hashKey(key) {
|
|
407
|
+
const cacheHashNumber = this._hashCache.get(key);
|
|
408
|
+
if (cacheHashNumber) {
|
|
409
|
+
return cacheHashNumber;
|
|
410
|
+
}
|
|
411
|
+
let hash = 0;
|
|
412
|
+
const primeMultiplier = 31;
|
|
413
|
+
for (let i = 0; i < key.length; i++) {
|
|
414
|
+
hash = hash * primeMultiplier + key.charCodeAt(i);
|
|
415
|
+
}
|
|
416
|
+
const result = Math.abs(hash) % 10;
|
|
417
|
+
this._hashCache.set(key, result);
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
getStore(key) {
|
|
421
|
+
const hashKey = this.hashKey(key);
|
|
422
|
+
switch (hashKey) {
|
|
423
|
+
case 1: {
|
|
424
|
+
return this._hash1;
|
|
425
|
+
}
|
|
426
|
+
case 2: {
|
|
427
|
+
return this._hash2;
|
|
428
|
+
}
|
|
429
|
+
case 3: {
|
|
430
|
+
return this._hash3;
|
|
431
|
+
}
|
|
432
|
+
case 4: {
|
|
433
|
+
return this._hash4;
|
|
434
|
+
}
|
|
435
|
+
case 5: {
|
|
436
|
+
return this._hash5;
|
|
437
|
+
}
|
|
438
|
+
case 6: {
|
|
439
|
+
return this._hash6;
|
|
440
|
+
}
|
|
441
|
+
case 7: {
|
|
442
|
+
return this._hash7;
|
|
443
|
+
}
|
|
444
|
+
case 8: {
|
|
445
|
+
return this._hash8;
|
|
446
|
+
}
|
|
447
|
+
case 9: {
|
|
448
|
+
return this._hash9;
|
|
449
|
+
}
|
|
450
|
+
default: {
|
|
451
|
+
return this._hash0;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
clone(value) {
|
|
456
|
+
if (this.isPrimitive(value)) {
|
|
457
|
+
return value;
|
|
458
|
+
}
|
|
459
|
+
return structuredClone(value);
|
|
460
|
+
}
|
|
461
|
+
lruAddToFront(key) {
|
|
462
|
+
if (this._lruSize === 0) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
this._lru.addToFront(key);
|
|
466
|
+
}
|
|
467
|
+
lruMoveToFront(key) {
|
|
468
|
+
if (this._lruSize === 0) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
this._lru.moveToFront(key);
|
|
472
|
+
}
|
|
473
|
+
lruResize() {
|
|
474
|
+
if (this._lruSize === 0) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
while (this._lru.size > this._lruSize) {
|
|
478
|
+
const oldestKey = this._lru.getOldest();
|
|
479
|
+
if (oldestKey) {
|
|
480
|
+
this._lru.removeOldest();
|
|
481
|
+
this.delete(oldestKey);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
isPrimitive(value) {
|
|
486
|
+
const result = false;
|
|
487
|
+
if (value === null || value === void 0) {
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
concatStores() {
|
|
496
|
+
const result = new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
199
499
|
};
|
|
200
500
|
|
|
201
501
|
// src/index.ts
|
|
@@ -215,7 +515,7 @@ var CacheableEvents = /* @__PURE__ */ ((CacheableEvents2) => {
|
|
|
215
515
|
return CacheableEvents2;
|
|
216
516
|
})(CacheableEvents || {});
|
|
217
517
|
var Cacheable = class extends import_hookified.Hookified {
|
|
218
|
-
_primary = new import_keyv.Keyv();
|
|
518
|
+
_primary = new import_keyv.Keyv({ store: new CacheableMemory() });
|
|
219
519
|
_secondary;
|
|
220
520
|
_nonBlocking = false;
|
|
221
521
|
_stats = new CacheableStats({ enabled: false });
|
|
@@ -276,6 +576,14 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
276
576
|
} catch (error) {
|
|
277
577
|
await this.emit("error" /* ERROR */, error);
|
|
278
578
|
}
|
|
579
|
+
if (this.stats.enabled) {
|
|
580
|
+
if (result) {
|
|
581
|
+
this._stats.incrementHits();
|
|
582
|
+
} else {
|
|
583
|
+
this._stats.incrementMisses();
|
|
584
|
+
}
|
|
585
|
+
this.stats.incrementGets();
|
|
586
|
+
}
|
|
279
587
|
return result;
|
|
280
588
|
}
|
|
281
589
|
async getMany(keys) {
|
|
@@ -302,6 +610,16 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
302
610
|
} catch (error) {
|
|
303
611
|
await this.emit("error" /* ERROR */, error);
|
|
304
612
|
}
|
|
613
|
+
if (this.stats.enabled) {
|
|
614
|
+
for (const item of result) {
|
|
615
|
+
if (item) {
|
|
616
|
+
this._stats.incrementHits();
|
|
617
|
+
} else {
|
|
618
|
+
this._stats.incrementMisses();
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
this.stats.incrementGets();
|
|
622
|
+
}
|
|
305
623
|
return result;
|
|
306
624
|
}
|
|
307
625
|
async set(key, value, ttl) {
|
|
@@ -323,6 +641,12 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
323
641
|
} catch (error) {
|
|
324
642
|
await this.emit("error" /* ERROR */, error);
|
|
325
643
|
}
|
|
644
|
+
if (this.stats.enabled) {
|
|
645
|
+
this.stats.incrementKSize(key);
|
|
646
|
+
this.stats.incrementCount();
|
|
647
|
+
this.stats.incrementVSize(value);
|
|
648
|
+
this.stats.incrementSets();
|
|
649
|
+
}
|
|
326
650
|
return result;
|
|
327
651
|
}
|
|
328
652
|
async setMany(items) {
|
|
@@ -341,6 +665,13 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
341
665
|
} catch (error) {
|
|
342
666
|
await this.emit("error" /* ERROR */, error);
|
|
343
667
|
}
|
|
668
|
+
if (this.stats.enabled) {
|
|
669
|
+
for (const item of items) {
|
|
670
|
+
this.stats.incrementKSize(item.key);
|
|
671
|
+
this.stats.incrementCount();
|
|
672
|
+
this.stats.incrementVSize(item.value);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
344
675
|
return result;
|
|
345
676
|
}
|
|
346
677
|
async take(key) {
|
|
@@ -354,11 +685,18 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
354
685
|
return result;
|
|
355
686
|
}
|
|
356
687
|
async has(key) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
688
|
+
const promises = [];
|
|
689
|
+
promises.push(this._primary.has(key));
|
|
690
|
+
if (this._secondary) {
|
|
691
|
+
promises.push(this._secondary.has(key));
|
|
360
692
|
}
|
|
361
|
-
|
|
693
|
+
const resultAll = await Promise.all(promises);
|
|
694
|
+
for (const result of resultAll) {
|
|
695
|
+
if (result) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return false;
|
|
362
700
|
}
|
|
363
701
|
async hasMany(keys) {
|
|
364
702
|
const result = await this.hasManyKeyv(this._primary, keys);
|
|
@@ -379,17 +717,39 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
379
717
|
return result;
|
|
380
718
|
}
|
|
381
719
|
async delete(key) {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
720
|
+
let result = false;
|
|
721
|
+
const promises = [];
|
|
722
|
+
if (this.stats.enabled) {
|
|
723
|
+
const statResult = await this._primary.get(key);
|
|
724
|
+
if (statResult) {
|
|
725
|
+
this.stats.decreaseKSize(key);
|
|
726
|
+
this.stats.decreaseVSize(statResult);
|
|
727
|
+
this.stats.decreaseCount();
|
|
728
|
+
this.stats.incrementDeletes();
|
|
388
729
|
}
|
|
389
730
|
}
|
|
731
|
+
promises.push(this._primary.delete(key));
|
|
732
|
+
if (this._secondary) {
|
|
733
|
+
promises.push(this._secondary.delete(key));
|
|
734
|
+
}
|
|
735
|
+
if (this.nonBlocking) {
|
|
736
|
+
result = await Promise.race(promises);
|
|
737
|
+
} else {
|
|
738
|
+
const resultAll = await Promise.all(promises);
|
|
739
|
+
result = resultAll[0];
|
|
740
|
+
}
|
|
390
741
|
return result;
|
|
391
742
|
}
|
|
392
743
|
async deleteMany(keys) {
|
|
744
|
+
if (this.stats.enabled) {
|
|
745
|
+
const statResult = await this._primary.get(keys);
|
|
746
|
+
for (const key of keys) {
|
|
747
|
+
this.stats.decreaseKSize(key);
|
|
748
|
+
this.stats.decreaseVSize(statResult);
|
|
749
|
+
this.stats.decreaseCount();
|
|
750
|
+
this.stats.incrementDeletes();
|
|
751
|
+
}
|
|
752
|
+
}
|
|
393
753
|
const result = await this.deleteManyKeyv(this._primary, keys);
|
|
394
754
|
if (this._secondary) {
|
|
395
755
|
if (this._nonBlocking) {
|
|
@@ -407,6 +767,10 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
407
767
|
promises.push(this._secondary.clear());
|
|
408
768
|
}
|
|
409
769
|
await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
|
|
770
|
+
if (this.stats.enabled) {
|
|
771
|
+
this._stats.resetStoreValues();
|
|
772
|
+
this._stats.incrementClears();
|
|
773
|
+
}
|
|
410
774
|
}
|
|
411
775
|
async disconnect() {
|
|
412
776
|
const promises = [];
|
|
@@ -444,5 +808,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
444
808
|
0 && (module.exports = {
|
|
445
809
|
Cacheable,
|
|
446
810
|
CacheableEvents,
|
|
447
|
-
CacheableHooks
|
|
811
|
+
CacheableHooks,
|
|
812
|
+
CacheableMemory,
|
|
813
|
+
CacheableStats
|
|
448
814
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -38,11 +38,58 @@ declare class CacheableStats {
|
|
|
38
38
|
incrementKSize(key: string): void;
|
|
39
39
|
decreaseKSize(key: string): void;
|
|
40
40
|
incrementCount(): void;
|
|
41
|
-
|
|
41
|
+
decreaseCount(): void;
|
|
42
42
|
setCount(count: number): void;
|
|
43
43
|
roughSizeOfString(value: string): number;
|
|
44
44
|
roughSizeOfObject(object: any): number;
|
|
45
45
|
reset(): void;
|
|
46
|
+
resetStoreValues(): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type CacheableMemoryOptions = {
|
|
50
|
+
ttl?: number;
|
|
51
|
+
useClone?: boolean;
|
|
52
|
+
lruSize?: number;
|
|
53
|
+
};
|
|
54
|
+
declare class CacheableMemory {
|
|
55
|
+
private readonly _hashCache;
|
|
56
|
+
private readonly _hash0;
|
|
57
|
+
private readonly _hash1;
|
|
58
|
+
private readonly _hash2;
|
|
59
|
+
private readonly _hash3;
|
|
60
|
+
private readonly _hash4;
|
|
61
|
+
private readonly _hash5;
|
|
62
|
+
private readonly _hash6;
|
|
63
|
+
private readonly _hash7;
|
|
64
|
+
private readonly _hash8;
|
|
65
|
+
private readonly _hash9;
|
|
66
|
+
private readonly _lru;
|
|
67
|
+
private _ttl;
|
|
68
|
+
private _useClone;
|
|
69
|
+
private _lruSize;
|
|
70
|
+
constructor(options?: CacheableMemoryOptions);
|
|
71
|
+
get ttl(): number;
|
|
72
|
+
set ttl(value: number);
|
|
73
|
+
get useClone(): boolean;
|
|
74
|
+
set useClone(value: boolean);
|
|
75
|
+
get lruSize(): number;
|
|
76
|
+
set lruSize(value: number);
|
|
77
|
+
get size(): number;
|
|
78
|
+
get keys(): IterableIterator<string>;
|
|
79
|
+
get<T>(key: string): any;
|
|
80
|
+
set(key: string, value: any, ttl?: number): void;
|
|
81
|
+
has(key: string): boolean;
|
|
82
|
+
take<T>(key: string): any;
|
|
83
|
+
delete(key: string): void;
|
|
84
|
+
clear(): void;
|
|
85
|
+
hashKey(key: string): number;
|
|
86
|
+
getStore(key: string): Map<string, any>;
|
|
87
|
+
clone(value: any): any;
|
|
88
|
+
lruAddToFront(key: string): void;
|
|
89
|
+
lruMoveToFront(key: string): void;
|
|
90
|
+
lruResize(): void;
|
|
91
|
+
private isPrimitive;
|
|
92
|
+
private concatStores;
|
|
46
93
|
}
|
|
47
94
|
|
|
48
95
|
declare enum CacheableHooks {
|
|
@@ -101,4 +148,4 @@ declare class Cacheable extends Hookified {
|
|
|
101
148
|
private hasManyKeyv;
|
|
102
149
|
}
|
|
103
150
|
|
|
104
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, type CacheableOptions };
|
|
151
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats };
|
package/dist/index.d.ts
CHANGED
|
@@ -38,11 +38,58 @@ declare class CacheableStats {
|
|
|
38
38
|
incrementKSize(key: string): void;
|
|
39
39
|
decreaseKSize(key: string): void;
|
|
40
40
|
incrementCount(): void;
|
|
41
|
-
|
|
41
|
+
decreaseCount(): void;
|
|
42
42
|
setCount(count: number): void;
|
|
43
43
|
roughSizeOfString(value: string): number;
|
|
44
44
|
roughSizeOfObject(object: any): number;
|
|
45
45
|
reset(): void;
|
|
46
|
+
resetStoreValues(): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type CacheableMemoryOptions = {
|
|
50
|
+
ttl?: number;
|
|
51
|
+
useClone?: boolean;
|
|
52
|
+
lruSize?: number;
|
|
53
|
+
};
|
|
54
|
+
declare class CacheableMemory {
|
|
55
|
+
private readonly _hashCache;
|
|
56
|
+
private readonly _hash0;
|
|
57
|
+
private readonly _hash1;
|
|
58
|
+
private readonly _hash2;
|
|
59
|
+
private readonly _hash3;
|
|
60
|
+
private readonly _hash4;
|
|
61
|
+
private readonly _hash5;
|
|
62
|
+
private readonly _hash6;
|
|
63
|
+
private readonly _hash7;
|
|
64
|
+
private readonly _hash8;
|
|
65
|
+
private readonly _hash9;
|
|
66
|
+
private readonly _lru;
|
|
67
|
+
private _ttl;
|
|
68
|
+
private _useClone;
|
|
69
|
+
private _lruSize;
|
|
70
|
+
constructor(options?: CacheableMemoryOptions);
|
|
71
|
+
get ttl(): number;
|
|
72
|
+
set ttl(value: number);
|
|
73
|
+
get useClone(): boolean;
|
|
74
|
+
set useClone(value: boolean);
|
|
75
|
+
get lruSize(): number;
|
|
76
|
+
set lruSize(value: number);
|
|
77
|
+
get size(): number;
|
|
78
|
+
get keys(): IterableIterator<string>;
|
|
79
|
+
get<T>(key: string): any;
|
|
80
|
+
set(key: string, value: any, ttl?: number): void;
|
|
81
|
+
has(key: string): boolean;
|
|
82
|
+
take<T>(key: string): any;
|
|
83
|
+
delete(key: string): void;
|
|
84
|
+
clear(): void;
|
|
85
|
+
hashKey(key: string): number;
|
|
86
|
+
getStore(key: string): Map<string, any>;
|
|
87
|
+
clone(value: any): any;
|
|
88
|
+
lruAddToFront(key: string): void;
|
|
89
|
+
lruMoveToFront(key: string): void;
|
|
90
|
+
lruResize(): void;
|
|
91
|
+
private isPrimitive;
|
|
92
|
+
private concatStores;
|
|
46
93
|
}
|
|
47
94
|
|
|
48
95
|
declare enum CacheableHooks {
|
|
@@ -101,4 +148,4 @@ declare class Cacheable extends Hookified {
|
|
|
101
148
|
private hasManyKeyv;
|
|
102
149
|
}
|
|
103
150
|
|
|
104
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, type CacheableOptions };
|
|
151
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats };
|
package/dist/index.js
CHANGED
|
@@ -122,7 +122,7 @@ var CacheableStats = class {
|
|
|
122
122
|
}
|
|
123
123
|
this._count++;
|
|
124
124
|
}
|
|
125
|
-
|
|
125
|
+
decreaseCount() {
|
|
126
126
|
if (!this._enabled) {
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
@@ -170,6 +170,304 @@ var CacheableStats = class {
|
|
|
170
170
|
this._ksize = 0;
|
|
171
171
|
this._count = 0;
|
|
172
172
|
}
|
|
173
|
+
resetStoreValues() {
|
|
174
|
+
this._vsize = 0;
|
|
175
|
+
this._ksize = 0;
|
|
176
|
+
this._count = 0;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// src/memory-lru.ts
|
|
181
|
+
var ListNode = class {
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/parameter-properties
|
|
183
|
+
value;
|
|
184
|
+
prev = void 0;
|
|
185
|
+
next = void 0;
|
|
186
|
+
constructor(value) {
|
|
187
|
+
this.value = value;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var DoublyLinkedList = class {
|
|
191
|
+
head = void 0;
|
|
192
|
+
tail = void 0;
|
|
193
|
+
nodesMap = /* @__PURE__ */ new Map();
|
|
194
|
+
// Add a new node to the front (most recently used)
|
|
195
|
+
addToFront(value) {
|
|
196
|
+
const newNode = new ListNode(value);
|
|
197
|
+
if (this.head) {
|
|
198
|
+
newNode.next = this.head;
|
|
199
|
+
this.head.prev = newNode;
|
|
200
|
+
this.head = newNode;
|
|
201
|
+
} else {
|
|
202
|
+
this.head = this.tail = newNode;
|
|
203
|
+
}
|
|
204
|
+
this.nodesMap.set(value, newNode);
|
|
205
|
+
}
|
|
206
|
+
// Move an existing node to the front (most recently used)
|
|
207
|
+
moveToFront(value) {
|
|
208
|
+
const node = this.nodesMap.get(value);
|
|
209
|
+
if (!node || this.head === node) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (node.prev) {
|
|
213
|
+
node.prev.next = node.next;
|
|
214
|
+
}
|
|
215
|
+
if (node.next) {
|
|
216
|
+
node.next.prev = node.prev;
|
|
217
|
+
}
|
|
218
|
+
if (node === this.tail) {
|
|
219
|
+
this.tail = node.prev;
|
|
220
|
+
}
|
|
221
|
+
node.prev = void 0;
|
|
222
|
+
node.next = this.head;
|
|
223
|
+
if (this.head) {
|
|
224
|
+
this.head.prev = node;
|
|
225
|
+
}
|
|
226
|
+
this.head = node;
|
|
227
|
+
this.tail ||= node;
|
|
228
|
+
}
|
|
229
|
+
// Get the oldest node (tail)
|
|
230
|
+
getOldest() {
|
|
231
|
+
return this.tail ? this.tail.value : void 0;
|
|
232
|
+
}
|
|
233
|
+
// Remove the oldest node (tail)
|
|
234
|
+
removeOldest() {
|
|
235
|
+
if (!this.tail) {
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
const oldValue = this.tail.value;
|
|
239
|
+
if (this.tail.prev) {
|
|
240
|
+
this.tail = this.tail.prev;
|
|
241
|
+
this.tail.next = void 0;
|
|
242
|
+
} else {
|
|
243
|
+
this.head = this.tail = void 0;
|
|
244
|
+
}
|
|
245
|
+
this.nodesMap.delete(oldValue);
|
|
246
|
+
return oldValue;
|
|
247
|
+
}
|
|
248
|
+
get size() {
|
|
249
|
+
return this.nodesMap.size;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/memory.ts
|
|
254
|
+
var CacheableMemory = class {
|
|
255
|
+
_hashCache = /* @__PURE__ */ new Map();
|
|
256
|
+
_hash0 = /* @__PURE__ */ new Map();
|
|
257
|
+
_hash1 = /* @__PURE__ */ new Map();
|
|
258
|
+
_hash2 = /* @__PURE__ */ new Map();
|
|
259
|
+
_hash3 = /* @__PURE__ */ new Map();
|
|
260
|
+
_hash4 = /* @__PURE__ */ new Map();
|
|
261
|
+
_hash5 = /* @__PURE__ */ new Map();
|
|
262
|
+
_hash6 = /* @__PURE__ */ new Map();
|
|
263
|
+
_hash7 = /* @__PURE__ */ new Map();
|
|
264
|
+
_hash8 = /* @__PURE__ */ new Map();
|
|
265
|
+
_hash9 = /* @__PURE__ */ new Map();
|
|
266
|
+
_lru = new DoublyLinkedList();
|
|
267
|
+
_ttl = 0;
|
|
268
|
+
_useClone = true;
|
|
269
|
+
_lruSize = 0;
|
|
270
|
+
constructor(options) {
|
|
271
|
+
if (options?.ttl) {
|
|
272
|
+
this._ttl = options.ttl;
|
|
273
|
+
}
|
|
274
|
+
if (options?.useClone !== void 0) {
|
|
275
|
+
this._useClone = options.useClone;
|
|
276
|
+
}
|
|
277
|
+
if (options?.lruSize) {
|
|
278
|
+
this._lruSize = options.lruSize;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
get ttl() {
|
|
282
|
+
return this._ttl;
|
|
283
|
+
}
|
|
284
|
+
set ttl(value) {
|
|
285
|
+
this._ttl = value;
|
|
286
|
+
}
|
|
287
|
+
get useClone() {
|
|
288
|
+
return this._useClone;
|
|
289
|
+
}
|
|
290
|
+
set useClone(value) {
|
|
291
|
+
this._useClone = value;
|
|
292
|
+
}
|
|
293
|
+
get lruSize() {
|
|
294
|
+
return this._lruSize;
|
|
295
|
+
}
|
|
296
|
+
set lruSize(value) {
|
|
297
|
+
this._lruSize = value;
|
|
298
|
+
this.lruResize();
|
|
299
|
+
}
|
|
300
|
+
get size() {
|
|
301
|
+
return this._hash0.size + this._hash1.size + this._hash2.size + this._hash3.size + this._hash4.size + this._hash5.size + this._hash6.size + this._hash7.size + this._hash8.size + this._hash9.size;
|
|
302
|
+
}
|
|
303
|
+
get keys() {
|
|
304
|
+
return this.concatStores().keys();
|
|
305
|
+
}
|
|
306
|
+
get(key) {
|
|
307
|
+
const store = this.getStore(key);
|
|
308
|
+
const item = store.get(key);
|
|
309
|
+
if (!item) {
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
312
|
+
if (item.expires && item.expires && Date.now() > item.expires) {
|
|
313
|
+
store.delete(key);
|
|
314
|
+
return void 0;
|
|
315
|
+
}
|
|
316
|
+
this.lruMoveToFront(key);
|
|
317
|
+
if (!this._useClone) {
|
|
318
|
+
return item.value;
|
|
319
|
+
}
|
|
320
|
+
return this.clone(item.value);
|
|
321
|
+
}
|
|
322
|
+
set(key, value, ttl) {
|
|
323
|
+
const store = this.getStore(key);
|
|
324
|
+
let expires;
|
|
325
|
+
if (ttl !== void 0 || this._ttl !== 0) {
|
|
326
|
+
expires = Date.now() + (ttl ?? this._ttl);
|
|
327
|
+
}
|
|
328
|
+
if (this._lruSize > 0) {
|
|
329
|
+
if (store.has(key)) {
|
|
330
|
+
this.lruMoveToFront(key);
|
|
331
|
+
} else {
|
|
332
|
+
this.lruAddToFront(key);
|
|
333
|
+
if (this._lru.size > this._lruSize) {
|
|
334
|
+
const oldestKey = this._lru.getOldest();
|
|
335
|
+
if (oldestKey) {
|
|
336
|
+
this._lru.removeOldest();
|
|
337
|
+
this.delete(oldestKey);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
store.set(key, {
|
|
343
|
+
key,
|
|
344
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
345
|
+
value,
|
|
346
|
+
expires
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
has(key) {
|
|
350
|
+
const item = this.get(key);
|
|
351
|
+
return Boolean(item);
|
|
352
|
+
}
|
|
353
|
+
take(key) {
|
|
354
|
+
const item = this.get(key);
|
|
355
|
+
if (!item) {
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
this.delete(key);
|
|
359
|
+
return item;
|
|
360
|
+
}
|
|
361
|
+
delete(key) {
|
|
362
|
+
const store = this.getStore(key);
|
|
363
|
+
store.delete(key);
|
|
364
|
+
}
|
|
365
|
+
clear() {
|
|
366
|
+
this._hash0.clear();
|
|
367
|
+
this._hash1.clear();
|
|
368
|
+
this._hash2.clear();
|
|
369
|
+
this._hash3.clear();
|
|
370
|
+
this._hash4.clear();
|
|
371
|
+
this._hash5.clear();
|
|
372
|
+
this._hash6.clear();
|
|
373
|
+
this._hash7.clear();
|
|
374
|
+
this._hash8.clear();
|
|
375
|
+
this._hash9.clear();
|
|
376
|
+
this._hashCache.clear();
|
|
377
|
+
}
|
|
378
|
+
hashKey(key) {
|
|
379
|
+
const cacheHashNumber = this._hashCache.get(key);
|
|
380
|
+
if (cacheHashNumber) {
|
|
381
|
+
return cacheHashNumber;
|
|
382
|
+
}
|
|
383
|
+
let hash = 0;
|
|
384
|
+
const primeMultiplier = 31;
|
|
385
|
+
for (let i = 0; i < key.length; i++) {
|
|
386
|
+
hash = hash * primeMultiplier + key.charCodeAt(i);
|
|
387
|
+
}
|
|
388
|
+
const result = Math.abs(hash) % 10;
|
|
389
|
+
this._hashCache.set(key, result);
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
getStore(key) {
|
|
393
|
+
const hashKey = this.hashKey(key);
|
|
394
|
+
switch (hashKey) {
|
|
395
|
+
case 1: {
|
|
396
|
+
return this._hash1;
|
|
397
|
+
}
|
|
398
|
+
case 2: {
|
|
399
|
+
return this._hash2;
|
|
400
|
+
}
|
|
401
|
+
case 3: {
|
|
402
|
+
return this._hash3;
|
|
403
|
+
}
|
|
404
|
+
case 4: {
|
|
405
|
+
return this._hash4;
|
|
406
|
+
}
|
|
407
|
+
case 5: {
|
|
408
|
+
return this._hash5;
|
|
409
|
+
}
|
|
410
|
+
case 6: {
|
|
411
|
+
return this._hash6;
|
|
412
|
+
}
|
|
413
|
+
case 7: {
|
|
414
|
+
return this._hash7;
|
|
415
|
+
}
|
|
416
|
+
case 8: {
|
|
417
|
+
return this._hash8;
|
|
418
|
+
}
|
|
419
|
+
case 9: {
|
|
420
|
+
return this._hash9;
|
|
421
|
+
}
|
|
422
|
+
default: {
|
|
423
|
+
return this._hash0;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
clone(value) {
|
|
428
|
+
if (this.isPrimitive(value)) {
|
|
429
|
+
return value;
|
|
430
|
+
}
|
|
431
|
+
return structuredClone(value);
|
|
432
|
+
}
|
|
433
|
+
lruAddToFront(key) {
|
|
434
|
+
if (this._lruSize === 0) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
this._lru.addToFront(key);
|
|
438
|
+
}
|
|
439
|
+
lruMoveToFront(key) {
|
|
440
|
+
if (this._lruSize === 0) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
this._lru.moveToFront(key);
|
|
444
|
+
}
|
|
445
|
+
lruResize() {
|
|
446
|
+
if (this._lruSize === 0) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
while (this._lru.size > this._lruSize) {
|
|
450
|
+
const oldestKey = this._lru.getOldest();
|
|
451
|
+
if (oldestKey) {
|
|
452
|
+
this._lru.removeOldest();
|
|
453
|
+
this.delete(oldestKey);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
isPrimitive(value) {
|
|
458
|
+
const result = false;
|
|
459
|
+
if (value === null || value === void 0) {
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
return result;
|
|
466
|
+
}
|
|
467
|
+
concatStores() {
|
|
468
|
+
const result = new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
173
471
|
};
|
|
174
472
|
|
|
175
473
|
// src/index.ts
|
|
@@ -189,7 +487,7 @@ var CacheableEvents = /* @__PURE__ */ ((CacheableEvents2) => {
|
|
|
189
487
|
return CacheableEvents2;
|
|
190
488
|
})(CacheableEvents || {});
|
|
191
489
|
var Cacheable = class extends Hookified {
|
|
192
|
-
_primary = new Keyv();
|
|
490
|
+
_primary = new Keyv({ store: new CacheableMemory() });
|
|
193
491
|
_secondary;
|
|
194
492
|
_nonBlocking = false;
|
|
195
493
|
_stats = new CacheableStats({ enabled: false });
|
|
@@ -250,6 +548,14 @@ var Cacheable = class extends Hookified {
|
|
|
250
548
|
} catch (error) {
|
|
251
549
|
await this.emit("error" /* ERROR */, error);
|
|
252
550
|
}
|
|
551
|
+
if (this.stats.enabled) {
|
|
552
|
+
if (result) {
|
|
553
|
+
this._stats.incrementHits();
|
|
554
|
+
} else {
|
|
555
|
+
this._stats.incrementMisses();
|
|
556
|
+
}
|
|
557
|
+
this.stats.incrementGets();
|
|
558
|
+
}
|
|
253
559
|
return result;
|
|
254
560
|
}
|
|
255
561
|
async getMany(keys) {
|
|
@@ -276,6 +582,16 @@ var Cacheable = class extends Hookified {
|
|
|
276
582
|
} catch (error) {
|
|
277
583
|
await this.emit("error" /* ERROR */, error);
|
|
278
584
|
}
|
|
585
|
+
if (this.stats.enabled) {
|
|
586
|
+
for (const item of result) {
|
|
587
|
+
if (item) {
|
|
588
|
+
this._stats.incrementHits();
|
|
589
|
+
} else {
|
|
590
|
+
this._stats.incrementMisses();
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
this.stats.incrementGets();
|
|
594
|
+
}
|
|
279
595
|
return result;
|
|
280
596
|
}
|
|
281
597
|
async set(key, value, ttl) {
|
|
@@ -297,6 +613,12 @@ var Cacheable = class extends Hookified {
|
|
|
297
613
|
} catch (error) {
|
|
298
614
|
await this.emit("error" /* ERROR */, error);
|
|
299
615
|
}
|
|
616
|
+
if (this.stats.enabled) {
|
|
617
|
+
this.stats.incrementKSize(key);
|
|
618
|
+
this.stats.incrementCount();
|
|
619
|
+
this.stats.incrementVSize(value);
|
|
620
|
+
this.stats.incrementSets();
|
|
621
|
+
}
|
|
300
622
|
return result;
|
|
301
623
|
}
|
|
302
624
|
async setMany(items) {
|
|
@@ -315,6 +637,13 @@ var Cacheable = class extends Hookified {
|
|
|
315
637
|
} catch (error) {
|
|
316
638
|
await this.emit("error" /* ERROR */, error);
|
|
317
639
|
}
|
|
640
|
+
if (this.stats.enabled) {
|
|
641
|
+
for (const item of items) {
|
|
642
|
+
this.stats.incrementKSize(item.key);
|
|
643
|
+
this.stats.incrementCount();
|
|
644
|
+
this.stats.incrementVSize(item.value);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
318
647
|
return result;
|
|
319
648
|
}
|
|
320
649
|
async take(key) {
|
|
@@ -328,11 +657,18 @@ var Cacheable = class extends Hookified {
|
|
|
328
657
|
return result;
|
|
329
658
|
}
|
|
330
659
|
async has(key) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
660
|
+
const promises = [];
|
|
661
|
+
promises.push(this._primary.has(key));
|
|
662
|
+
if (this._secondary) {
|
|
663
|
+
promises.push(this._secondary.has(key));
|
|
334
664
|
}
|
|
335
|
-
|
|
665
|
+
const resultAll = await Promise.all(promises);
|
|
666
|
+
for (const result of resultAll) {
|
|
667
|
+
if (result) {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return false;
|
|
336
672
|
}
|
|
337
673
|
async hasMany(keys) {
|
|
338
674
|
const result = await this.hasManyKeyv(this._primary, keys);
|
|
@@ -353,17 +689,39 @@ var Cacheable = class extends Hookified {
|
|
|
353
689
|
return result;
|
|
354
690
|
}
|
|
355
691
|
async delete(key) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
692
|
+
let result = false;
|
|
693
|
+
const promises = [];
|
|
694
|
+
if (this.stats.enabled) {
|
|
695
|
+
const statResult = await this._primary.get(key);
|
|
696
|
+
if (statResult) {
|
|
697
|
+
this.stats.decreaseKSize(key);
|
|
698
|
+
this.stats.decreaseVSize(statResult);
|
|
699
|
+
this.stats.decreaseCount();
|
|
700
|
+
this.stats.incrementDeletes();
|
|
362
701
|
}
|
|
363
702
|
}
|
|
703
|
+
promises.push(this._primary.delete(key));
|
|
704
|
+
if (this._secondary) {
|
|
705
|
+
promises.push(this._secondary.delete(key));
|
|
706
|
+
}
|
|
707
|
+
if (this.nonBlocking) {
|
|
708
|
+
result = await Promise.race(promises);
|
|
709
|
+
} else {
|
|
710
|
+
const resultAll = await Promise.all(promises);
|
|
711
|
+
result = resultAll[0];
|
|
712
|
+
}
|
|
364
713
|
return result;
|
|
365
714
|
}
|
|
366
715
|
async deleteMany(keys) {
|
|
716
|
+
if (this.stats.enabled) {
|
|
717
|
+
const statResult = await this._primary.get(keys);
|
|
718
|
+
for (const key of keys) {
|
|
719
|
+
this.stats.decreaseKSize(key);
|
|
720
|
+
this.stats.decreaseVSize(statResult);
|
|
721
|
+
this.stats.decreaseCount();
|
|
722
|
+
this.stats.incrementDeletes();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
367
725
|
const result = await this.deleteManyKeyv(this._primary, keys);
|
|
368
726
|
if (this._secondary) {
|
|
369
727
|
if (this._nonBlocking) {
|
|
@@ -381,6 +739,10 @@ var Cacheable = class extends Hookified {
|
|
|
381
739
|
promises.push(this._secondary.clear());
|
|
382
740
|
}
|
|
383
741
|
await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
|
|
742
|
+
if (this.stats.enabled) {
|
|
743
|
+
this._stats.resetStoreValues();
|
|
744
|
+
this._stats.incrementClears();
|
|
745
|
+
}
|
|
384
746
|
}
|
|
385
747
|
async disconnect() {
|
|
386
748
|
const promises = [];
|
|
@@ -417,5 +779,7 @@ var Cacheable = class extends Hookified {
|
|
|
417
779
|
export {
|
|
418
780
|
Cacheable,
|
|
419
781
|
CacheableEvents,
|
|
420
|
-
CacheableHooks
|
|
782
|
+
CacheableHooks,
|
|
783
|
+
CacheableMemory,
|
|
784
|
+
CacheableStats
|
|
421
785
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cacheable",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Simple Caching Engine using Keyv",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@keyv/redis": "^3.0.1",
|
|
21
21
|
"@vitest/coverage-v8": "^2.1.1",
|
|
22
|
-
"lru-cache": "^
|
|
22
|
+
"lru-cache": "^11.0.1",
|
|
23
23
|
"rimraf": "^6.0.1",
|
|
24
24
|
"ts-node": "^10.9.2",
|
|
25
|
-
"tsup": "^8.
|
|
26
|
-
"typescript": "^5.
|
|
25
|
+
"tsup": "^8.3.0",
|
|
26
|
+
"typescript": "^5.6.2",
|
|
27
27
|
"vitest": "^2.1.1",
|
|
28
28
|
"xo": "^0.59.3"
|
|
29
29
|
},
|