From 9c009ac543defc9784c3da2a06cf7d146e0c7b81 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 20 Jul 2024 13:55:09 -0500 Subject: [PATCH] getFilterLimit: handle parameterized replaceable events --- filter.test.ts | 10 ++++++++++ filter.ts | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/filter.test.ts b/filter.test.ts index d9d40e2..eb07079 100644 --- a/filter.test.ts +++ b/filter.test.ts @@ -215,6 +215,16 @@ describe('Filter', () => { expect(getFilterLimit({ kinds: [0, 3], authors: ['alex', 'fiatjaf'] })).toEqual(4) }) + test('should handle parameterized replaceable events', () => { + expect(getFilterLimit({ kinds: [30078], authors: ['alex'] })).toEqual(Infinity) + expect(getFilterLimit({ kinds: [30078], authors: ['alex'], '#d': ['ditto'] })).toEqual(1) + expect(getFilterLimit({ kinds: [30078], authors: ['alex'], '#d': ['ditto', 'soapbox'] })).toEqual(2) + expect(getFilterLimit({ kinds: [30078], authors: ['alex', 'fiatjaf'], '#d': ['ditto', 'soapbox'] })).toEqual(4) + expect( + getFilterLimit({ kinds: [30000, 30078], authors: ['alex', 'fiatjaf'], '#d': ['ditto', 'soapbox'] }), + ).toEqual(8) + }) + test('should return Infinity for authors with regular kinds', () => { expect(getFilterLimit({ kinds: [1], authors: ['alex'] })).toEqual(Infinity) }) diff --git a/filter.ts b/filter.ts index 5eab56d..00f00d9 100644 --- a/filter.ts +++ b/filter.ts @@ -1,5 +1,5 @@ import { Event } from './core.ts' -import { isReplaceableKind } from './kinds.ts' +import { isParameterizedReplaceableKind, isReplaceableKind } from './kinds.ts' export type Filter = { ids?: string[] @@ -72,7 +72,10 @@ export function mergeFilters(...filters: Filter[]): Filter { return result } -/** Calculate the intrinsic limit of a filter. This function may return `Infinity`. */ +/** + * Calculate the intrinsic limit of a filter. + * This function returns a positive integer, or `Infinity` if there is no intrinsic limit. + */ export function getFilterLimit(filter: Filter): number { if (filter.ids && !filter.ids.length) return 0 if (filter.kinds && !filter.kinds.length) return 0 @@ -83,10 +86,20 @@ export function getFilterLimit(filter: Filter): number { } return Math.min( + // The `limit` property creates an artificial limit. Math.max(0, filter.limit ?? Infinity), + + // There can only be one event per `id`. filter.ids?.length ?? Infinity, + + // Replaceable events are limited by the number of authors and kinds. filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind)) ? filter.authors.length * filter.kinds.length : Infinity, + + // Parameterized replaceable events are limited by the number of authors, kinds, and "d" tags. + filter.authors?.length && filter.kinds?.every(kind => isParameterizedReplaceableKind(kind)) && filter['#d']?.length + ? filter.authors.length * filter.kinds.length * filter['#d'].length + : Infinity, ) }