Skip to content

feat(api): fall back to main in content routes - #278

Open
bbornino wants to merge 1 commit into
playfulprogramming:mainfrom
bbornino:feature/244-branch-fallback
Open

bbornino wants to merge 1 commit into
playfulprogramming:mainfrom
bbornino:feature/244-branch-fallback

Conversation

@bbornino

Copy link
Copy Markdown
Contributor

Closes #244. Follows #277.

Content routes now return main's row when the requested branch has no row for a slug. This follows the two answers from Discord: the branch decides which row is used and the publishedAt and noindex filters apply to that row afterwards, and the fallback stays on db.query with a second round trip instead of a single statement.

How it works

  • Single-item routes (/content/post/:slug, /content/authors/:slug) look up the requested branch, then main.
  • List routes (/content/posts, /content/collections, /content/authors) first fetch the slugs that exist on the requested branch, with no publish or noindex filter. The existing query then takes rows on the requested branch, or rows on main whose slug is not in that set. Filters, sorting and paging are unchanged and stay on that query.
  • Chapters and versions use the same rule, so a post the branch moved to another collection or group does not show main's copy.
  • A post's authors and collection are read from both branches and narrowed to one row per slug in pickBranchRows.
  • When the branch is main, none of the extra queries run.
  • The shared helpers are in content/common.ts.

Also changed

  • chapterCount used to count posts across every branch and locale. It now counts published chapters for the requested locale after branch resolution.
  • The nested authors relation on the post, posts and collections routes had no branch filter, so a post could get one author row per branch. It is now one row per author.

Testing

  • pnpm test:unit passes.
  • The helpers are unit tested on real row objects, and the core-builder condition is rendered to SQL in the tests.
  • The route tests mock the database, so I also ran the real route handlers against a throwaway Postgres database seeded with these cases on main, pull/42 and pull/7: only on main, edited on the branch, unpublished on the branch but published on main, noindex on the branch, moved out of its collection on the branch, and only on a third branch. All results matched the unit tests, and paging /content/posts with a small limit returned each slug once. The schema for that run came from drizzle-kit push, because the migrations fail on a fresh database on main (the misty_stick primary key, which Implement same-image e2e testing using mockhttp + self-signed cert #262 fixes).

Known gaps

  • A post deleted on a PR branch still shows main's copy on that branch, since there is no row to say it was removed.
  • No locale fallback.
  • A slug that exists only on some third branch is never returned.

Questions

  • A post that is noindex on the branch is still returned by /content/post/:slug, still listed as a chapter, and still counted in chapterCount. That matches main today. Should chapters and chapterCount exclude noindex posts?
  • /content/collections has no orderBy, so its paging order is not deterministic. That predates this PR. Want it fixed here or as a separate issue?

Content routes now return main's row when the requested branch has no
row for a slug. The branch decides which row is used; publishedAt and
noindex filters apply to that row afterwards, so a post that is
unpublished or noindex on a branch stays hidden there.

- Single-item routes look up the requested branch, then main.
- List routes fetch the branch's slugs, then query the branch's rows
  plus main's rows for every other slug.
- Chapters and versions use the same rule, so a post the branch moved
  to another collection or group no longer shows main's copy.
- Related authors and a post's collection are read from both branches
  and narrowed to one row per slug.
- chapterCount now counts published chapters for the requested locale
  after branch resolution, instead of posts across every branch and
  locale.

Closes playfulprogramming#244
@coderabbitai

coderabbitai Bot commented Oct 11, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 76baaeb0-ce14-4c8e-bc17-07764ece1c16

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

Implement branch-aware routing across content endpoints

1 participant