import { BaseStorage, FindOptions } from './base-storage.js'; import { StorageMemory } from './storage-memory.js'; /** * Storage Adapter that takes another Storage Adapter (e.g. IndexedDB) and "syncs" its contents to system memory for faster read access. * * All read operations will use system memory - all write operations will use the provided adapter. */ export class StorageMemorySynced = Record> extends BaseStorage { constructor( private inMemoryCache: StorageMemory, private store: BaseStorage, ) { super(); // Hook into all write operations so that we can sync the In-Memory cache. this.store.on('insert', async (payload) => { await this.inMemoryCache.insertOne(payload.value); this.emit('insert', payload); }); this.store.on('update', async (payload) => { // For update events, we need to find and update the document in memory // Since we don't have the filter, we'll update by key const filter = { id: payload.value.id, } as unknown as Partial // Update the document in memory by ID. await this.inMemoryCache.updateOne(filter, payload.value); this.emit('update', payload); }); this.store.on('delete', async (payload) => { await this.inMemoryCache.deleteOne(payload.value); // Re-emit the delete event with the original payload. this.emit('delete', payload); }); this.store.on('clear', async () => { // Clear all documents from memory cache await this.inMemoryCache.deleteMany({}); // Re-emit the clear event with the original payload. this.emit('clear', undefined); }); } static async create>(store: BaseStorage) { // Instantiate in-memory cache and the backing store. const inMemoryCache = new StorageMemory(); // Create instance of this store. const memorySyncedStore = new StorageMemorySynced(inMemoryCache, store); // Sync the data from the backing store into the In-Memory cache. const allDocuments = await store.find(); for (const document of allDocuments) { await inMemoryCache.insertOne(document); } // Return our instance of this store. return memorySyncedStore; } async insertMany(documents: Array): Promise { await this.store.insertMany(documents); } async find(filter?: Partial, options?: FindOptions): Promise { return await this.inMemoryCache.find(filter, options); } async updateMany( filter: Partial, update: Partial, options: FindOptions = {} as FindOptions ): Promise { return await this.store.updateMany(filter, update, options); } async deleteMany(filter: Partial, options: FindOptions = {} as FindOptions): Promise { return await this.store.deleteMany(filter, options); } deriveChild>(path: string): BaseStorage { const childStore = this.store.deriveChild(path); const childMemory = this.inMemoryCache.deriveChild(path); // Create a new synced storage for the child return new StorageMemorySynced(childMemory as StorageMemory, childStore); } }