Codemod
uql-codemod rewrites your code across UQL’s mechanical breaking changes and reports what it cannot decide. Run it
first when you upgrade, then tsc, then the upgrade guide for anything else.
npx uql-codemod --dry-runneeds a decision: src/entity/audit.ts:9: cannot infer 'type' for Json<Payload>would change: src/entity/user.ts...23 file(s) would change1 item(s) need a decision; see aboveneeds a decision: marks something it will not guess, and worth a look: a rewrite you may want to read. Drop
--dry-run to write the files. Only the edited text changes; comments and formatting stay as you wrote them.
--project=<path> picks another tsconfig.json, and --include=<a,b> limits the paths. It exits 0 when nothing
is left, 1 when something is, and 2 when it could not start.
Everything it inserts is type-checked against the property it describes, so a wrong guess shows up as a tsc error.
What it rewrites
Section titled “What it rewrites”Entities and relations:
- A missing
typeon@Field/@Id, from the property’s declared type. entity: () => Xon a relation, andRelation<T>toT.- Members named by string to callbacks, in
mappedBy,references,@Index, and theindexesandhooksof@Entity/defineEntity:@Index((post) => [post.title]). references: (post) => post.authorIdon each to-one, declaring theauthorIdcolumn where it is missing.| nullon each nullable column’s property, except keys, relation aggregates andnullable: falsefields.- The
idKeybrand on a key not calledid,_idoruuid, and on every composite. virtualtocomputed, and a check’sexpressionand a filter’sconditiontowhere.
SQL and queries:
raw('SQL')to the tagged template,raw(fn, alias)toraw(fn).as(alias), andcol('cost')to a ref:(product) => raw`${product.cost}`in acomputed,refs(Item).costin a statement.- A partial-index
wherestring toraw, in entities and the migration builder, and the builder’sexprdefaults:expr.now()tocurrentTimestamp,expr.uuid()touuid,expr.raw('...')toraw`...`. - An aggregate’s
$aggto$select, and fields named in it or in$text’s$fieldsto keys:{ $sum: { amount: true } }. - An upsert’s
{ update: X }toXas its fourth argument, inupsertOne,upsertManyand a trigger’supsertInto. $lock: { wait: 'skip' }to{ $wait: 'skip' }, ortruefor a lock that waits.runandallto tags:all('SELECT * FROM t WHERE id = ?', [id])toall`SELECT * FROM t WHERE id = ${id}`. A string built at run time goes inraw.text(...).
Imports and setup:
- Renamed exports, with their imports and uses:
QueryWhereMap,RelationKeyMap,FilterCondition,SqlMigrationModuleOptions,buildSqlQuerierMigrationModule,Sqlite3QuerierPool(toSqliteQuerierPool), the migration builder’sIMigrationBuilder,ITableBuilderand the like (toMigrationBuilder,TableBuilder), and each driver subclass (PgDialect,NeonQuerier,LibsqlQuerier, …) to its base class. MongoQuerier,isMongoQuerierandMongoSchemaIntrospector, imported fromuql-orm/mongodb.- Entries:
uql-orm/maria,uql-orm/mongoanduql-orm/bunSqltouql-orm/mariadb,uql-orm/mongodbanduql-orm/bun-sql;uql-orm/type,uql-orm/dialect,uql-orm/entity,uql-orm/querieranduql-orm/namingStrategytouql-orm. - Removes
import 'reflect-metadata', andexperimentalDecorators/emitDecoratorMetadatafromtsconfig.json.
What it leaves to you
Section titled “What it leaves to you”@Transactional(),@InjectQuerier(),@Log()and@Serialized(), which UQL does not have. Wrap a@Transactional()method’s body inpool.transaction()on the pool you choose.- Removed exports with no one-to-one replacement, such as
setQuerierPoolorAbstractPgQuerier, the internals the root no longer exports (AbstractSqlQuerier,fieldOf, …), the migration storages, and any import fromuql-orm/utilthe root does not export:raw,refsand the rest it does move touql-orm. - A
col()whose entity it cannot tell: a raw built apart from its query, one under a relation filter, or a column no field maps. Read it offrefs(Entity). - Values it cannot read statically:
@Field(shared), a spread, a non-literal list. - A partial-index
wheretemplate that interpolates, sincerawwould bind each interpolation as a value. - A
run/allwith values it cannot place safely, such as a non-literal list or SQL, or mixed?and$n. - SQL in a definition that names a column by hand (
worth a look:). Only a ref follows a rename:(user) => raw`lower(${user.email})`. - A to-one onto a composite key (declare a column per key and pair each in
references), and a to-one whose<relation>Idis not a declared column. - A property whose type maps to no column, a key under a computed name, and a nullable column’s property with no written type.
- A branded string id, written as
type: Stringto keep your column.'uuid'is a native column type and would need a migration. target: esnext, which leaves decorators untransformed. Any other modern target works.