fix(stats): show all downloads without browse-ready filter
Downloads represent real user actions and should not be filtered by browse-ready criteria. Skills count and contributors remain filtered. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,8 @@ vi.mock('@/lib/cache', () => ({
|
||||
|
||||
// Mock the db module - must be before imports that use it
|
||||
vi.mock('@skillhub/db', () => {
|
||||
const mockStatsRow = [{ totalSkills: 100, totalDownloads: 5000, totalContributors: 50 }];
|
||||
const mockStatsRow = [{ totalSkills: 100, totalContributors: 50 }];
|
||||
const mockDownloadsRow = [{ totalDownloads: 5000 }];
|
||||
const mockCategoryRow = [{ count: 8 }];
|
||||
return {
|
||||
createDb: vi.fn(() => ({
|
||||
@@ -28,9 +29,11 @@ vi.mock('@skillhub/db', () => {
|
||||
if (table === 'categories-table') {
|
||||
return Promise.resolve(mockCategoryRow);
|
||||
}
|
||||
// skills table query has .where() chained
|
||||
// skills table: thenable for downloads (no .where()) + .where() for filtered stats
|
||||
return {
|
||||
where: vi.fn().mockResolvedValue(mockStatsRow),
|
||||
then: (resolve: (v: unknown) => void, reject: (e: unknown) => void) =>
|
||||
Promise.resolve(mockDownloadsRow).then(resolve, reject),
|
||||
};
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -37,16 +37,22 @@ export async function GET(request: NextRequest) {
|
||||
// Browse-ready filter: exclude duplicates and aggregators
|
||||
const browseReady = sql`${skills.isDuplicate} = false AND (${skills.skillType} IS NULL OR ${skills.skillType} != 'aggregator')`;
|
||||
|
||||
// Consolidate all skill stats into a single query (browse-ready only)
|
||||
// Browse-ready skill stats (skills count + contributors)
|
||||
const statsResult = await db
|
||||
.select({
|
||||
totalSkills: sql<number>`count(*)::int`,
|
||||
totalDownloads: sql<number>`coalesce(sum(${skills.downloadCount}), 0)::int`,
|
||||
totalContributors: sql<number>`count(distinct ${skills.githubOwner})::int`,
|
||||
})
|
||||
.from(skills)
|
||||
.where(browseReady);
|
||||
|
||||
// Total downloads: count ALL downloads (real user actions, not filtered)
|
||||
const downloadsResult = await db
|
||||
.select({
|
||||
totalDownloads: sql<number>`coalesce(sum(${skills.downloadCount}), 0)::int`,
|
||||
})
|
||||
.from(skills);
|
||||
|
||||
// Get category count in separate query (different table)
|
||||
const categoryResult = await db
|
||||
.select({ count: sql<number>`count(*)::int` })
|
||||
@@ -57,7 +63,7 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
const data: StatsData = {
|
||||
totalSkills: stats?.totalSkills ?? 0,
|
||||
totalDownloads: stats?.totalDownloads ?? 0,
|
||||
totalDownloads: downloadsResult[0]?.totalDownloads ?? 0,
|
||||
totalCategories,
|
||||
totalContributors: stats?.totalContributors ?? 0,
|
||||
platforms: 5, // Claude, Codex, Copilot, Cursor, Windsurf
|
||||
|
||||
Reference in New Issue
Block a user