From c03fcecd0547ca0d35e5aa435113bf79909f5233 Mon Sep 17 00:00:00 2001 From: Devin Ivy Date: Wed, 31 Jan 2024 16:05:53 -0500 Subject: [PATCH] support feed search on getPopularFeedGenerators --- .../unspecced/getPopularFeedGenerators.ts | 28 +++++++++++++----- .../src/data-plane/server/routes/feed-gens.ts | 25 +++++++++++++++- .../feed-generation.test.ts.snap | 1 + packages/bsky/tests/feed-generation.test.ts | 29 ++++++++++++------- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/packages/bsky/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/bsky/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts index 55263e8483a..a5a3d8a8cef 100644 --- a/packages/bsky/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/bsky/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -20,12 +20,26 @@ export default function (server: Server, ctx: AppContext) { } } - const suggestedRes = await ctx.dataplane.getSuggestedFeeds({ - actorDid: viewer ?? undefined, - limit: params.limit, - cursor: params.cursor, - }) - const uris = suggestedRes.uris + let uris: string[] + let cursor: string | undefined + + const query = params.query?.trim() ?? '' + if (query) { + const res = await ctx.dataplane.searchFeedGenerators({ + query, + limit: params.limit, + }) + uris = res.uris + } else { + const res = await ctx.dataplane.getSuggestedFeeds({ + actorDid: viewer ?? undefined, + limit: params.limit, + cursor: params.cursor, + }) + uris = res.uris + cursor = parseString(res.cursor) + } + const hydration = await ctx.hydrator.hydrateFeedGens(uris, viewer) const feedViews = mapDefined(uris, (uri) => ctx.views.feedGenerator(uri, hydration), @@ -35,7 +49,7 @@ export default function (server: Server, ctx: AppContext) { encoding: 'application/json', body: { feeds: feedViews, - cursor: parseString(suggestedRes.cursor), + cursor, }, } }, diff --git a/packages/bsky/src/data-plane/server/routes/feed-gens.ts b/packages/bsky/src/data-plane/server/routes/feed-gens.ts index adaff47d3e3..129229f923f 100644 --- a/packages/bsky/src/data-plane/server/routes/feed-gens.ts +++ b/packages/bsky/src/data-plane/server/routes/feed-gens.ts @@ -30,14 +30,37 @@ export default (db: Database): Partial> => ({ } }, - async getSuggestedFeeds() { + async getSuggestedFeeds(req) { const feeds = await db.db .selectFrom('suggested_feed') .orderBy('suggested_feed.order', 'asc') + .if(!!req.cursor, (q) => q.where('order', '>', parseInt(req.cursor, 10))) + .limit(req.limit || 50) .selectAll() .execute() return { uris: feeds.map((f) => f.uri), + cursor: feeds.at(-1)?.order.toString(), + } + }, + + async searchFeedGenerators(req) { + const { ref } = db.db.dynamic + const limit = req.limit + const query = req.query.trim() + let builder = db.db + .selectFrom('feed_generator') + .if(!!query, (q) => q.where('displayName', 'ilike', `%${query}%`)) + .selectAll() + const keyset = new TimeCidKeyset( + ref('feed_generator.createdAt'), + ref('feed_generator.cid'), + ) + builder = paginate(builder, { limit, keyset }) + const feeds = await builder.execute() + return { + uris: feeds.map((f) => f.uri), + cursor: keyset.packFromResult(feeds), } }, diff --git a/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap b/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap index 2de2fd20ffb..8aea15ddfc8 100644 --- a/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap +++ b/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap @@ -1597,6 +1597,7 @@ Object { exports[`feed generation getSuggestedFeeds returns list of suggested feed generators 1`] = ` Object { + "cursor": "4", "feeds": Array [ Object { "cid": "cids(0)", diff --git a/packages/bsky/tests/feed-generation.test.ts b/packages/bsky/tests/feed-generation.test.ts index 23cd5f1e759..00426075fe3 100644 --- a/packages/bsky/tests/feed-generation.test.ts +++ b/packages/bsky/tests/feed-generation.test.ts @@ -348,18 +348,26 @@ describe('feed generation', () => { }) }) - // @TODO support from dataplane - describe.skip('getPopularFeedGenerators', () => { + describe('getPopularFeedGenerators', () => { it('gets popular feed generators', async () => { - const resEven = - await agent.api.app.bsky.unspecced.getPopularFeedGenerators( - {}, - { headers: await network.serviceHeaders(sc.dids.bob) }, - ) - expect(resEven.data.feeds.map((f) => f.likeCount)).toEqual([ - 2, 0, 0, 0, 0, + const res = await agent.api.app.bsky.unspecced.getPopularFeedGenerators( + {}, + { headers: await network.serviceHeaders(sc.dids.bob) }, + ) + expect(res.data.feeds.map((f) => f.uri)).not.toContain(feedUriPrime) // taken-down + expect(res.data.feeds.map((f) => f.uri)).toEqual([ + feedUriAll, + feedUriEven, + feedUriBadPagination, ]) - expect(resEven.data.feeds.map((f) => f.uri)).not.toContain(feedUriPrime) // taken-down + }) + + it('searches feed generators', async () => { + const res = await agent.api.app.bsky.unspecced.getPopularFeedGenerators( + { query: 'all' }, + { headers: await network.serviceHeaders(sc.dids.bob) }, + ) + expect(res.data.feeds.map((f) => f.uri)).toEqual([feedUriAll]) }) it('paginates', async () => { @@ -368,7 +376,6 @@ describe('feed generation', () => { {}, { headers: await network.serviceHeaders(sc.dids.bob) }, ) - const resOne = await agent.api.app.bsky.unspecced.getPopularFeedGenerators( { limit: 2 },