ORM Migrations

For code-based ORMs, pgfence extracts or transpiles SQL from the forward migration path only. Prisma and Drizzle support means reading their generated .sql files directly, not parsing the schema DSL itself.

TypeORM

bash
pgfence analyze --format typeorm src/migrations/*.ts

pgfence extracts literal queryRunner.query() calls from the up() method. The parameter name is resolved dynamically, so queryRunner, qr, or any other identifier works.

Auto-commit detection

When a migration sets public transaction = false, pgfence detects auto-commit mode and skips compounding lock warnings (each statement releases its lock before the next begins).

Builder API detection

TypeORM also offers a builder API such as queryRunner.createTable() and queryRunner.addColumn(). The current OSS extractor does not transpile that API to SQL. Instead, it emits an ExtractionWarning naming the specific method so the migration is never silently treated as fully analyzed.

Knex

bash
pgfence analyze --format knex migrations/*.ts

pgfence extracts literal knex.raw() / trx.raw() calls and transpiles a focused subset of schema builder calls from the up export into SQL for analysis.

Schema builder support

The current transpiler covers common table-level operations such as:

  • createTable, createTableIfNotExists
  • alterTable, table (alias for alterTable)
  • dropTable, dropTableIfExists
  • renameTable, renameColumn, dropColumn, dropColumns
  • setNullable and dropNullable for NOT NULL changes

Column builder support

Inside createTable and alterTable callbacks, pgfence handles common column definitions including:

  • Column types: integer, bigInteger, text, string, float, decimal, boolean, date, datetime, timestamp, binary, json, jsonb, uuid, specificType
  • Modifiers: notNullable(), nullable(), defaultTo(), primary(), unique()
  • Foreign keys: basic literal chains such as references('id').inTable('users').onDelete('CASCADE') and onUpdate(...), when table and column names resolve cleanly
  • Timestamps: t.timestamps() produces created_at and updated_at columns

Many unsupported dynamic patterns are surfaced as ExtractionWarnings, but some ORM builder chains are still best-effort and only partially reconstructed. Treat the coverage line as a lower bound on what was analyzed, not proof that every ORM statement was fully recovered.

Sequelize

bash
pgfence analyze --format sequelize migrations/*.js

pgfence extracts literal queryInterface.sequelize.query() calls from the up() function and transpiles a focused subset of queryInterface builder calls into SQL.

Builder API support

The current transpiler covers common queryInterface methods:

  • createTable, dropTable, renameTable
  • addColumn, removeColumn, changeColumn, renameColumn
  • addIndex, removeIndex
  • addConstraint (UNIQUE, FOREIGN KEY, CHECK), removeConstraint

Volatile default detection

Sequelize.literal('NOW()') used as a defaultValue is lowered to a synthetic volatile expression so the normal analyzer can flag it like any other non-constant default.

Prisma

bash
pgfence analyze --format prisma prisma/migrations/**/migration.sql

Prisma generates plain .sql files in its migrations directory. pgfence reads those files directly, the same way it reads raw SQL migrations.

Drizzle

bash
pgfence analyze --format drizzle drizzle/*.sql

Drizzle also generates plain .sql migration files. pgfence reads those directly, the same way it reads raw SQL migrations.

Auto-Detect

bash
pgfence analyze migrations/*

Auto-detect uses both file paths and source markers. Prisma migrations are detected from the prisma/migrations path, Drizzle from a drizzle/ path, and .ts / .js files are checked for TypeORM, Knex, or Sequelize markers in the source.

Dynamic SQL

Extractors that encounter template literals with interpolations or other non-literal arguments emit an ExtractionWarning. When pgfence cannot fully reconstruct a statement, the coverage line tells you how much of the migration was not statically analyzable.