Skip to content

feat(bookshelf): Implement discovery query layer - #106

Merged
codenamed22 merged 6 commits into
codenamed22:mainfrom
Ivez-pop:pr5-bookshelf-discovery-query
Jul 29, 2026
Merged

codenamed22 merged 6 commits into
codenamed22:mainfrom
Ivez-pop:pr5-bookshelf-discovery-query

Conversation

@Ivez-pop

@Ivez-pop Ivez-pop commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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

  • Introduces a shared DEFAULT_PAGE_SIZE constant for consistent pagination limits.
  • Adds page parsing and validation helpers to safely normalize page parameters.

Discovery query builder

Implements a reusable query builder supporting:

  • Keyword search (title and author)
  • Resource type filtering
  • Sorting by:
    • Newest
    • Oldest
    • Title (A–Z)
    • Title (Z–A)

Paginated query APIs

Adds two new read-only query helpers:

  • getPaginatedResources
  • getPaginatedCategoryResources

Both queries:

  • Execute findMany and count inside a Prisma transaction.
  • Return pagination metadata (currentPage, total, totalPages).
  • Use lightweight list projections to avoid unnecessary data fetching.

Query-layer types

Introduces:

  • ResourceList
  • resourceListSelect

The runtime Prisma selection and inferred TypeScript payload are derived from the same definition, ensuring they remain synchronized.

Internal improvements

  • Adds buildResourcesQuery to centralize filtering and sorting logic.
  • Adds parsePage for consistent page parameter validation.
  • Refactors getResourceById to use a shared detail select without changing its behavior.

Scope

Included

  • Discovery query builder
  • Search support
  • Filtering support
  • Sorting support
  • Pagination queries
  • Pagination constants
  • Query-layer types

Not Included

  • UI components
  • Landing page changes
  • Category page changes
  • Resource detail UI
  • Admin functionality
  • Create/update/delete mutations
  • Database schema changes
  • Prisma migrations
  • Authentication changes
  • Styling changes
  • Navigation changes
  • End-to-end tests

Backward Compatibility

  • Existing query APIs remain available with unchanged behavior.
  • Existing callers continue to compile without modification.
  • No schema or migration changes are introduced.

Verification

The following checks were completed successfully:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm test
  • npm run build

This PR is intentionally limited to the backend discovery query layer and is ready for review.

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

@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 Gotnochill left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 .

Comment thread lib/bookshelf/queries.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Comment thread lib/bookshelf/queries.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Ivez-pop
Ivez-pop force-pushed the pr5-bookshelf-discovery-query branch from e601344 to e06b78b Compare July 8, 2026 18:35
Comment thread lib/bookshelf/queries.ts

@Gotnochill Gotnochill Jul 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Navneet and others added 3 commits July 29, 2026 12:48
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.
@codenamed22
codenamed22 merged commit 850646a into codenamed22:main Jul 29, 2026
2 of 3 checks passed
@Ivez-pop
Ivez-pop deleted the pr5-bookshelf-discovery-query branch August 31, 2026 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants