diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index d3d67820..18433f1f 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -119,6 +119,7 @@ const accountSearchQuerySchema = z.object({ const accountSearchController: AppController = async (c) => { const { signal } = c.req.raw; const { limit } = c.get('pagination'); + const kysely = await Storages.kysely(); const viewerPubkey = await c.get('signer')?.getPublicKey(); @@ -136,27 +137,22 @@ const accountSearchController: AppController = async (c) => { if (!event && lookup) { const pubkey = await lookupPubkey(lookup); - return c.json(pubkey ? [await accountFromPubkey(pubkey)] : []); + return c.json(pubkey ? [accountFromPubkey(pubkey)] : []); } - const followedPubkeys: Set = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set(); - const pubkeys = Array.from(await getPubkeysBySearch(kysely, { q: query, limit, offset: 0, followedPubkeys })); + const events: NostrEvent[] = []; - let events = event ? [event] : await store.query([{ kinds: [0], authors: pubkeys, limit }], { - signal, - }); - - if (!event) { - events = pubkeys - .map((pubkey) => events.find((event) => event.pubkey === pubkey)) - .filter((event) => !!event); + if (event) { + events.push(event); + } else { + const following = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set(); + const authors = [...await getPubkeysBySearch(kysely, { q: query, limit, offset: 0, following })]; + const profiles = await store.query([{ kinds: [0], authors, limit }], { signal }); + events.push(...profiles); } - const accounts = await hydrateEvents({ events, store, signal }).then( - (events) => - Promise.all( - events.map((event) => renderAccount(event)), - ), - ); + + const accounts = await hydrateEvents({ events, store, signal }) + .then((events) => events.map((event) => renderAccount(event))); return c.json(accounts); }; diff --git a/src/utils/search.ts b/src/utils/search.ts index 29ecefd9..1c608c99 100644 --- a/src/utils/search.ts +++ b/src/utils/search.ts @@ -5,30 +5,35 @@ import { DittoTables } from '@/db/DittoTables.ts'; /** Get pubkeys whose name and NIP-05 is similar to 'q' */ export async function getPubkeysBySearch( kysely: Kysely, - opts: { q: string; limit: number; offset: number; followedPubkeys: Set }, + opts: { q: string; limit: number; offset: number; following: Set }, ): Promise> { - const { q, limit, followedPubkeys, offset } = opts; + const { q, limit, following, offset } = opts; - let query = kysely + const pubkeys = new Set(); + + const query = kysely .selectFrom('author_stats') - .select((eb) => [ - 'pubkey', - 'search', - eb.fn('word_similarity', [sql`${q}`, 'search']).as('sml'), - ]) - .where(() => sql`${q} <% search`) - .orderBy(['followers_count desc']) - .orderBy(['sml desc', 'search']) + .select('pubkey') + .where('search', sql`%>`, q) + .orderBy('followers_count desc') .limit(limit) .offset(offset); - const pubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey)); + if (following.size) { + const authorsQuery = query.where('pubkey', 'in', [...following]); - if (followedPubkeys.size > 0) { - query = query.where('pubkey', 'in', [...followedPubkeys]); + for (const { pubkey } of await authorsQuery.execute()) { + pubkeys.add(pubkey); + } } - const followingPubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey)); + if (pubkeys.size >= limit) { + return pubkeys; + } - return new Set(Array.from(followingPubkeys.union(pubkeys))); + for (const { pubkey } of await query.execute()) { + pubkeys.add(pubkey); + } + + return pubkeys; }