From fc2fbaac425ec608b0108c3128d23f9115707f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ad=C3=A1mek?= Date: Wed, 2 Sep 2020 15:39:19 +0200 Subject: [PATCH] feat(migrations): allow using knex in migrations This adds a `Migration.getKnex()` shortcut as well as allows using knex in `Migration.addSql()` and `Migration.execute()`. Related: #799 --- packages/migrations/src/Migration.ts | 14 ++++++++---- packages/migrations/src/MigrationRunner.ts | 4 ++-- tests/Migrator.test.ts | 25 +++++++++++++--------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/migrations/src/Migration.ts b/packages/migrations/src/Migration.ts index cc503576ee97..b22ae7cd4cf4 100644 --- a/packages/migrations/src/Migration.ts +++ b/packages/migrations/src/Migration.ts @@ -1,9 +1,11 @@ import { Configuration, Transaction } from '@mikro-orm/core'; import { AbstractSqlDriver, Knex } from '@mikro-orm/knex'; +export type Query = string | Knex.QueryBuilder | Knex.Raw; + export abstract class Migration { - private readonly queries: string[] = []; + private readonly queries: Query[] = []; protected ctx?: Transaction; constructor(protected readonly driver: AbstractSqlDriver, @@ -19,7 +21,7 @@ export abstract class Migration { return true; } - addSql(sql: string): void { + addSql(sql: Query): void { this.queries.push(sql); } @@ -32,11 +34,15 @@ export abstract class Migration { this.ctx = ctx; } - async execute(sql: string) { + async execute(sql: Query) { return this.driver.execute(sql, undefined, 'all', this.ctx); } - getQueries(): string[] { + getKnex() { + return this.driver.getConnection('write').getKnex(); + } + + getQueries(): Query[] { return this.queries; } diff --git a/packages/migrations/src/MigrationRunner.ts b/packages/migrations/src/MigrationRunner.ts index bba0d0dd06dc..53bd9eb06f9b 100644 --- a/packages/migrations/src/MigrationRunner.ts +++ b/packages/migrations/src/MigrationRunner.ts @@ -22,7 +22,7 @@ export class MigrationRunner { await this.connection.transactional(async tx => { migration.setTransactionContext(tx); const queries = await this.getQueries(migration, method); - await Utils.runSerial(queries, sql => this.driver.execute(tx.raw(sql))); + await Utils.runSerial(queries, sql => this.driver.execute(sql, undefined, 'all', tx)); }, this.masterTransaction); } } @@ -45,7 +45,7 @@ export class MigrationRunner { queries.push(...this.helper.getSchemaEnd().split('\n')); } - queries = queries.filter(sql => sql.trim().length > 0); + queries = queries.filter(sql => !Utils.isString(sql) || sql.trim().length > 0); return queries; } diff --git a/tests/Migrator.test.ts b/tests/Migrator.test.ts index ab5bdba190f4..3b69f427431c 100644 --- a/tests/Migrator.test.ts +++ b/tests/Migrator.test.ts @@ -18,8 +18,11 @@ class MigrationTest2 extends Migration { async up(): Promise { this.addSql('select 1 + 1'); - const res = await this.execute('select 1 + 1 as count'); - expect(res).toEqual([{ count: 2 }]); + const knex = this.getKnex(); + this.addSql(knex.raw('select 1 + 1')); + this.addSql(knex.select(knex.raw('2 + 2 as count2'))); + const res = await this.execute('select 1 + 1 as count1'); + expect(res).toEqual([{ count1: 2 }]); } isTransactional(): boolean { @@ -97,7 +100,7 @@ describe('Migrator', () => { }); test('ensureTable and list executed migrations', async () => { - await orm.em.getConnection().getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); + await orm.em.getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); const migrator = new Migrator(orm.em); // @ts-ignore const storage = migrator.storage; @@ -115,7 +118,7 @@ describe('Migrator', () => { }); test('runner', async () => { - await orm.em.getConnection().getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); + await orm.em.getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); const migrator = new Migrator(orm.em); // @ts-ignore await migrator.storage.ensureTable(); @@ -149,13 +152,15 @@ describe('Migrator', () => { migrator.options.disableForeignKeys = false; const migration2 = new MigrationTest2(orm.em.getDriver(), orm.config); await runner.run(migration2, 'up'); - expect(mock.mock.calls.length).toBe(2); - expect(mock.mock.calls[0][0]).toMatch('select 1 + 1'); - expect(mock.mock.calls[0][0]).toMatch('select 1 + 1 as count'); + expect(mock.mock.calls.length).toBe(4); + expect(mock.mock.calls[0][0]).toMatch('select 1 + 1 as count1'); + expect(mock.mock.calls[1][0]).toMatch('select 1 + 1'); + expect(mock.mock.calls[2][0]).toMatch('select 1 + 1'); + expect(mock.mock.calls[3][0]).toMatch('select 2 + 2 as count2'); }); test('up/down params [all or nothing enabled]', async () => { - await orm.em.getConnection().getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); + await orm.em.getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); const migrator = new Migrator(orm.em); // @ts-ignore migrator.options.disableForeignKeys = false; @@ -189,7 +194,7 @@ describe('Migrator', () => { }); test('up/down params [all or nothing disabled]', async () => { - await orm.em.getConnection().getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); + await orm.em.getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); const migrator = new Migrator(orm.em); // @ts-ignore migrator.options.disableForeignKeys = false; @@ -245,7 +250,7 @@ describe('Migrator - with explicit migrations', () => { afterAll(async () => orm.close(true)); test('runner', async () => { - await orm.em.getConnection().getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); + await orm.em.getKnex().schema.dropTableIfExists(orm.config.get('migrations').tableName!); const migrator = new Migrator(orm.em); // @ts-ignore await migrator.storage.ensureTable();