Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions convex/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ const skills = defineTable({
.index('by_stats_installs_all_time', ['statsInstallsAllTime', 'updatedAt'])
.index('by_batch', ['batch'])
.index('by_active_updated', ['softDeletedAt', 'updatedAt'])
.index('by_active_created', ['softDeletedAt', 'createdAt'])
.index('by_active_name', ['softDeletedAt', 'displayName'])
.index('by_active_stats_downloads', ['softDeletedAt', 'statsDownloads', 'updatedAt'])
.index('by_active_stats_stars', ['softDeletedAt', 'statsStars', 'updatedAt'])
.index('by_active_stats_installs_all_time', ['softDeletedAt', 'statsInstallsAllTime', 'updatedAt'])

const souls = defineTable({
slug: v.string(),
Expand Down
39 changes: 30 additions & 9 deletions convex/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,23 +720,44 @@ export const listPublicPage = query({
export const listPublicPageV2 = query({
args: {
paginationOpts: paginationOptsValidator,
sort: v.optional(
v.union(
v.literal('newest'),
v.literal('updated'),
v.literal('downloads'),
v.literal('installs'),
v.literal('stars'),
v.literal('name'),
),
),
dir: v.optional(v.union(v.literal('asc'), v.literal('desc'))),
},
handler: async (ctx, args) => {
// Use the new index to filter out soft-deleted skills at query time.
// softDeletedAt === undefined means active (non-deleted) skills only.
const sort = args.sort ?? 'newest'
const dir = args.dir ?? 'desc'

const indexName =
sort === 'newest'
? 'by_active_created'
: sort === 'updated'
? 'by_active_updated'
: sort === 'name'
? 'by_active_name'
: sort === 'downloads'
? 'by_active_stats_downloads'
: sort === 'stars'
? 'by_active_stats_stars'
: 'by_active_stats_installs_all_time'

const result = await paginator(ctx.db, schema)
.query('skills')
.withIndex('by_active_updated', (q) => q.eq('softDeletedAt', undefined))
.order('desc')
.withIndex(indexName, (q) => q.eq('softDeletedAt', undefined))
.order(dir)
.paginate(args.paginationOpts)

// Build the public skill entries (fetch latestVersion + ownerHandle)
const items = await buildPublicSkillEntries(ctx, result.page)

return {
...result,
page: items,
}
return { ...result, page: items }
},
})

Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/skills-index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ describe('SkillsIndex', () => {

it('requests the first skills page', () => {
render(<SkillsIndex />)
// usePaginatedQuery should be called with the API endpoint and empty args
// usePaginatedQuery should be called with the API endpoint and sort/dir args
expect(usePaginatedQueryMock).toHaveBeenCalledWith(
expect.anything(),
{},
{ sort: 'newest', dir: 'desc' },
{ initialNumItems: 25 },
)
})
Expand Down
2 changes: 1 addition & 1 deletion src/routes/skills/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function SkillsIndex() {
results: paginatedResults,
status: paginationStatus,
loadMore: loadMorePaginated,
} = usePaginatedQuery(api.skills.listPublicPageV2, hasQuery ? 'skip' : {}, {
} = usePaginatedQuery(api.skills.listPublicPageV2, hasQuery ? 'skip' : { sort, dir }, {
initialNumItems: pageSize,
})

Expand Down