SearchStorage: make author relations work

This commit is contained in:
Alex Gleason 2024-01-04 00:52:55 -06:00
parent 6d80b43335
commit d170eb6d8e
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 27 additions and 3 deletions

View File

@ -2,7 +2,9 @@ import { Conf } from '@/config.ts';
import { db } from '@/db.ts'; import { db } from '@/db.ts';
import { EventsDB } from '@/storages/events-db.ts'; import { EventsDB } from '@/storages/events-db.ts';
import { Memorelay } from '@/storages/memorelay.ts'; import { Memorelay } from '@/storages/memorelay.ts';
import { Optimizer } from '@/storages/optimizer.ts';
import { SearchStore } from '@/storages/search-store.ts'; import { SearchStore } from '@/storages/search-store.ts';
import { reqmeister } from '@/reqmeister.ts';
/** SQLite database to store events this Ditto server cares about. */ /** SQLite database to store events this Ditto server cares about. */
const eventsDB = new EventsDB(db); const eventsDB = new EventsDB(db);
@ -10,10 +12,17 @@ const eventsDB = new EventsDB(db);
/** In-memory data store for cached events. */ /** In-memory data store for cached events. */
const memorelay = new Memorelay({ max: 3000 }); const memorelay = new Memorelay({ max: 3000 });
/** Main Ditto storage adapter */
const optimizer = new Optimizer({
db: eventsDB,
cache: memorelay,
client: reqmeister,
});
/** Storage to use for remote search. */ /** Storage to use for remote search. */
const searchStore = new SearchStore({ const searchStore = new SearchStore({
relay: Conf.searchRelay, relay: Conf.searchRelay,
fallback: eventsDB, fallback: optimizer,
}); });
export { eventsDB, memorelay, searchStore }; export { eventsDB, memorelay, optimizer, searchStore };

View File

@ -1,3 +1,4 @@
import { Debug } from '@/deps.ts';
import { type DittoFilter, normalizeFilters } from '@/filter.ts'; import { type DittoFilter, normalizeFilters } from '@/filter.ts';
import { EventSet } from '@/utils/event-set.ts'; import { EventSet } from '@/utils/event-set.ts';
@ -10,6 +11,8 @@ interface OptimizerOpts {
} }
class Optimizer implements EventStore { class Optimizer implements EventStore {
#debug = Debug('ditto:optimizer');
#db: EventStore; #db: EventStore;
#cache: EventStore; #cache: EventStore;
#client: EventStore; #client: EventStore;
@ -33,6 +36,8 @@ class Optimizer implements EventStore {
filters: DittoFilter<K>[], filters: DittoFilter<K>[],
opts: GetEventsOpts | undefined = {}, opts: GetEventsOpts | undefined = {},
): Promise<DittoEvent<K>[]> { ): Promise<DittoEvent<K>[]> {
this.#debug('REQ', JSON.stringify(filters));
const { limit = Infinity } = opts; const { limit = Infinity } = opts;
filters = normalizeFilters(filters); filters = normalizeFilters(filters);
@ -45,6 +50,7 @@ class Optimizer implements EventStore {
for (let i = 0; i < filters.length; i++) { for (let i = 0; i < filters.length; i++) {
const filter = filters[i]; const filter = filters[i];
if (filter.ids) { if (filter.ids) {
this.#debug(`Filter[${i}] is an IDs filter; querying cache...`);
const ids = new Set<string>(filter.ids); const ids = new Set<string>(filter.ids);
for (const event of await this.#cache.getEvents([filter], opts)) { for (const event of await this.#cache.getEvents([filter], opts)) {
ids.delete(event.id); ids.delete(event.id);
@ -59,18 +65,27 @@ class Optimizer implements EventStore {
if (!filters.length) return getResults(); if (!filters.length) return getResults();
// Query the database for events. // Query the database for events.
this.#debug('Querying database...');
for (const dbEvent of await this.#db.getEvents(filters, opts)) { for (const dbEvent of await this.#db.getEvents(filters, opts)) {
results.add(dbEvent); results.add(dbEvent);
if (results.size >= limit) return getResults(); if (results.size >= limit) return getResults();
} }
// We already searched the DB, so stop if this is a search filter.
if (filters.some((filter) => typeof filter.search === 'string')) {
this.#debug(`Bailing early for search filter: "${filters[0]?.search}"`);
return getResults();
}
// Query the cache again. // Query the cache again.
this.#debug('Querying cache...');
for (const cacheEvent of await this.#cache.getEvents(filters, opts)) { for (const cacheEvent of await this.#cache.getEvents(filters, opts)) {
results.add(cacheEvent); results.add(cacheEvent);
if (results.size >= limit) return getResults(); if (results.size >= limit) return getResults();
} }
// Finally, query the client. // Finally, query the client.
this.#debug('Querying client...');
for (const clientEvent of await this.#client.getEvents(filters, opts)) { for (const clientEvent of await this.#client.getEvents(filters, opts)) {
results.add(clientEvent); results.add(clientEvent);
if (results.size >= limit) return getResults(); if (results.size >= limit) return getResults();

View File

@ -57,7 +57,7 @@ class SearchStore implements EventStore {
const authorIds = new Set([...events].map((event) => event.pubkey)); const authorIds = new Set([...events].map((event) => event.pubkey));
const authors = await this.getEvents([{ kinds: [0], authors: [...authorIds] }], opts); const authors = await this.getEvents([{ kinds: [0], authors: [...authorIds] }], opts);
for (const event of events) { for (const event of events) {
event.author = authors.find((author) => author.id === event.pubkey); event.author = authors.find((author) => author.pubkey === event.pubkey);
} }
} }