feat(bookshelf): Implement discovery query layer - #106
Conversation
|
@Ivez-pop is attempting to deploy a commit to the codenamed22's projects Team on Vercel. A member of the Team first needs to authorize it. |
Gotnochill
left a comment
There was a problem hiding this comment.
Summary:
$transaction used for two independent reads; should be Promise.all
Every other $transaction call in this codebase wraps writes (badges, cohort, contest, apply). Using it for [findMany, count] wraps both reads in a BEGIN/COMMIT on PostgreSQL, unnecessary overhead when the two queries are independent and no atomicity is needed. The idiomatic form:
prisma.resource.findMany({ ... }),
prisma.resource.count({ where }),
]);
Same issue in getPaginatedCategoryResources .
There was a problem hiding this comment.
Summary:
getRecentResources and getResourcesByCategory still use inline selects identical to resourceListSelect
The PR extracts resourceListSelect precisely to avoid this duplication, but both pre-existing functions were left with the old inline form. Both functions should use select: resourceListSelect instead; otherwise, adding a field to resourceListSelect (e.g., categoryId) won't propagate to these functions, and callers will get inconsistent shapes.
Fix:
getRecentResources - change to:
select: resourceListSelect,
getResourcesByCategory - change to:
select: resourceListSelect,
There was a problem hiding this comment.
Summary:
totalPages is 0 when the result set is empty, but currentPage is always ≥ 1
Math.ceil(0 / 6) === 0 , so when no resources match the query, the return value is
{ total: 0, totalPages: 0, currentPage: 1 }.
Any UI rendering "Page 1 of 0" or using currentPage < totalPages to gate a Next button will misbehave.
Fix:
const totalPages = Math.max(1, Math.ceil(total / limit));
Same issue on line ~215.
Fix it now so problems don't arise when the UI layer is pushed.
e601344 to
e06b78b
Compare
There was a problem hiding this comment.
Prisma and ResourceType are still imported from @prisma/client but the entire codebase has migrated to @/prisma-client as part of the Prisma 7 upgrade (see lib/bookshelf/types.ts in this same PR which already uses the new path).
Please update this import to match:
import { Prisma, ResourceType } from "@/prisma-client";
@Ivez-pop See this:
All 5 e2e failures trace back to the exact same root cause — the one import I flagged. Every bookshelf page crashes at startup with:
Cannot find module '.prisma/client/default'
because queries.ts imports Prisma and ResourceType from @prisma/client, which no longer resolves after the Prisma 7 upgrade. The server throws a 500 on every bookshelf route, hence "Server Error" instead of the page, and 500s instead of 404s.
The typecheck confirms the same thing:
error TS2305: Module '"@prisma/client"' has no exported member 'Prisma'.
error TS2305: Module '"@prisma/client"' has no exported member 'ResourceType'.
One line change in lib/bookshelf/queries.ts line 9 fixes everything:
// before
import { Prisma, ResourceType } from "@prisma/client";
// after
import { Prisma, ResourceType } from "@/prisma-client";
That's the only change needed. All 5 failing tests will pass once this is pushed.
The generated Prisma client lives at lib/generated/prisma (aliased as @/prisma-client), not @prisma/client, so the original import failed typecheck. Align with the rest of the codebase.
Summary
Implements the backend discovery query layer for the Bookshelf feature.
This PR introduces reusable query infrastructure for resource discovery, including search, filtering, sorting, and pagination, while preserving all existing read APIs for backward compatibility. It is intentionally limited to the data access layer and does not introduce any UI, routing, schema, or migration changes.
What this PR adds
Pagination infrastructure
DEFAULT_PAGE_SIZEconstant for consistent pagination limits.Discovery query builder
Implements a reusable query builder supporting:
Paginated query APIs
Adds two new read-only query helpers:
getPaginatedResourcesgetPaginatedCategoryResourcesBoth queries:
findManyandcountinside a Prisma transaction.currentPage,total,totalPages).Query-layer types
Introduces:
ResourceListresourceListSelectThe runtime Prisma selection and inferred TypeScript payload are derived from the same definition, ensuring they remain synchronized.
Internal improvements
buildResourcesQueryto centralize filtering and sorting logic.parsePagefor consistent page parameter validation.getResourceByIdto use a shared detail select without changing its behavior.Scope
Included
Not Included
Backward Compatibility
Verification
The following checks were completed successfully:
npm run format:checknpm run lintnpm run typechecknpm testnpm run buildThis PR is intentionally limited to the backend discovery query layer and is ready for review.