Add a function to calculate the intrinsic limit of a filter
This commit is contained in:
parent
80e6147927
commit
5bffffe07b
|
@ -4,7 +4,7 @@ import { assertEquals } from '@/deps-test.ts';
|
||||||
import event0 from '~/fixtures/events/event-0.json' assert { type: 'json' };
|
import event0 from '~/fixtures/events/event-0.json' assert { type: 'json' };
|
||||||
import event1 from '~/fixtures/events/event-1.json' assert { type: 'json' };
|
import event1 from '~/fixtures/events/event-1.json' assert { type: 'json' };
|
||||||
|
|
||||||
import { eventToMicroFilter, getFilterId, getMicroFilters, isMicrofilter } from './filter.ts';
|
import { eventToMicroFilter, getFilterId, getFilterLimit, getMicroFilters, isMicrofilter } from './filter.ts';
|
||||||
|
|
||||||
Deno.test('getMicroFilters', () => {
|
Deno.test('getMicroFilters', () => {
|
||||||
const event = event0 as Event<0>;
|
const event = event0 as Event<0>;
|
||||||
|
@ -35,3 +35,13 @@ Deno.test('getFilterId', () => {
|
||||||
'{"authors":["79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6"],"kinds":[0]}',
|
'{"authors":["79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6"],"kinds":[0]}',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test('getFilterLimit', () => {
|
||||||
|
assertEquals(getFilterLimit({ ids: [event0.id] }), 1);
|
||||||
|
assertEquals(getFilterLimit({ ids: [event0.id], limit: 2 }), 1);
|
||||||
|
assertEquals(getFilterLimit({ ids: [event0.id], limit: 0 }), 0);
|
||||||
|
assertEquals(getFilterLimit({ ids: [event0.id], limit: -1 }), 0);
|
||||||
|
assertEquals(getFilterLimit({ kinds: [0], authors: [event0.pubkey] }), 1);
|
||||||
|
assertEquals(getFilterLimit({ kinds: [1], authors: [event0.pubkey] }), Infinity);
|
||||||
|
assertEquals(getFilterLimit({}), Infinity);
|
||||||
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Conf } from '@/config.ts';
|
||||||
import { type Event, type Filter, matchFilters, stringifyStable, z } from '@/deps.ts';
|
import { type Event, type Filter, matchFilters, stringifyStable, z } from '@/deps.ts';
|
||||||
import { nostrIdSchema } from '@/schemas/nostr.ts';
|
import { nostrIdSchema } from '@/schemas/nostr.ts';
|
||||||
import { type EventData } from '@/types.ts';
|
import { type EventData } from '@/types.ts';
|
||||||
|
import { isReplaceableKind } from '@/kinds.ts';
|
||||||
|
|
||||||
/** Additional properties that may be added by Ditto to events. */
|
/** Additional properties that may be added by Ditto to events. */
|
||||||
type Relation = 'author' | 'author_stats' | 'event_stats';
|
type Relation = 'author' | 'author_stats' | 'event_stats';
|
||||||
|
@ -82,11 +83,34 @@ function isMicrofilter(filter: Filter): filter is MicroFilter {
|
||||||
return microFilterSchema.safeParse(filter).success;
|
return microFilterSchema.safeParse(filter).success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Calculate the intrinsic limit of a filter. */
|
||||||
|
function getFilterLimit(filter: Filter): number {
|
||||||
|
if (filter.ids && !filter.ids.length) return 0;
|
||||||
|
if (filter.kinds && !filter.kinds.length) return 0;
|
||||||
|
if (filter.authors && !filter.authors.length) return 0;
|
||||||
|
|
||||||
|
return Math.min(
|
||||||
|
Math.max(0, filter.limit ?? Infinity),
|
||||||
|
filter.ids?.length ?? Infinity,
|
||||||
|
filter.authors?.length &&
|
||||||
|
filter.kinds?.every((kind) => isReplaceableKind(kind))
|
||||||
|
? filter.authors.length * filter.kinds.length
|
||||||
|
: Infinity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the filter could potentially return any stored events at all. */
|
||||||
|
function canFilter(filter: Filter): boolean {
|
||||||
|
return getFilterLimit(filter) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
type AuthorMicrofilter,
|
type AuthorMicrofilter,
|
||||||
|
canFilter,
|
||||||
type DittoFilter,
|
type DittoFilter,
|
||||||
eventToMicroFilter,
|
eventToMicroFilter,
|
||||||
getFilterId,
|
getFilterId,
|
||||||
|
getFilterLimit,
|
||||||
getMicroFilters,
|
getMicroFilters,
|
||||||
type IdMicrofilter,
|
type IdMicrofilter,
|
||||||
isMicrofilter,
|
isMicrofilter,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Debug, type Event, type Filter, LRUCache, matchFilter, matchFilters } from '@/deps.ts';
|
import { Debug, type Event, type Filter, LRUCache, matchFilter, matchFilters } from '@/deps.ts';
|
||||||
|
import { canFilter, getFilterLimit } from '@/filter.ts';
|
||||||
import { type EventStore, type GetEventsOpts } from '@/store.ts';
|
import { type EventStore, type GetEventsOpts } from '@/store.ts';
|
||||||
|
|
||||||
/** In-memory data store for events. */
|
/** In-memory data store for events. */
|
||||||
|
@ -27,6 +28,7 @@ class Memorelay implements EventStore {
|
||||||
/** Get events from memory. */
|
/** Get events from memory. */
|
||||||
getEvents<K extends number>(filters: Filter<K>[], opts: GetEventsOpts = {}): Promise<Event<K>[]> {
|
getEvents<K extends number>(filters: Filter<K>[], opts: GetEventsOpts = {}): Promise<Event<K>[]> {
|
||||||
if (opts.signal?.aborted) return Promise.resolve([]);
|
if (opts.signal?.aborted) return Promise.resolve([]);
|
||||||
|
filters = filters.filter(canFilter);
|
||||||
if (!filters.length) return Promise.resolve([]);
|
if (!filters.length) return Promise.resolve([]);
|
||||||
this.#debug('REQ', JSON.stringify(filters));
|
this.#debug('REQ', JSON.stringify(filters));
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ class Memorelay implements EventStore {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
const limit = filter.limit ?? Infinity;
|
const limit = getFilterLimit(filter);
|
||||||
const usage = usages[index] ?? 0;
|
const usage = usages[index] ?? 0;
|
||||||
|
|
||||||
if (usage >= limit) {
|
if (usage >= limit) {
|
||||||
|
@ -50,7 +52,7 @@ class Memorelay implements EventStore {
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.every((filter, index) => usages[index] >= (filter.limit ?? Infinity))) {
|
if (filters.every((filter, index) => usages[index] >= getFilterLimit(filter))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue