Repository navigation
Conversation
Adds npx-runnable CLI (bin: convex-migrations) with a create command: --rename-field table.old=new and --rename-table old=new scaffold the documented migration patterns non-interactively; with no flags it prompts. Detects a missing component setup (no migrations entry in convex.config.ts) and prints the install/config steps instead of failing. --json emits an agent-friendly summary. Suggested by @ianmacartney in convex/convex-backend#477.
📝 WalkthroughWalkthroughThis PR adds a new Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as cli.ts / main.ts
participant Generator as generator.ts
participant FS as convex/migrations.ts
User->>CLI: convex-migrations create [--rename-field/--rename-table]
CLI->>CLI: parseArgs / buildCreateRequest
alt flags supplied
CLI->>Generator: render*Migration(spec)
else interactive prompt
CLI->>User: prompt for kind, values, name
User-->>CLI: input
CLI->>Generator: render*Migration(spec)
end
Generator-->>CLI: GeneratedMigration { name, definition }
CLI->>FS: detect convex.config, check existing exports
CLI->>FS: create or append migrations.ts
CLI-->>User: success message / JSON output or error
Compact metadata:
Related issues: None specified in provided summaries. Related PRs: None specified in provided summaries. Suggested labels: enhancement, cli Suggested reviewers: None specified in provided summaries. 🐰 A rabbit taps a fresh new key, 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/cli/generator.test.ts (1)
1-69: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding coverage for
renderCustomMigration, parse-error paths, andtoExportNameedge cases.Current tests only cover the happy paths for
renderRenameFieldMigration/renderRenameTableMigration. Missing coverage:renderCustomMigration,parseRenameFieldSpec/parseRenameTableSpecerror cases (malformed input, same old/new value), andtoExportName's reserved-word/non-identifier fallback branches — all of which contain non-trivial logic.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/generator.test.ts` around lines 1 - 69, Add tests to cover the missing generator branches: use the existing generator helpers in generator.test.ts to exercise renderCustomMigration, and add cases for parseRenameFieldSpec and parseRenameTableSpec that verify malformed input and same old/new value errors. Also add focused tests for toExportName covering reserved words and invalid identifiers so the fallback naming path is validated alongside the current happy-path rename migration coverage.src/cli/generator.ts (1)
122-144: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winRename-table scaffold changes document IDs — worth calling out.
The generated migration inserts a new document and deletes the old one, so any other document that stores an
Id<oldTable>(viav.id(...)) will silently point to a non-existent document after the migration runs. This matches Convex's documented workaround for the lack of native table renames — confirmed by Convex's own community: Renaming columns or tables requires a flow like add‑new‑field + migrate + remove‑old‑field which can get rough when using an entire new terminology over the system. Since this is inherent to the pattern (not a bug), consider emitting a comment in the generated scaffold warning that references to the old table's IDs will break, so first-time users of this CLI aren't caught off guard.💡 Suggested comment addition
const definition = `export const ${toExportName(name)} = migrations.define({ table: ${quote(oldTable)}, + // NOTE: this creates new documents with new _ids in ${quote(newTable)}. + // Any other documents referencing ${quote(oldTable)} ids will need to be updated separately. migrateOne: async (ctx, doc) => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/generator.ts` around lines 122 - 144, The rename-table migration scaffold in renderRenameTableMigration should warn that it replaces documents, not just renames them. Add a generated comment near the migration definition explaining that inserting into the new table and deleting from the old one will invalidate any stored Id<oldTable> references (for example via v.id), and point users to the need to update dependent fields before running the migration.src/cli/main.ts (1)
105-134: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winInconsistent JSON output shape between success and error.
On success,
JSON.stringify(result, null, 2)has nook/successdiscriminator, but the error path returns{ ok: false, error: ... }. A consumer of--jsonoutput parsing for machine-readable results has to rely on exit code alone to distinguish success/failure rather than a uniform schema — this undercuts the "machine-readable success summaries" goal called out in the PR.♻️ Suggested fix
if (parsed.json) { - writeLine(io.stdout, JSON.stringify(result, null, 2)); + writeLine(io.stdout, JSON.stringify({ ok: true, ...result }, null, 2)); } else {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/main.ts` around lines 105 - 134, The JSON output from the CLI is inconsistent between success and failure in main(): success writes the raw createMigration result, while the error path wraps the message in an { ok: false, error: ... } object. Update the parsed.json branch in the try path to emit a uniform machine-readable schema with an explicit success discriminator (for example, matching the error shape with ok/success plus the result payload), so consumers can reliably parse both outcomes without depending only on exit code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/cli/generator.test.ts`:
- Around line 1-69: Add tests to cover the missing generator branches: use the
existing generator helpers in generator.test.ts to exercise
renderCustomMigration, and add cases for parseRenameFieldSpec and
parseRenameTableSpec that verify malformed input and same old/new value errors.
Also add focused tests for toExportName covering reserved words and invalid
identifiers so the fallback naming path is validated alongside the current
happy-path rename migration coverage.
In `@src/cli/generator.ts`:
- Around line 122-144: The rename-table migration scaffold in
renderRenameTableMigration should warn that it replaces documents, not just
renames them. Add a generated comment near the migration definition explaining
that inserting into the new table and deleting from the old one will invalidate
any stored Id<oldTable> references (for example via v.id), and point users to
the need to update dependent fields before running the migration.
In `@src/cli/main.ts`:
- Around line 105-134: The JSON output from the CLI is inconsistent between
success and failure in main(): success writes the raw createMigration result,
while the error path wraps the message in an { ok: false, error: ... } object.
Update the parsed.json branch in the try path to emit a uniform machine-readable
schema with an explicit success discriminator (for example, matching the error
shape with ok/success plus the result payload), so consumers can reliably parse
both outcomes without depending only on exit code.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: get-convex/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6ed1c79f-3b96-498d-a7ee-d9087199f5b3
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
eslint.config.jspackage.jsonsrc/cli.tssrc/cli/generator.test.tssrc/cli/generator.tssrc/cli/main.ts
commit: |
The generated migration copies each document into the new table, so it gets a new _id and any v.id(oldTable) reference elsewhere goes stale. Say so in the generated code.
|
Following up on the CodeRabbit note about rename-table changing document IDs: 5356804 puts that warning in the generated code. The scaffold now says that copying gives each document a new |
Summary
Adds a
createCLI to the migrations component, per @ianmacartney's suggestion on convex/convex-backend#477:What it does
npx @convex-dev/migrations create [name] --rename-field users.oldName=newNamescaffolds a field-rename migration (copy old to new, unset old) without prompting--rename-table old=newscaffolds the documented table-rename patternconvex.config.tshas no migrations entry, the CLI prints the install/config steps instead of failing opaquely--jsonprints a machine-readable success summary so agents can consume itTesting
npm run build,npm run typecheck,npm run lintpass--rename-fieldscaffold generation into a bare project, setup detection, and--jsonoutputRefs convex/convex-backend#477