cachimbo 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -40,6 +40,67 @@ var BaseCache = class {
40
40
  }
41
41
  };
42
42
 
43
+ //#endregion
44
+ //#region src/base/local.ts
45
+ var BaseLocalCache = class extends BaseCache {
46
+ disposeListeners = [];
47
+ /**
48
+ * Reads cached resources by their keys. (synchronous version)
49
+ * @protected
50
+ */
51
+ _getMany(keys) {
52
+ return Object.fromEntries(keys.map((key) => [key, this._get(key)]));
53
+ }
54
+ /**
55
+ * Writes resources into cache. (synchronous version)
56
+ * @protected
57
+ */
58
+ _setMany(data, options) {
59
+ for (const [key, value] of Object.entries(data)) this._set(key, value, options);
60
+ }
61
+ /**
62
+ * Deletes many cached resources by their keys. (synchronous version)
63
+ * @protected
64
+ */
65
+ _deleteMany(keys) {
66
+ for (const key of keys) this._delete(key);
67
+ }
68
+ /**
69
+ * Adds a listener that will be called when a cached item is disposed.
70
+ *
71
+ * @param listener The listener function to add.
72
+ * @protected
73
+ */
74
+ _addDisposeListener(listener) {
75
+ this.disposeListeners.push(listener);
76
+ }
77
+ get(key) {
78
+ return Promise.resolve(this._get(key));
79
+ }
80
+ set(key, value, options) {
81
+ this._set(key, value, options);
82
+ return Promise.resolve();
83
+ }
84
+ delete(key) {
85
+ this._delete(key);
86
+ return Promise.resolve();
87
+ }
88
+ getMany(keys) {
89
+ return Promise.resolve(this._getMany(keys));
90
+ }
91
+ setMany(data, options) {
92
+ this._setMany(data, options);
93
+ return Promise.resolve();
94
+ }
95
+ deleteMany(keys) {
96
+ this._deleteMany(keys);
97
+ return Promise.resolve();
98
+ }
99
+ onDispose(key, value, reason) {
100
+ for (const listener of this.disposeListeners) listener(key, value, reason);
101
+ }
102
+ };
103
+
43
104
  //#endregion
44
105
  //#region src/local/lru/index.ts
45
106
  /**
@@ -49,7 +110,7 @@ var BaseCache = class {
49
110
  *
50
111
  * Once the limit of items is reached, the least recently used items will be purged.
51
112
  */
52
- var LocalLRUCache = class extends BaseCache {
113
+ var LocalLRUCache = class extends BaseLocalCache {
53
114
  cache;
54
115
  shouldUseFetch;
55
116
  constructor(options = {}) {
@@ -62,16 +123,29 @@ var LocalLRUCache = class extends BaseCache {
62
123
  ttl: options.ttl ? options.ttl * 1e3 : void 0,
63
124
  max: options.max || 1e4,
64
125
  ttlAutopurge: false,
65
- fetchMethod: (_key, _staleValue, options$1) => options$1.context()
126
+ fetchMethod: (_key, _staleValue, options$1) => options$1.context(),
127
+ disposeAfter: (value, key, reason) => this.onDispose(key, value, reason)
66
128
  });
67
129
  this.shouldUseFetch = true;
68
130
  }
69
131
  }
70
- async get(key) {
132
+ /** @internal */
133
+ _get(key) {
71
134
  this.logger?.debug(this.name, "[get]", "key =", key);
72
135
  const data = this.cache.get(key);
73
136
  return data === void 0 ? null : data;
74
137
  }
138
+ /** @internal */
139
+ _set(key, value, options) {
140
+ this.logger?.debug(this.name, "[set]", "key =", key);
141
+ const ttl = options?.ttl;
142
+ this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
143
+ }
144
+ /** @internal */
145
+ _delete(key) {
146
+ this.logger?.debug(this.name, "[delete]", "key =", key);
147
+ this.cache.delete(key);
148
+ }
75
149
  getOrLoad(key, load, options) {
76
150
  if (!this.shouldUseFetch) return super.getOrLoad(key, load, options);
77
151
  this.logger?.debug(this.name, "[getOrLoad] Running LRUCache's fetch...", "key =", key);
@@ -81,15 +155,6 @@ var LocalLRUCache = class extends BaseCache {
81
155
  ttl: ttl ? ttl * 1e3 : void 0
82
156
  });
83
157
  }
84
- async set(key, value, options) {
85
- this.logger?.debug(this.name, "[set]", "key =", key);
86
- const ttl = options?.ttl;
87
- this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
88
- }
89
- async delete(key) {
90
- this.logger?.debug(this.name, "[delete]", "key =", key);
91
- this.cache.delete(key);
92
- }
93
158
  };
94
159
 
95
160
  //#endregion
@@ -99,27 +164,31 @@ var LocalLRUCache = class extends BaseCache {
99
164
  *
100
165
  * Once the limit of items is reached, the soonest expiring items will be purged.
101
166
  */
102
- var LocalTTLCache = class extends BaseCache {
167
+ var LocalTTLCache = class extends BaseLocalCache {
103
168
  cache;
104
169
  constructor(options = {}) {
105
170
  super(options);
106
171
  if ("cache" in options) this.cache = options.cache;
107
172
  else this.cache = new TTLCache({
108
173
  max: options.max,
109
- ttl: options.ttl ? options.ttl * 1e3 : void 0
174
+ ttl: options.ttl ? options.ttl * 1e3 : void 0,
175
+ dispose: (value, key, reason) => this.onDispose(key, value, reason)
110
176
  });
111
177
  }
112
- async get(key) {
178
+ /** @internal */
179
+ _get(key) {
113
180
  this.logger?.debug(this.name, "[get]", "key =", key);
114
181
  const data = this.cache.get(key);
115
182
  return data === void 0 ? null : data;
116
183
  }
117
- async set(key, value, options) {
184
+ /** @internal */
185
+ _set(key, value, options) {
118
186
  this.logger?.debug(this.name, "[set]", "key =", key);
119
187
  const ttl = options?.ttl;
120
188
  this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
121
189
  }
122
- async delete(key) {
190
+ /** @internal */
191
+ _delete(key) {
123
192
  this.logger?.debug(this.name, "[delete]", "key =", key);
124
193
  this.cache.delete(key);
125
194
  }
@@ -132,9 +201,10 @@ var LocalTTLCache = class extends BaseCache {
132
201
  *
133
202
  * It ignores expiration times, but a limit of cached items can be set.
134
203
  *
204
+ * It implements a simple FIFO eviction policy:
135
205
  * Once the limit of items is reached, the first inserted keys will be purged.
136
206
  */
137
- var LocalMapCache = class extends BaseCache {
207
+ var LocalMapCache = class extends BaseLocalCache {
138
208
  cache;
139
209
  max;
140
210
  constructor(options = {}) {
@@ -142,38 +212,55 @@ var LocalMapCache = class extends BaseCache {
142
212
  this.cache = options.cache ?? /* @__PURE__ */ new Map();
143
213
  this.max = options.max ?? Infinity;
144
214
  }
145
- async get(key) {
215
+ /** @internal */
216
+ _get(key) {
146
217
  this.logger?.debug(this.name, "[get]", "key =", key);
147
218
  const data = this.cache.get(key);
148
219
  return data === void 0 ? null : data;
149
220
  }
150
- async set(key, value, options) {
221
+ /** @internal */
222
+ _set(key, value, options) {
151
223
  this.logger?.debug(this.name, "[set]", "key =", key);
152
- if (this.cache.size >= this.max && !this.cache.has(key)) this.evict(1);
224
+ const previousValue = this.cache.get(key);
225
+ if (this.cache.size >= this.max && previousValue === void 0) this.evict(1);
153
226
  this.cache.set(key, value);
227
+ this.onDispose(key, previousValue, "set");
154
228
  }
155
- async delete(key) {
229
+ /** @internal */
230
+ _delete(key) {
156
231
  this.logger?.debug(this.name, "[delete]", "key =", key);
232
+ const previousValue = this.cache.get(key);
157
233
  this.cache.delete(key);
234
+ this.onDispose(key, previousValue, "delete");
158
235
  }
159
236
  async setMany(data, options) {
160
237
  this.logger?.debug(this.name, "[setMany]", "data =", data);
161
238
  const entries = Object.entries(data);
162
239
  const newEntries = entries.filter(([key]) => !this.cache.has(key)).length;
163
240
  if (this.cache.size + newEntries > this.max) this.evict(this.cache.size + newEntries - this.max);
164
- for (const [key, value] of entries) this.cache.set(key, value);
241
+ for (const [key, value] of entries) {
242
+ const previousValue = this.cache.get(key);
243
+ this.cache.set(key, value);
244
+ this.onDispose(key, previousValue, "set");
245
+ }
165
246
  }
166
247
  clear() {
167
248
  this.logger?.debug(this.name, "[clear]");
249
+ for (const key of this.cache.keys()) this.onDispose(key, this.cache.get(key), "delete");
168
250
  this.cache.clear();
169
251
  }
252
+ onDispose(key, value, reason) {
253
+ if (value !== void 0) super.onDispose(key, value, reason);
254
+ }
170
255
  evict(length) {
171
256
  const keys = this.cache.keys();
172
257
  for (let i = 0; i < length; i++) {
173
258
  const key = keys.next();
174
259
  if (key.done) break;
175
260
  this.logger?.debug(this.name, "[evict]", "key = ", key);
261
+ const previousValue = this.cache.get(key.value);
176
262
  this.cache.delete(key.value);
263
+ this.onDispose(key.value, previousValue, "evict");
177
264
  }
178
265
  }
179
266
  };
@@ -182,7 +269,7 @@ var LocalMapCache = class extends BaseCache {
182
269
  //#region src/local/noop/index.ts
183
270
  /**
184
271
  * A cache implementation that does nothing.
185
- * It's useful for disabling cache.
272
+ * It's useful for disabling cache and unit testing.
186
273
  *
187
274
  * @example
188
275
  * ```ts
@@ -214,12 +301,14 @@ var NoOpCache = class {
214
301
  var IORedisCache = class extends BaseCache {
215
302
  client;
216
303
  defaultTTL;
304
+ isUNLINKSupported;
217
305
  isMSETEXSupported;
218
306
  constructor(options) {
219
307
  super(options);
220
308
  this.client = options.client;
221
309
  this.defaultTTL = options.defaultTTL;
222
- this.isMSETEXSupported = options.isMSETEXSupported;
310
+ this.isUNLINKSupported = options.isUNLINKSupported ?? true;
311
+ this.isMSETEXSupported = options.isMSETEXSupported ?? false;
223
312
  }
224
313
  async get(key) {
225
314
  this.logger?.debug(this.name, "[get] Running \"GET\" command...", "key =", key);
@@ -234,8 +323,13 @@ var IORedisCache = class extends BaseCache {
234
323
  else await this.client.set(key, raw);
235
324
  }
236
325
  async delete(key) {
237
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
238
- await this.client.del(key);
326
+ if (this.isUNLINKSupported) {
327
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
328
+ await this.client.unlink(key);
329
+ } else {
330
+ this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
331
+ await this.client.del(key);
332
+ }
239
333
  }
240
334
  async getMany(keys) {
241
335
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -256,8 +350,13 @@ var IORedisCache = class extends BaseCache {
256
350
  await this.client.call("MSETEX", entries.length, ...raw, ...ttl ? ["EX", ttl] : []);
257
351
  }
258
352
  async deleteMany(keys) {
259
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
260
- await this.client.del(keys);
353
+ if (this.isUNLINKSupported) {
354
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
355
+ await this.client.unlink(keys);
356
+ } else {
357
+ this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
358
+ await this.client.del(keys);
359
+ }
261
360
  }
262
361
  };
263
362
 
@@ -269,12 +368,14 @@ var IORedisCache = class extends BaseCache {
269
368
  var RedisCache = class extends BaseCache {
270
369
  client;
271
370
  defaultTTL;
371
+ isUNLINKSupported;
272
372
  isMSETEXSupported;
273
373
  constructor(options) {
274
374
  super(options);
275
375
  this.client = options.client;
276
376
  this.defaultTTL = options.defaultTTL;
277
- this.isMSETEXSupported = options.isMSETEXSupported;
377
+ this.isUNLINKSupported = options.isUNLINKSupported ?? true;
378
+ this.isMSETEXSupported = options.isMSETEXSupported ?? false;
278
379
  }
279
380
  async get(key) {
280
381
  this.logger?.debug(this.name, "[get] Running \"GET\" command...", "key =", key);
@@ -290,8 +391,13 @@ var RedisCache = class extends BaseCache {
290
391
  } : void 0 });
291
392
  }
292
393
  async delete(key) {
293
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
294
- await this.client.del(key);
394
+ if (this.isUNLINKSupported) {
395
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
396
+ await this.client.unlink(key);
397
+ } else {
398
+ this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
399
+ await this.client.del(key);
400
+ }
295
401
  }
296
402
  async getMany(keys) {
297
403
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -315,8 +421,13 @@ var RedisCache = class extends BaseCache {
315
421
  } : void 0 });
316
422
  }
317
423
  async deleteMany(keys) {
318
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
319
- await this.client.del(keys);
424
+ if (this.isUNLINKSupported) {
425
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
426
+ await this.client.unlink(keys);
427
+ } else {
428
+ this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
429
+ await this.client.del(keys);
430
+ }
320
431
  }
321
432
  };
322
433
 
@@ -347,8 +458,8 @@ var ValkeyGlideCache = class extends BaseCache {
347
458
  } : void 0 });
348
459
  }
349
460
  async delete(key) {
350
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
351
- await this.client.del([key]);
461
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
462
+ await this.client.unlink([key]);
352
463
  }
353
464
  async getMany(keys) {
354
465
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -361,8 +472,8 @@ var ValkeyGlideCache = class extends BaseCache {
361
472
  return data;
362
473
  }
363
474
  async deleteMany(keys) {
364
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
365
- await this.client.del(keys);
475
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
476
+ await this.client.unlink(keys);
366
477
  }
367
478
  };
368
479