EventsDB: expandFilters, greatly speed up domain timelines

Fixes: https://gitlab.com/soapbox-pub/ditto/-/issues/80
This commit is contained in:
Alex Gleason 2024-03-22 17:50:50 -05:00
parent c3adafa860
commit cfc2f02104
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
1 changed files with 42 additions and 21 deletions

View File

@ -193,26 +193,9 @@ class EventsDB implements NStore {
} }
if (filter.search) { if (filter.search) {
const tokens = NIP50.parseInput(filter.search); query = query
.innerJoin('events_fts', 'events_fts.id', 'events.id')
const domain = (tokens.find((t) => .where('events_fts.content', 'match', JSON.stringify(filter.search));
typeof t === 'object' && t.key === 'domain'
) as { key: 'domain'; value: string } | undefined)?.value;
if (domain) {
query = query.where('events.pubkey', 'in', (eb) =>
eb.selectFrom('pubkey_domains').select('pubkey').where('domain', '=', domain));
}
const q = tokens.filter((t) =>
typeof t === 'string'
).join(' ');
if (q) {
query = query
.innerJoin('events_fts', 'events_fts.id', 'events.id')
.where('events_fts.content', 'match', JSON.stringify(q));
}
} }
return query; return query;
@ -234,9 +217,47 @@ class EventsDB implements NStore {
.as('users'); .as('users');
} }
/** Converts filters to more performant, simpler filters that are better for SQLite. */
async expandFilters(filters: NostrFilter[]): Promise<NostrFilter[]> {
filters = normalizeFilters(filters); // Improves performance of `{ kinds: [0], authors: ['...'] }` queries.
for (const filter of filters) {
if (filter.search) {
const tokens = NIP50.parseInput(filter.search);
const domain = (tokens.find((t) =>
typeof t === 'object' && t.key === 'domain'
) as { key: 'domain'; value: string } | undefined)?.value;
if (domain) {
const query = this.#db
.selectFrom('pubkey_domains')
.select('pubkey')
.where('domain', '=', domain);
if (filter.authors) {
query.where('pubkey', 'in', filter.authors);
}
const pubkeys = await query
.execute()
.then((rows) =>
rows.map((row) => row.pubkey)
);
filter.authors = pubkeys;
}
filter.search = tokens.filter((t) => typeof t === 'string').join(' ');
}
}
return filters;
}
/** Get events for filters from the database. */ /** Get events for filters from the database. */
async query(filters: NostrFilter[], opts: NStoreOpts = {}): Promise<DittoEvent[]> { async query(filters: NostrFilter[], opts: NStoreOpts = {}): Promise<DittoEvent[]> {
filters = normalizeFilters(filters); // Improves performance of `{ kinds: [0], authors: ['...'] }` queries. filters = await this.expandFilters(filters);
if (opts.signal?.aborted) return Promise.resolve([]); if (opts.signal?.aborted) return Promise.resolve([]);
if (!filters.length) return Promise.resolve([]); if (!filters.length) return Promise.resolve([]);