Skip to content
NewComposite primary keys6 min read

Codemod

Dry run first:

Terminal window
npx uql-codemod --dry-run
needs a decision: src/entity/audit.ts:9: cannot infer 'type' for Json<Payload>
23 file(s) would change
1 property(ies) left untouched; see above

needs a decision: is something it will not guess at, and the run exits 1 while any remain. worth a look: is a rewrite it did make that you may still want to read.

Then drop the flag to write the changes. Edits are spliced into the text rather than the file being reprinted, so everything it does not touch stays byte for byte as you wrote it, comments and formatting included. Point it elsewhere with --project=<path>, or narrow it to certain paths with --include=<a,b>. It reads a real tsconfig.json rather than parsing one, because half the job is writing down types and only the checker knows what role?: Role resolves to.

  • type on a @Field/@Id that has none, from the property’s declared type.
  • entity: () => X on a relation, unwrapping arrays and the old Relation<T> alias.
  • Relation<T> to T, its import going with the last use.
  • virtual to computed.
  • raw('SQL') to the tagged template, an alias argument moving onto .as().
  • The idKey brand on a key not called id, _id or uuid, and on every composite.
  • Deletes import 'reflect-metadata', and experimentalDecorators/emitDecoratorMetadata from your tsconfig.json.

Anything where the choice is yours, reported rather than guessed. It exits 1 when something is left, 0 when nothing is, and 2 when it could not start at all.

  • @Transactional(), @InjectQuerier(), @Log() and @Serialized(), which no longer exist. A @Transactional() method becomes a pool.transaction() around its body, and only you know which pool.
  • Options it cannot read: @Field(shared), a spread, or a @Field never called.
  • A property whose type maps to no column, and a key written under a computed name.
  • A branded string id, written as type: String to keep the column you have. 'uuid' is a native column, and a migration.
  • target: esnext, the one target that leaves decorators untransformed. Any other modern one works.

That is the rest of the migration, and the point of it. Everything the codemod inserts is checked against the property it describes, so anything it got wrong is a compile error rather than a quietly wrong column. What each release asks beyond this is in the upgrade guide.