diff --git a/src/storages/memorelay.ts b/src/storages/memorelay.ts index ec744ea..b0f7104 100644 --- a/src/storages/memorelay.ts +++ b/src/storages/memorelay.ts @@ -1,4 +1,4 @@ -import { Debug, type Event, type Filter, LRUCache, matchFilter, matchFilters } from '@/deps.ts'; +import { Debug, type Event, type Filter, LRUCache, matchFilter } from '@/deps.ts'; import { normalizeFilters } from '@/filter.ts'; import { type EventStore, type GetEventsOpts } from '@/store.ts'; @@ -27,32 +27,62 @@ class Memorelay implements EventStore { /** Get events from memory. */ getEvents(filters: Filter[], opts: GetEventsOpts = {}): Promise[]> { - if (opts.signal?.aborted) return Promise.resolve([]); filters = normalizeFilters(filters); + + if (opts.signal?.aborted) return Promise.resolve([]); if (!filters.length) return Promise.resolve([]); + this.#debug('REQ', JSON.stringify(filters)); + /** Event results to return. */ const results: Event[] = []; - const usages: number[] = []; + /** Number of times an event has been added to results for each filter. */ + const filterUsages: number[] = []; + + /** Check if all filters have been satisfied. */ + function checkSatisfied() { + return results.length >= (opts.limit ?? Infinity) || + filters.every((filter, index) => filter.limit && (filterUsages[index] >= filter.limit)); + } + + // Optimize for filters with IDs. + filters.forEach((filter, index) => { + if (filter.ids) { + for (const id of filter.ids) { + const event = this.#cache.get(id); + if (event && matchFilter(filter, event)) { + results.push(event as Event); + } + } + filterUsages[index] = Infinity; + } + }); + + // Return early if all filters are satisfied. + if (checkSatisfied()) { + return Promise.resolve(results); + } + + // Seek through all events in memory. for (const event of this.#events()) { - let index = 0; - - for (const filter of filters) { + filters.forEach((filter, index) => { const limit = filter.limit ?? Infinity; - const usage = usages[index] ?? 0; + const usage = filterUsages[index] ?? 0; if (usage >= limit) { - continue; + return; } else if (matchFilter(filter, event)) { results.push(event as Event); - usages[index] = usage + 1; + this.#cache.get(event.id); + filterUsages[index] = usage + 1; } index++; - } + }); - if (filters.every((filter, index) => filter.limit && (usages[index] >= filter.limit))) { + // Check after each event if we can return. + if (checkSatisfied()) { break; } } @@ -73,11 +103,9 @@ class Memorelay implements EventStore { } /** Delete events from memory. */ - deleteEvents(filters: Filter[]): Promise { - for (const event of this.#events()) { - if (matchFilters(filters, event)) { - this.#cache.delete(event.id); - } + async deleteEvents(filters: Filter[]): Promise { + for (const event of await this.getEvents(filters)) { + this.#cache.delete(event.id); } return Promise.resolve(); }