|
1 | | -/** @implements {ReadonlyMap<string, any>} */ |
| 1 | +/** @import { ObservableCache } from './observable-cache.js' */ |
| 2 | + |
| 3 | +/** |
| 4 | + * @template T |
| 5 | + * @implements {ReadonlyMap<string, T>} */ |
2 | 6 | export class BaseCacheObserver { |
3 | | - /** @type {ReadonlyMap<string, any>} */ |
4 | | - #cache; |
| 7 | + /** |
| 8 | + * This is a function so that you can create an ObservableCache instance globally and as long as you don't actually |
| 9 | + * use it until you're inside the server render lifecycle you'll be okay |
| 10 | + * @type {() => ObservableCache} |
| 11 | + */ |
| 12 | + #get_cache; |
| 13 | + |
| 14 | + /** @type {string} */ |
| 15 | + #prefix; |
| 16 | + |
| 17 | + /** |
| 18 | + * @param {() => ObservableCache} get_cache |
| 19 | + * @param {string} [prefix] |
| 20 | + */ |
| 21 | + constructor(get_cache, prefix = '') { |
| 22 | + this.#get_cache = get_cache; |
| 23 | + this.#prefix = prefix; |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Register a callback to be called when a new key is inserted |
| 28 | + * @param {(key: string, value: T) => void} callback |
| 29 | + * @returns {() => void} Function to unregister the callback |
| 30 | + */ |
| 31 | + onInsert(callback) { |
| 32 | + return this.#get_cache().on_insert((key, value) => { |
| 33 | + if (!key.startsWith(this.#prefix)) return; |
| 34 | + callback(key, value.item); |
| 35 | + }); |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * Register a callback to be called when an existing key is updated |
| 40 | + * @param {(key: string, value: T, old_value: T) => void} callback |
| 41 | + * @returns {() => void} Function to unregister the callback |
| 42 | + */ |
| 43 | + onUpdate(callback) { |
| 44 | + return this.#get_cache().on_update((key, value, old_value) => { |
| 45 | + if (!key.startsWith(this.#prefix)) return; |
| 46 | + callback(key, value.item, old_value.item); |
| 47 | + }); |
| 48 | + } |
5 | 49 |
|
6 | | - /** @param {Map<string, any>} cache */ |
7 | | - constructor(cache) { |
8 | | - this.#cache = cache; |
| 50 | + /** |
| 51 | + * Register a callback to be called when a key is deleted |
| 52 | + * @param {(key: string, old_value: T) => void} callback |
| 53 | + * @returns {() => void} Function to unregister the callback |
| 54 | + */ |
| 55 | + onDelete(callback) { |
| 56 | + return this.#get_cache().on_delete((key, old_value) => { |
| 57 | + if (!key.startsWith(this.#prefix)) return; |
| 58 | + callback(key, old_value.item); |
| 59 | + }); |
9 | 60 | } |
10 | 61 |
|
11 | | - /** @type {ReadonlyMap<string, any>['get']} */ |
| 62 | + /** @param {string} key */ |
12 | 63 | get(key) { |
13 | | - const entry = this.#cache.get(key); |
| 64 | + const entry = this.#get_cache().get(this.#key(key)); |
14 | 65 | return entry?.item; |
15 | 66 | } |
16 | 67 |
|
17 | | - /** @type {ReadonlyMap<string, any>['has']} */ |
| 68 | + /** @param {string} key */ |
18 | 69 | has(key) { |
19 | | - return this.#cache.has(key); |
| 70 | + return this.#get_cache().has(this.#key(key)); |
20 | 71 | } |
21 | 72 |
|
22 | | - /** @type {ReadonlyMap<string, any>['size']} */ |
23 | 73 | get size() { |
24 | | - return this.#cache.size; |
| 74 | + return [...this.keys()].length; |
25 | 75 | } |
26 | 76 |
|
27 | | - /** @type {ReadonlyMap<string, any>['forEach']} */ |
| 77 | + /** @param {(item: T, key: string, map: ReadonlyMap<string, T>) => void} cb */ |
28 | 78 | forEach(cb) { |
29 | | - this.#cache.forEach((entry, key) => cb(entry.item, key, this)); |
| 79 | + this.entries().forEach(([key, entry]) => cb(entry, key, this)); |
30 | 80 | } |
31 | 81 |
|
32 | | - /** @type {ReadonlyMap<string, any>['entries']} */ |
33 | 82 | *entries() { |
34 | | - for (const [key, entry] of this.#cache.entries()) { |
35 | | - yield [key, entry.item]; |
| 83 | + for (const [key, entry] of this.#get_cache().entries()) { |
| 84 | + if (!key.startsWith(this.#prefix)) continue; |
| 85 | + yield /** @type {[string, T]} */ ([key, entry.item]); |
36 | 86 | } |
| 87 | + return undefined; |
37 | 88 | } |
38 | 89 |
|
39 | | - /** @type {ReadonlyMap<string, any>['keys']} */ |
40 | 90 | *keys() { |
41 | | - for (const key of this.#cache.keys()) { |
| 91 | + for (const [key] of this.entries()) { |
42 | 92 | yield key; |
43 | 93 | } |
| 94 | + return undefined; |
44 | 95 | } |
45 | 96 |
|
46 | | - /** @type {ReadonlyMap<string, any>['values']} */ |
47 | 97 | *values() { |
48 | | - for (const entry of this.#cache.values()) { |
49 | | - yield entry.item; |
| 98 | + for (const [, entry] of this.entries()) { |
| 99 | + yield entry; |
50 | 100 | } |
| 101 | + return undefined; |
51 | 102 | } |
52 | 103 |
|
53 | 104 | [Symbol.iterator]() { |
54 | 105 | return this.entries(); |
55 | 106 | } |
| 107 | + |
| 108 | + /** @param {string} key */ |
| 109 | + #key(key) { |
| 110 | + return this.#prefix + key; |
| 111 | + } |
56 | 112 | } |
0 commit comments