fix: search profiles with offset pagination

This commit is contained in:
P. Reis 2024-10-23 20:37:31 -03:00
parent 28b874edc9
commit 994dff8e79
3 changed files with 31 additions and 9 deletions

View file

@ -20,6 +20,7 @@ const searchQuerySchema = z.object({
following: z.boolean().default(false), following: z.boolean().default(false),
account_id: n.id().optional(), account_id: n.id().optional(),
limit: z.coerce.number().catch(20).transform((value) => Math.min(Math.max(value, 0), 40)), limit: z.coerce.number().catch(20).transform((value) => Math.min(Math.max(value, 0), 40)),
offset: z.coerce.number().nonnegative().catch(0),
}); });
type SearchQuery = z.infer<typeof searchQuerySchema>; type SearchQuery = z.infer<typeof searchQuerySchema>;
@ -77,7 +78,7 @@ const searchController: AppController = async (c) => {
/** Get events for the search params. */ /** Get events for the search params. */
async function searchEvents( async function searchEvents(
{ q, type, limit, account_id, viewerPubkey }: SearchQuery & { viewerPubkey?: string }, { q, type, limit, offset, account_id, viewerPubkey }: SearchQuery & { viewerPubkey?: string },
signal: AbortSignal, signal: AbortSignal,
): Promise<NostrEvent[]> { ): Promise<NostrEvent[]> {
// Hashtag search is not supported. // Hashtag search is not supported.
@ -98,7 +99,7 @@ async function searchEvents(
const kysely = await Storages.kysely(); const kysely = await Storages.kysely();
const followedPubkeys = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set<string>(); const followedPubkeys = viewerPubkey ? await getFollowedPubkeys(viewerPubkey) : new Set<string>();
const searchPubkeys = await getPubkeysBySearch(kysely, { q, limit, followedPubkeys }); const searchPubkeys = await getPubkeysBySearch(kysely, { q, limit, offset, followedPubkeys });
filter.authors = [...searchPubkeys]; filter.authors = [...searchPubkeys];
filter.search = undefined; filter.search = undefined;

View file

@ -14,17 +14,37 @@ Deno.test('fuzzy search works', async () => {
following_count: 0, following_count: 0,
}).execute(); }).execute();
assertEquals(await getPubkeysBySearch(db.kysely, { q: 'pat rick', limit: 1, followedPubkeys: new Set() }), new Set());
assertEquals( assertEquals(
await getPubkeysBySearch(db.kysely, { q: 'patrick dosreis', limit: 1, followedPubkeys: new Set() }), await getPubkeysBySearch(db.kysely, { q: 'pat rick', limit: 1, offset: 0, followedPubkeys: new Set() }),
new Set(),
);
assertEquals(
await getPubkeysBySearch(db.kysely, { q: 'patrick dosreis', limit: 1, offset: 0, followedPubkeys: new Set() }),
new Set([ new Set([
'47259076c85f9240e852420d7213c95e95102f1de929fb60f33a2c32570c98c4', '47259076c85f9240e852420d7213c95e95102f1de929fb60f33a2c32570c98c4',
]), ]),
); );
assertEquals( assertEquals(
await getPubkeysBySearch(db.kysely, { q: 'dosreis.com', limit: 1, followedPubkeys: new Set() }), await getPubkeysBySearch(db.kysely, { q: 'dosreis.com', limit: 1, offset: 0, followedPubkeys: new Set() }),
new Set([ new Set([
'47259076c85f9240e852420d7213c95e95102f1de929fb60f33a2c32570c98c4', '47259076c85f9240e852420d7213c95e95102f1de929fb60f33a2c32570c98c4',
]), ]),
); );
}); });
Deno.test('fuzzy search works with offset', async () => {
await using db = await createTestDB();
await db.kysely.insertInto('author_stats').values({
pubkey: '47259076c85f9240e852420d7213c95e95102f1de929fb60f33a2c32570c98c4',
search: 'abdcef patrickReiis patrickdosreis.com',
notes_count: 0,
followers_count: 0,
following_count: 0,
}).execute();
assertEquals(
await getPubkeysBySearch(db.kysely, { q: 'dosreis.com', limit: 1, offset: 1, followedPubkeys: new Set() }),
new Set(),
);
});

View file

@ -5,9 +5,9 @@ import { DittoTables } from '@/db/DittoTables.ts';
/** Get pubkeys whose name and NIP-05 is similar to 'q' */ /** Get pubkeys whose name and NIP-05 is similar to 'q' */
export async function getPubkeysBySearch( export async function getPubkeysBySearch(
kysely: Kysely<DittoTables>, kysely: Kysely<DittoTables>,
opts: { q: string; limit: number; followedPubkeys: Set<string> }, opts: { q: string; limit: number; offset: number; followedPubkeys: Set<string> },
): Promise<Set<string>> { ): Promise<Set<string>> {
const { q, limit, followedPubkeys } = opts; const { q, limit, followedPubkeys, offset } = opts;
let query = kysely let query = kysely
.selectFrom('author_stats') .selectFrom('author_stats')
@ -19,7 +19,8 @@ export async function getPubkeysBySearch(
.where(() => sql`${q} <% search`) .where(() => sql`${q} <% search`)
.orderBy(['followers_count desc']) .orderBy(['followers_count desc'])
.orderBy(['sml desc', 'search']) .orderBy(['sml desc', 'search'])
.limit(limit); .limit(limit)
.offset(offset);
const pubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey)); const pubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey));
@ -29,5 +30,5 @@ export async function getPubkeysBySearch(
const followingPubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey)); const followingPubkeys = new Set((await query.execute()).map(({ pubkey }) => pubkey));
return new Set(Array.from(followingPubkeys.union(pubkeys)).slice(0, limit)); return new Set(Array.from(followingPubkeys.union(pubkeys)));
} }