Add Cache primtive
This commit is contained in:
@@ -7,11 +7,17 @@ import { StorageMemory } from './storage-memory.js';
|
||||
* All read operations will use system memory - all write operations will use the provided adapter.
|
||||
*/
|
||||
export class StorageMemorySynced<T extends Record<string, any> = Record<string, any>> extends BaseStorage<T> {
|
||||
private isPrimed: boolean;
|
||||
private primePromise: Promise<void> | null;
|
||||
|
||||
constructor(
|
||||
private inMemoryCache: StorageMemory<T>,
|
||||
private store: BaseStorage<T>,
|
||||
isPrimed = false,
|
||||
) {
|
||||
super();
|
||||
this.isPrimed = isPrimed;
|
||||
this.primePromise = null;
|
||||
|
||||
// Hook into all write operations so that we can sync the In-Memory cache.
|
||||
this.store.on('insert', async (payload) => {
|
||||
@@ -44,6 +50,23 @@ export class StorageMemorySynced<T extends Record<string, any> = Record<string,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the in-memory cache has been initialized from the backing store.
|
||||
* This is especially important for derived children, whose caches start empty.
|
||||
*/
|
||||
private async ensurePrimed(): Promise<void> {
|
||||
if (this.isPrimed) return;
|
||||
if (!this.primePromise) {
|
||||
this.primePromise = (async () => {
|
||||
await this.inMemoryCache.deleteMany({});
|
||||
const allDocuments = await this.store.find();
|
||||
await this.inMemoryCache.insertMany(allDocuments);
|
||||
this.isPrimed = true;
|
||||
})();
|
||||
}
|
||||
await this.primePromise;
|
||||
}
|
||||
|
||||
static async create<T extends Record<string, any>>(store: BaseStorage<T>) {
|
||||
// Instantiate in-memory cache and the backing store.
|
||||
const inMemoryCache = new StorageMemory<T>();
|
||||
@@ -58,6 +81,7 @@ export class StorageMemorySynced<T extends Record<string, any> = Record<string,
|
||||
}
|
||||
|
||||
// Return our instance of this store.
|
||||
memorySyncedStore.isPrimed = true;
|
||||
return memorySyncedStore;
|
||||
}
|
||||
|
||||
@@ -66,26 +90,33 @@ export class StorageMemorySynced<T extends Record<string, any> = Record<string,
|
||||
}
|
||||
|
||||
async find(filter?: Filter<T>, options?: FindOptions): Promise<T[]> {
|
||||
await this.ensurePrimed();
|
||||
return await this.inMemoryCache.find(filter, options);
|
||||
}
|
||||
|
||||
async updateMany(
|
||||
filter: Filter<T>,
|
||||
update: Partial<T>,
|
||||
options: FindOptions = {} as FindOptions
|
||||
options: Partial<FindOptions> = {},
|
||||
): Promise<number> {
|
||||
await this.ensurePrimed();
|
||||
return await this.store.updateMany(filter, update, options);
|
||||
}
|
||||
|
||||
async deleteMany(filter: Filter<T>, options: FindOptions = {} as FindOptions): Promise<number> {
|
||||
async deleteMany(filter: Filter<T>, options: Partial<FindOptions> = {}): Promise<number> {
|
||||
await this.ensurePrimed();
|
||||
return await this.store.deleteMany(filter, options);
|
||||
}
|
||||
|
||||
deriveChild<C extends Record<string, any>>(path: string): BaseStorage<C> {
|
||||
const childStore = this.store.deriveChild<C>(path);
|
||||
const childMemory = this.inMemoryCache.deriveChild<C>(path);
|
||||
|
||||
|
||||
if (!(childMemory instanceof StorageMemory)) {
|
||||
throw new Error('Expected derived in-memory cache to be a StorageMemory instance');
|
||||
}
|
||||
|
||||
// Create a new synced storage for the child
|
||||
return new StorageMemorySynced<C>(childMemory as StorageMemory<C>, childStore);
|
||||
return new StorageMemorySynced<C>(childMemory, childStore);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user