refactor(db): auto-generate migration registry (closes #24) #25

Merged
lz merged 3 commits from feat/proper-db into main 2026-05-30 23:14:07 +02:00
Owner

Closes #24.

Summary

The two call sites that knew the migration list — nexus/src/lib/server/db/migrate.ts and nexus/src/lib/server/testing/db.ts — now both consume migrations.generated.ts, written by nexus/scripts/gen-migrations.mjs from a readdir of nexus/migrations/. Adding a migration is now just dropping the file.

Why not switch to Drizzle (despite the issue title)

Independent research turned up that Drizzle has the same constraint under bundled deployment: its own docs prescribe a generated index module fed through Babel's inline-import plugin, so the registry doesn't disappear — it just changes shape. Meanwhile Kysely has the stronger type-safety story for our strict-mode + noUncheckedIndexedAccess setup, and there is no Kysely → Drizzle codemod, so a swap would mean rewriting every query call site for zero ergonomic gain.

Sources consulted (June 2025 marmelab comparison, April 2025 DEV piece, Kysely issue #23, Drizzle Expo SQLite guide) all point at codegen as the right minimal fix.

What's in this PR

  • nexus/scripts/gen-migrations.mjs — scans nexus/migrations/*.ts, emits migrations.generated.ts with a Record<string, Migration>. Idempotent: skips writing when content is unchanged.
  • nexus/src/lib/server/db/migrate.ts — imports the generated registry; the inline list is gone.
  • nexus/src/lib/server/testing/db.ts — same, plus the sequential await up0001(db); … chain is replaced by for (const m of Object.values(migrations)) await m.up(db).
  • Wire-up: called from vite.config.ts and vitest.config.ts at top-level (covers pnpm dev, vite build, and pnpm test), and prepended to build:server in package.json for the esbuild path.
  • .gitignore ignores the generated file.
  • Dockerfile comment updated — it claimed "vite statically bundles" when it's actually esbuild, and now via codegen.

Test plan

  • pnpm typecheck — 842 files, 0 errors
  • pnpm test — 47 files, 474 tests, all green
  • pnpm run build:server — deleted the generated file first; codegen regenerated it and esbuild produced build/server.js (59.7 kb)
  • Smoke docker compose up -d and confirm migrations apply on a fresh data volume
Closes #24. ## Summary The two call sites that knew the migration list — `nexus/src/lib/server/db/migrate.ts` and `nexus/src/lib/server/testing/db.ts` — now both consume `migrations.generated.ts`, written by `nexus/scripts/gen-migrations.mjs` from a `readdir` of `nexus/migrations/`. Adding a migration is now just dropping the file. ## Why not switch to Drizzle (despite the issue title) Independent research turned up that Drizzle has the **same constraint** under bundled deployment: its own docs prescribe a generated index module fed through Babel's `inline-import` plugin, so the registry doesn't disappear — it just changes shape. Meanwhile Kysely has the stronger type-safety story for our strict-mode + `noUncheckedIndexedAccess` setup, and there is no Kysely → Drizzle codemod, so a swap would mean rewriting every query call site for zero ergonomic gain. Sources consulted (June 2025 marmelab comparison, April 2025 DEV piece, Kysely issue #23, Drizzle Expo SQLite guide) all point at codegen as the right minimal fix. ## What's in this PR - `nexus/scripts/gen-migrations.mjs` — scans `nexus/migrations/*.ts`, emits `migrations.generated.ts` with a `Record<string, Migration>`. Idempotent: skips writing when content is unchanged. - `nexus/src/lib/server/db/migrate.ts` — imports the generated registry; the inline list is gone. - `nexus/src/lib/server/testing/db.ts` — same, plus the sequential `await up0001(db); …` chain is replaced by `for (const m of Object.values(migrations)) await m.up(db)`. - Wire-up: called from `vite.config.ts` and `vitest.config.ts` at top-level (covers `pnpm dev`, `vite build`, and `pnpm test`), and prepended to `build:server` in `package.json` for the esbuild path. - `.gitignore` ignores the generated file. - Dockerfile comment updated — it claimed "vite statically bundles" when it's actually esbuild, and now via codegen. ## Test plan - [x] `pnpm typecheck` — 842 files, 0 errors - [x] `pnpm test` — 47 files, 474 tests, all green - [x] `pnpm run build:server` — deleted the generated file first; codegen regenerated it and esbuild produced `build/server.js` (59.7 kb) - [ ] Smoke `docker compose up -d` and confirm migrations apply on a fresh data volume
refactor(db): auto-generate migration registry (closes #24)
Some checks failed
ci / nexus (pull_request) Failing after 1m22s
ci / images (./nexus, agent-nexus) (pull_request) Has been skipped
ci / images (./worker, nexus-worker) (pull_request) Has been skipped
a47fe0b3bb
The two call sites that knew the migration list — `migrate.ts` and
`testing/db.ts` — now both consume `migrations.generated.ts`, written by
`scripts/gen-migrations.mjs` from a `readdir` of `nexus/migrations/`.

Why not switch ORM: Drizzle has the same bundled-deploy constraint (its
own docs prescribe a generated index module via babel inline-import), and
swapping would mean a rewrite of every Kysely call site for no
ergonomic gain. Codegen is the minimal fix.

Wired into `vite.config.ts`, `vitest.config.ts`, and prepended to
`build:server` so the file exists before any bundler resolves it. The
generated file is `.gitignore`d.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into feat/proper-db
Some checks are pending
ci / nexus (pull_request) Waiting to run
ci / images (./nexus, agent-nexus) (pull_request) Blocked by required conditions
ci / images (./worker, agent-nexus-worker, base) (pull_request) Blocked by required conditions
ci / images (PLAYWRIGHT_CLI_VERSION=0.1.13, ./worker, agent-nexus-worker, -playwright0.1.13, playwright) (pull_request) Blocked by required conditions
ba15ab2052
# Conflicts:
#	.gitignore
#	nexus/src/lib/server/db/migrate.ts
#	nexus/src/lib/server/testing/db.ts
fix(db): exclude *.test.ts from generated migration registry
Some checks failed
ci / nexus (pull_request) Failing after 2m7s
ci / images (./nexus, agent-nexus) (pull_request) Has been skipped
ci / images (./worker, agent-nexus-worker, base) (pull_request) Has been skipped
ci / images (PLAYWRIGHT_CLI_VERSION=0.1.13, ./worker, agent-nexus-worker, -playwright0.1.13, playwright) (pull_request) Has been skipped
4886733615
Co-located migration tests (0010/0011) matched the codegen glob and were
imported as migrations, breaking typecheck + the test-DB migration loop.
lz merged commit 89eaa89860 into main 2026-05-30 23:14:07 +02:00
lz referenced this pull request from a commit 2026-09-12 19:41:22 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lz/agent-nexus!25
No description provided.