Upgrade NSpec, update `count` interface

This commit is contained in:
Alex Gleason 2024-02-12 10:48:26 -06:00
parent 676bd04229
commit cb80770fc7
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
10 changed files with 25 additions and 51 deletions

View File

@ -96,7 +96,7 @@ function connectStream(socket: WebSocket) {
/** Handle COUNT. Return the number of events matching the filters. */
async function handleCount([_, subId, ...rest]: ClientCOUNT): Promise<void> {
const count = await eventsDB.count(prepareFilters(rest));
const { count } = await eventsDB.count(prepareFilters(rest));
send(['COUNT', subId, { count, approximate: false }]);
}

View File

@ -85,7 +85,6 @@ export { default as Debug } from 'https://gitlab.com/soapbox-pub/stickynotes/-/r
export {
LNURL,
type LNURLDetails,
type MapCache,
NCache,
NIP05,
type NostrEvent,
@ -93,6 +92,6 @@ export {
NSet,
type NStore,
type NStoreOpts,
} from 'https://gitlab.com/soapbox-pub/NSpec/-/raw/8ce84d9acd9925f51b51c00374eae81a5031559b/mod.ts';
} from 'https://gitlab.com/soapbox-pub/NSpec/-/raw/v0.1.0/mod.ts';
export type * as TypeFest from 'npm:type-fest@^4.3.0';

View File

@ -46,7 +46,7 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
/** Encounter the event, and return whether it has already been encountered. */
async function encounterEvent(event: NostrEvent, signal: AbortSignal): Promise<boolean> {
const preexisting = (await cache.count([{ ids: [event.id] }])) > 0;
const preexisting = (await cache.count([{ ids: [event.id] }])).count > 0;
cache.event(event);
reqmeister.event(event, { signal });
return preexisting;
@ -72,10 +72,10 @@ async function storeEvent(event: DittoEvent, opts: StoreEventOpts): Promise<void
const { force = false, signal } = opts;
if (force || event.user || isAdminEvent(event) || await isLocallyFollowed(event.pubkey)) {
const isDeleted = await eventsDB.count(
const isDeleted = (await eventsDB.count(
[{ kinds: [5], authors: [Conf.pubkey, event.pubkey], '#e': [event.id], limit: 1 }],
opts,
) > 0;
)).count > 0;
if (isDeleted) {
return Promise.reject(new RelayError('blocked', 'event was deleted'));
@ -145,16 +145,20 @@ function trackRelays(event: NostrEvent) {
}
/** Queue related events to fetch. */
function fetchRelatedEvents(event: DittoEvent, signal: AbortSignal) {
async function fetchRelatedEvents(event: DittoEvent, signal: AbortSignal) {
if (!event.user) {
reqmeister.req({ kinds: [0], authors: [event.pubkey] }, { signal }).catch(() => {});
}
for (const [name, id, relay] of event.tags) {
if (name === 'e' && !cache.count([{ ids: [id] }])) {
if (name === 'e') {
const { count } = await cache.count([{ ids: [id] }]);
if (!count) {
reqmeister.req({ ids: [id] }, { relays: [relay] }).catch(() => {});
}
}
}
}
/** Delete unattached media entries that are attached to the event. */
function processMedia({ tags, pubkey, user }: DittoEvent) {

View File

@ -10,9 +10,9 @@ import { EventsDB } from './events-db.ts';
const eventsDB = new EventsDB(db);
Deno.test('count filters', async () => {
assertEquals(await eventsDB.count([{ kinds: [1] }]), 0);
assertEquals((await eventsDB.count([{ kinds: [1] }])).count, 0);
await eventsDB.event(event1);
assertEquals(await eventsDB.count([{ kinds: [1] }]), 1);
assertEquals((await eventsDB.count([{ kinds: [1] }])).count, 1);
});
Deno.test('insert and filter events', async () => {
@ -55,11 +55,11 @@ Deno.test('query events with local filter', async () => {
});
Deno.test('inserting replaceable events', async () => {
assertEquals(await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }]), 0);
assertEquals((await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }])).count, 0);
await eventsDB.event(event0);
await assertRejects(() => eventsDB.event(event0));
assertEquals(await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }]), 1);
assertEquals((await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }])).count, 1);
const changeEvent = { ...event0, id: '123', created_at: event0.created_at + 1 };
await eventsDB.event(changeEvent);

View File

@ -345,9 +345,9 @@ class EventsDB implements NStore {
}
/** Get number of events that would be returned by filters. */
async count(filters: DittoFilter[], opts: NStoreOpts = {}): Promise<number> {
async count(filters: DittoFilter[], opts: NStoreOpts = {}): Promise<{ count: number; approximate: boolean }> {
if (opts.signal?.aborted) return Promise.reject(abortError());
if (!filters.length) return Promise.resolve(0);
if (!filters.length) return Promise.resolve({ count: 0, approximate: false });
this.#debug('COUNT', JSON.stringify(filters));
const query = this.getEventsQuery(filters);
@ -357,7 +357,10 @@ class EventsDB implements NStore {
.select((eb) => eb.fn.count('id').as('count'))
.execute();
return Number(count);
return {
count: Number(count),
approximate: false,
};
}
}

View File

@ -94,14 +94,6 @@ class Optimizer implements NStore {
return getResults();
}
count(_filters: DittoFilter[]): Promise<number> {
return Promise.reject(new Error('COUNT not implemented.'));
}
remove(_filters: DittoFilter[]): Promise<void> {
return Promise.reject(new Error('DELETE not implemented.'));
}
}
export { Optimizer };

View File

@ -92,14 +92,6 @@ class PoolStore implements NStore {
opts.signal?.addEventListener('abort', onAbort);
});
}
count() {
return Promise.reject(new Error('COUNT not implemented'));
}
remove() {
return Promise.reject(new Error('Cannot delete events from relays. Create a kind 5 event instead.'));
}
}
export { PoolStore };

View File

@ -133,14 +133,6 @@ class Reqmeister extends EventEmitter<{ [filterId: string]: (event: NostrEvent)
return Promise.all(promises);
}
count(_filters: NostrFilter[]): Promise<number> {
return Promise.reject(new Error('COUNT not implemented.'));
}
remove(_filters: NostrFilter[]): Promise<void> {
return Promise.reject(new Error('DELETE not implemented.'));
}
}
export { Reqmeister };

View File

@ -1,6 +1,6 @@
import { NiceRelay } from 'https://gitlab.com/soapbox-pub/nostr-machina/-/raw/5f4fb59c90c092e5aa59c01e6556a4bec264c167/mod.ts';
import { Debug, type NostrEvent, type NostrFilter, NSet, type NStore, type NStoreOpts } from '@/deps.ts';
import { Debug, type NostrEvent, NSet, type NStore, type NStoreOpts } from '@/deps.ts';
import { normalizeFilters } from '@/filter.ts';
import { type DittoEvent } from '@/interfaces/DittoEvent.ts';
import { type DittoFilter } from '@/interfaces/DittoFilter.ts';
@ -68,14 +68,6 @@ class SearchStore implements NStore {
return this.#fallback.query(filters, opts);
}
}
count(_filters: NostrFilter[]): Promise<number> {
return Promise.reject(new Error('COUNT not implemented.'));
}
remove(_filters: NostrFilter[]): Promise<void> {
return Promise.reject(new Error('DELETE not implemented.'));
}
}
export { SearchStore };

View File

@ -1,6 +1,6 @@
// deno-lint-ignore-file ban-types
import { LRUCache, type MapCache } from '@/deps.ts';
import { LRUCache } from '@/deps.ts';
type FetchFn<K extends {}, V extends {}, O extends {}> = (key: K, opts: O) => Promise<V>;
@ -12,7 +12,7 @@ export class SimpleLRU<
K extends {},
V extends {},
O extends {} = FetchFnOpts,
> implements MapCache<K, V, O> {
> {
protected cache: LRUCache<K, V, void>;
constructor(fetchFn: FetchFn<K, V, { signal: AbortSignal }>, opts: LRUCache.Options<K, V, void>) {