Skip to content

Commit a0197bc

Browse files
feat(Migrator): allow passing transactions to Migrator. (#1480)
Co-authored-by: Igal Klebanov <igalklebanov@gmail.com> Co-authored-by: João Lucas de Oliveira Lopes <55464917+jlucaso1@users.noreply.github.com>
1 parent edac2ba commit a0197bc

2 files changed

Lines changed: 91 additions & 8 deletions

File tree

src/migration/migrator.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,14 +546,30 @@ export class Migrator {
546546
}
547547
}
548548

549-
const disableTransaction =
549+
const disableTransactions =
550550
options?.disableTransactions ?? this.#props.disableTransactions
551551

552-
if (!adapter.supportsTransactionalDdl || disableTransaction) {
553-
return this.#props.db.connection().execute(run)
552+
if (this.#props.db.isTransaction) {
553+
if (!adapter.supportsTransactionalDdl) {
554+
throw new Error(
555+
'Transactional DDL is not supported in this dialect. Passing a transaction to this migrator would result in failure or unexpected behavior.',
556+
)
557+
}
558+
559+
if (disableTransactions) {
560+
throw new Error(
561+
'`disableTransactions` is true but the migrator was given a transaction. Passing a transaction to this migrator would result in failure or unexpected behavior.',
562+
)
563+
}
564+
565+
return run(this.#props.db)
566+
}
567+
568+
if (adapter.supportsTransactionalDdl && !disableTransactions) {
569+
return this.#props.db.transaction().execute(run)
554570
}
555571

556-
return this.#props.db.transaction().execute(run)
572+
return this.#props.db.connection().execute(run)
557573
}
558574

559575
async #getState(db: Kysely<any>): Promise<MigrationState> {

test/node/src/migration.test.ts

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,22 @@ import { dirname, join } from 'pathe'
44
import { createSandbox, type SinonSpy } from 'sinon'
55
import {
66
FileMigrationProvider,
7-
Migration,
8-
MigrationResultSet,
7+
type Migration,
8+
type MigrationResultSet,
99
DEFAULT_MIGRATION_LOCK_TABLE,
1010
DEFAULT_MIGRATION_TABLE,
11+
type MigrationProvider,
1112
Migrator,
1213
NO_MIGRATIONS,
13-
MigratorProps,
14+
type MigratorProps,
1415
type Kysely,
1516
} from '../../../dist/cjs/index.js'
1617
import {
1718
clearDatabase,
1819
destroyTest,
1920
expect,
2021
initTest,
21-
TestContext,
22+
type TestContext,
2223
DIALECTS,
2324
type Database,
2425
} from './test-setup.js'
@@ -868,6 +869,72 @@ for (const dialect of DIALECTS) {
868869
expect(transactionSpy.called).to.be.false
869870
}
870871
})
872+
873+
if (sqlSpec === 'postgres' || sqlSpec === 'mssql') {
874+
it('should run migrations using a provided transaction', async () => {
875+
const migrationName = 'trx_connection_method_fail_case'
876+
877+
const trx = await ctx.db.startTransaction().execute()
878+
879+
try {
880+
const provider: MigrationProvider = {
881+
getMigrations: async () => ({
882+
[migrationName]: {
883+
async up(db: Kysely<any>): Promise<void> {
884+
expect(db).to.equal(trx)
885+
},
886+
},
887+
}),
888+
}
889+
890+
const migrator = new Migrator({ db: trx, provider })
891+
892+
const { results, error } = await migrator.migrateUp()
893+
894+
expect(trx.isCommitted).to.be.false
895+
expect(trx.isRolledBack).to.be.false
896+
897+
expect(error).to.be.undefined
898+
expect(results).to.eql([
899+
{ migrationName, direction: 'Up', status: 'Success' },
900+
])
901+
} finally {
902+
await trx.rollback().execute()
903+
}
904+
})
905+
}
906+
907+
if (sqlSpec === 'mysql' || sqlSpec === 'sqlite') {
908+
it('should refuse to run migrations using a provided transaction due to lack of support for transactional DDL', async () => {
909+
const trx = await ctx.db.startTransaction().execute()
910+
try {
911+
const provider: MigrationProvider = {
912+
getMigrations: async () => ({
913+
some_migration: {
914+
async up(db: Kysely<any>): Promise<void> {
915+
expect(db).to.equal(trx)
916+
},
917+
},
918+
}),
919+
}
920+
921+
const migrator = new Migrator({ db: trx, provider })
922+
923+
const { results, error } = await migrator.migrateUp()
924+
925+
expect(error).to.be.an.instanceOf(Error)
926+
expect(getMessage(error)).to.eql(
927+
'Transactional DDL is not supported in this dialect. Passing a transaction to this migrator would result in failure or unexpected behavior.',
928+
)
929+
expect(results).to.be.undefined
930+
931+
expect(trx.isCommitted).to.be.false
932+
expect(trx.isRolledBack).to.be.false
933+
} finally {
934+
await trx.rollback().execute()
935+
}
936+
})
937+
}
871938
})
872939

873940
describe('migrateDown', () => {

0 commit comments

Comments
 (0)