> Every UQL docs page, as Markdown: https://uql-orm.dev/llms.txt
> The same docs over MCP: https://uql-orm.dev/mcp
> Before writing UQL code, read the skill: https://uql-orm.dev/.well-known/agent-skills/uql-orm/SKILL.md

# Codemod

> One command that rewrites your code across the UQL breaking changes that can be made mechanically.

Source: https://uql-orm.dev/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](https://uql-orm.dev/upgrade-guide.md) for the rest.

```sh
npx uql-codemod --dry-run
```

```plaintext
needs a decision: src/entity/audit.ts:9: cannot infer 'type' for Json<Payload>
would change: src/entity/user.ts
...
23 file(s) would change
1 item(s) need a decision; see above
```

`needs 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` (it must cover your entities), 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

Entities and relations:

- A missing `type` on `@Field`/`@Id`, from the property’s declared type.
- `entity: () => X` on a relation, and `Relation<T>` to `T`.
- Members named by string to callbacks, in `mappedBy`, `references`, `@Index`, and the `indexes` and `hooks` of `@Entity`/`defineEntity`: `@Index((post) => [post.title])`.
- `references: (post) => post.authorId` on each to-one, declaring the `authorId` column where it is missing.
- `| null` on each [nullable column](https://uql-orm.dev/entities/basic.md#nullable-columns)’s property, except keys, relation aggregates and `nullable: false` fields.
- The [`idKey` brand](https://uql-orm.dev/entities/basic.md#naming-the-key) on a key not called `id`, `_id` or `uuid`, and on every composite.
- `virtual` to [`computed`](https://uql-orm.dev/entities/computed-fields.md), and a check’s `expression` and a filter’s `condition` to `where`.

SQL and queries:

- `raw` to [`sql`](https://uql-orm.dev/querying/raw-sql.md), at the import and every use. `raw('SQL')` becomes the tagged template, `raw(fn, alias)` becomes `sql(fn).as(alias)`, and `col('cost')` becomes a ref: ``(product) => sql`${product.cost}` ``in a `computed`, `refs(Item).cost` in a statement.
- A partial-index `where` string to `sql`, in entities and the [migration builder](https://uql-orm.dev/migrations/builder.md), and the builder’s `expr` defaults: `expr.now()` to `currentTimestamp`, `expr.uuid()` to `uuid`, `expr.raw('...')` to ``sql`...` ``.
- An aggregate’s `$agg` to `$select`, and fields named in it or in `$text`’s `$fields` to keys: `{ $sum: { amount: true } }`.
- An upsert’s `{ update: X }` to `X` as its fourth argument, in `upsertOne`, `upsertMany` and a trigger’s `upsertInto`, and `const { id } = await upsertOne(...)` to `const id`, since it resolves to the id.
- `$lock: { wait: 'skip' }` to `{ $wait: 'skip' }`, or `true` for a lock that waits.
- `run` and `all` to tags: `all('SELECT * FROM t WHERE id = ?', [id])` to ``all`SELECT * FROM t WHERE id = ${id}` ``. A string built at run time goes in `sql.text(...)`.

Imports and setup:

- Renamed exports, with their imports and uses: `QueryWhereMap`, `RelationKeyMap`, `FilterCondition`, `QueryDialect`, `EngineFeatures`, `SqlMigrationModuleOptions`, `buildSqlQuerierMigrationModule`, `Sqlite3QuerierPool` (to `SqliteQuerierPool`), the migration builder’s `IMigrationBuilder`, `ITableBuilder` and the like (to `MigrationBuilder`, `TableBuilder`), and each driver subclass (`PgDialect`, `NeonQuerier`, `LibsqlQuerier`, …) to its base class.
- `MongoQuerier`, `isMongoQuerier` and `MongoSchemaIntrospector`, imported from `uql-orm/mongodb`.
- Entries: `uql-orm/maria`, `uql-orm/mongo` and `uql-orm/bunSql` to `uql-orm/mariadb`, `uql-orm/mongodb` and `uql-orm/bun-sql`; `uql-orm/type`, `uql-orm/dialect`, `uql-orm/entity`, `uql-orm/querier` and `uql-orm/namingStrategy` to `uql-orm`.
- Removes `import 'reflect-metadata'`, and `experimentalDecorators`/`emitDecoratorMetadata` from `tsconfig.json`.

## What it leaves to you

- `@Transactional()`, `@InjectQuerier()`, `@Log()` and `@Serialized()`, which UQL does not have. Wrap a `@Transactional()` method’s body in `pool.transaction()` on the pool you choose.
- Removed exports with no one-to-one replacement, such as `setQuerierPool` or `AbstractPgQuerier`; internals the root no longer exports (`AbstractSqlQuerier`, `fieldOf`, …); the migration storages; and any import from `uql-orm/util` the root does not export (`raw`, `refs` and the rest it does export move to `uql-orm`).
- `Migrator`’s `pending()` and `executed()`, now read off `(await migrator.status())`, and a bare `down()` (`worth a look:`), which reverts only the last migration: `{ step: Infinity }` reverts them all.
- 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 off [`refs(Entity)`](https://uql-orm.dev/querying/raw-sql.md).
- Values it cannot read statically: `@Field(shared)`, a spread, a non-literal list.
- A partial-index `where` template that interpolates, since `sql` would bind each interpolation as a value.
- A `run`/`all` with 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) => sql`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>Id` is not a declared column.
- A property whose type maps to no column (`Json<T>`, a vector, a mixed union), a key under a computed name, and a nullable column’s property with no written type.
- A file that already declares a name the codemod would import (`sql`, `refs`, `idKey`, a renamed export), which it leaves unchanged.
- A branded string id, written as `type: String` to 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.
