uql-codemod
v0.48.1
Published
Upgrade uql-orm across versions that introduce breaking changes
Maintainers
Readme
uql-codemod
Rewrites a uql-orm project across the breaking changes that can be made mechanically. Dry run first:
npx uql-codemod --dry-run
npx uql-codemod| Flag | |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| --project=<path> | The tsconfig.json to read, ./tsconfig.json by default. It has to cover your entities: the type checker is what says each property's type. |
| --dry-run | Report what would change and touch nothing. |
| --include=<a,b> | Only files whose path contains one of these fragments. |
Only --flag=value is read, and anything unrecognised is an error. It exits 0 when nothing is left for you, 1 when something is, and 2 when it could not start. Edits are spliced into the text, so everything it does not touch stays byte for byte as written.
What it rewrites
typeon a@Field/@Idthat has none, from the property's declared type; not besidereferences, whose column comes from the key it points at.entity: () => Xon a bare relation decorator, andRelation<T>toT, its import going with the last use.virtualtocomputed(on@Fieldand indefineEntity'sfields), a check'sexpressionand a filter'sconditiontowhere(@Entity/defineEntity,@Filter,defineFilter),raw('sql')to the tagged template, and arawalias argument onto.as().- Members named by string to callbacks:
mappedBy: 'author'to(post) => post.author, and@Index,include,referencesand@Entity/defineEntity'sindexesandhookslikewise:@Index((post) => [post.title]). references: (post) => post.authorIdon a to-one (@ManyToOne,@OneToOne, ordefineEntity/defineRelation) that names no foreign key, declaring@Field({ references: () => User }) authorIdfirst on a decorated class that has no such column, typed as the key it points at.- A partial-index
wherestring toraw, importing it, on entities and in the migration builder. col('cost')to the ref it names,(product) => raw`${product.cost}`in acomputedandrefs(Item).costin a statement, and$lock: { wait: 'skip' }to{ $wait: 'skip' }, or totruefor{}and a'block'wait.- An aggregate's
$aggto$select, and each field it or$text's$fieldsnames to a key:{ $sum: { amount: true } }. - Renamed exports, at the import and every use:
QueryWhereMaptoQueryWhere,RelationKeyMaptoKeyMap,FilterConditiontoFilterWhere,SqlMigrationModuleOptionstoMigrationModuleOptions,buildSqlQuerierMigrationModuletobuildMigrationModule,QueryDialecttoSqlQueryDialect,EngineFeaturestoDialectFeatures,KnownMigratorDialecttoDialectName,D1Preparer/D1DatabasetoD1Queryable, and the removed driver classes to the one each extended:PgDialect/NeonDialect/PgliteDialecttoPostgresDialect,CrdbQuerier/NeonQueriertoPgQuerier,LibsqlQuerier/TursoQueriertoHranaQuerier,TursoLocalQueriertoSqliteQuerierandTursoDatabasetoSqliteDatabase,MySql2DialecttoMySqlDialect,MongodbNativeDialecttoMongoDialect,Sqlite3QuerierPooltoSqliteQuerierPool, the migration builder'sI-prefixed types to the unprefixed name, moving the import to the entry that exports it; andMongoQuerier,isMongoQuerierandMongoSchemaIntrospectortouql-orm/mongodb. - Imports off
uql-orm/maria,uql-orm/mongoanduql-orm/bunSqltouql-orm/mariadb,uql-orm/mongodbanduql-orm/bun-sql, and offuql-orm/type,uql-orm/dialect,uql-orm/entity,uql-orm/querieranduql-orm/namingStrategytouql-orm. - The
[idKey]?: '...'brand, and its import, on a key not calledid,_idoruuidand on every composite. import 'reflect-metadata', andexperimentalDecorators/emitDecoratorMetadataintsconfig.json, comments and formatting kept.
What it leaves to you
Reported with what to do, never guessed:
target: esnext, the one target that leaves decorators untransformed, and a value inherited throughextends.@Log(),@Serialized(),@Transactional()and@InjectQuerier(): a@Transactional()method becomes apool.transaction()around its body, and only you know which pool.- An export removed with no one-to-one replacement (
setQuerierPool,getQuerier,augmentWhere,AbstractPgQuerier, ...), an internal the root no longer exports (AbstractSqlQuerier,fieldOf, ...), the migration storages, and any import fromuql-orm/utilthe root does not export (raw,refs, ... move touql-orm). - A value it cannot read: options passed as a variable or a spread, a list that is not a literal, a key under a computed name.
- A to-one onto a composite key: declare a column per key and pair each with it in
references. - A to-one whose
<relation>Idis not a declared column: an undecorated property, adefineEntitywhosefieldsleave it out, or adefineRelationwhose entity has no such member. - A partial-index
wherestring that interpolates, sincerawwould bind what the template spliced in. - 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. - SQL in a definition that names a column by hand, as a note: a rename reaches a callback's refs,
(user) => raw`lower(${user.email})`, and never the text. - A property whose type maps to no column (
Json<T>, a vector, a mixed union). - A branded string id, written as
type: Stringto keep the column you have, with a note:'uuid'is a native column, and a migration.
After it runs
tsc is the rest of the migration: what the codemod wrote is checked against the property it describes, so anything it got wrong is a compile error. See the upgrade guide.
Why TypeScript 6
Reading each property's type needs the checker, so TypeScript is a runtime dependency. 7's entry point exports no compiler API yet and has no standalone parser, which the tsconfig.json rewrite needs to keep your formatting; revisit once that API is stable.
License
MIT
