2014-09-01 17:18:45 +02:00
|
|
|
/*global after, before, describe, expect, it*/
|
|
|
|
'use strict';
|
|
|
|
|
2018-08-24 11:39:20 +02:00
|
|
|
const equal = require('assert').equal;
|
2019-04-30 18:21:49 -04:00
|
|
|
const fs = require('fs');
|
2018-08-24 11:39:20 +02:00
|
|
|
const path = require('path');
|
|
|
|
const rimraf = require('rimraf');
|
|
|
|
const Promise = require('bluebird');
|
2018-09-12 19:58:37 +08:00
|
|
|
const testMemoryMigrations = require('./memory-migrations');
|
2019-03-05 01:03:51 +01:00
|
|
|
const { isNode6 } = require('../../../lib/util/version-helper');
|
2013-10-24 21:54:35 -04:00
|
|
|
|
|
|
|
module.exports = function(knex) {
|
|
|
|
require('rimraf').sync(path.join(__dirname, './migration'));
|
|
|
|
|
2015-12-13 15:53:54 +02:00
|
|
|
before(function() {
|
2015-12-13 15:05:31 +02:00
|
|
|
// make sure lock was not left from previous failed test run
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.forceFreeMigrationsLock({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
2015-12-13 15:05:31 +02:00
|
|
|
});
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
describe('knex.migrate', function() {
|
2019-03-30 14:58:56 +01:00
|
|
|
it('should not fail on null default for timestamp', () => {
|
2019-05-13 12:21:36 +03:00
|
|
|
return knex.schema
|
|
|
|
.dropTableIfExists('null_date')
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: 'test/integration/migrate/null_timestamp_default',
|
|
|
|
});
|
2019-03-30 14:58:56 +01:00
|
|
|
})
|
|
|
|
.then(() => {
|
2019-05-13 12:21:36 +03:00
|
|
|
return knex.into('null_date').insert({
|
|
|
|
dummy: 'cannot insert empty object',
|
|
|
|
});
|
2019-03-30 14:58:56 +01:00
|
|
|
})
|
|
|
|
.then(() => {
|
2019-05-13 12:21:36 +03:00
|
|
|
return knex('null_date').first();
|
2019-03-30 14:58:56 +01:00
|
|
|
})
|
|
|
|
.then((rows) => {
|
|
|
|
expect(rows.deleted_at).to.equal(null);
|
|
|
|
})
|
2019-05-13 12:21:36 +03:00
|
|
|
.finally(() => {
|
2019-03-30 14:58:56 +01:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/null_timestamp_default',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-03-05 01:03:51 +01:00
|
|
|
it('should not fail drop-and-recreate-column operation when using promise chain', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/drop-and-recreate',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/drop-and-recreate',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
if (knex.client.driverName === 'pg') {
|
|
|
|
it('should not fail drop-and-recreate-column operation when using promise chain and schema', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/drop-and-recreate-with-schema',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/drop-and-recreate-with-schema',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isNode6()) {
|
|
|
|
it('should not fail drop-and-recreate-column operation when using async/await', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/async-await-drop-and-recreate',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/async-await-drop-and-recreate',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isNode6() && knex.client.driverName === 'pg') {
|
|
|
|
it('should not fail drop-and-recreate-column operation when using async/await and schema', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/async-await-drop-and-recreate-with-schema',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/async-await-drop-and-recreate-with-schema',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-10-24 21:54:35 -04:00
|
|
|
it('should create a new migration file with the create method', function() {
|
2014-05-28 22:29:34 -04:00
|
|
|
return knex.migrate.make('test').then(function(name) {
|
2014-07-21 19:48:31 -04:00
|
|
|
name = path.basename(name);
|
2013-10-24 21:54:35 -04:00
|
|
|
expect(name.split('_')[0]).to.have.length(14);
|
2013-11-29 10:00:42 -05:00
|
|
|
expect(name.split('_')[1].split('.')[0]).to.equal('test');
|
2013-10-24 21:54:35 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should list the current migration state with the currentVersion method', function() {
|
2014-05-28 22:29:34 -04:00
|
|
|
return knex.migrate.currentVersion().then(function(version) {
|
2013-10-24 21:54:35 -04:00
|
|
|
equal(version, 'none');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-08-24 11:39:20 +02:00
|
|
|
const tables = [
|
|
|
|
'migration_test_1',
|
|
|
|
'migration_test_2',
|
|
|
|
'migration_test_2_1',
|
|
|
|
];
|
2013-11-29 10:00:42 -05:00
|
|
|
|
2015-11-18 16:31:54 -06:00
|
|
|
describe('knex.migrate.status', function() {
|
2018-02-03 08:33:02 -05:00
|
|
|
this.timeout(process.env.KNEX_TEST_TIMEOUT || 30000);
|
2015-11-18 16:31:54 -06:00
|
|
|
|
|
|
|
beforeEach(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
2015-11-18 16:31:54 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
2015-11-18 16:31:54 -06:00
|
|
|
});
|
|
|
|
|
2015-12-13 15:05:31 +02:00
|
|
|
it('should create a migrations lock table', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.schema
|
|
|
|
.hasTable('knex_migrations_lock')
|
|
|
|
.then(function(exists) {
|
2015-12-13 15:05:31 +02:00
|
|
|
expect(exists).to.equal(true);
|
2018-07-09 08:10:34 -04:00
|
|
|
|
|
|
|
return knex.schema
|
|
|
|
.hasColumn('knex_migrations_lock', 'is_locked')
|
|
|
|
.then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
});
|
2015-12-13 15:05:31 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-18 16:31:54 -06:00
|
|
|
it('should return 0 if code matches DB', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.status({ directory: 'test/integration/migrate/test' })
|
|
|
|
.then(function(migrationLevel) {
|
|
|
|
expect(migrationLevel).to.equal(0);
|
|
|
|
});
|
2015-11-18 16:31:54 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should return a negative number if the DB is behind', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.rollback({ directory: 'test/integration/migrate/test' })
|
|
|
|
.then(function() {
|
|
|
|
return knex.migrate
|
|
|
|
.status({ directory: 'test/integration/migrate/test' })
|
|
|
|
.then(function(migrationLevel) {
|
|
|
|
expect(migrationLevel).to.equal(-2);
|
|
|
|
});
|
2017-03-27 17:39:08 +03:00
|
|
|
});
|
2015-11-18 16:31:54 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should return a positive number if the DB is ahead', function() {
|
|
|
|
return Promise.all([
|
2018-07-09 08:10:34 -04:00
|
|
|
knex('knex_migrations')
|
|
|
|
.returning('id')
|
|
|
|
.insert({
|
|
|
|
name: 'foobar',
|
|
|
|
batch: 5,
|
|
|
|
migration_time: new Date(),
|
|
|
|
}),
|
|
|
|
knex('knex_migrations')
|
|
|
|
.returning('id')
|
|
|
|
.insert({
|
|
|
|
name: 'foobar',
|
|
|
|
batch: 5,
|
|
|
|
migration_time: new Date(),
|
|
|
|
}),
|
|
|
|
knex('knex_migrations')
|
|
|
|
.returning('id')
|
|
|
|
.insert({
|
|
|
|
name: 'foobarbaz',
|
|
|
|
batch: 6,
|
|
|
|
migration_time: new Date(),
|
|
|
|
}),
|
|
|
|
]).spread(function(migration1, migration2, migration3) {
|
|
|
|
return knex.migrate
|
|
|
|
.status({ directory: 'test/integration/migrate/test' })
|
|
|
|
.then(function(migrationLevel) {
|
2017-03-27 17:39:08 +03:00
|
|
|
expect(migrationLevel).to.equal(3);
|
|
|
|
})
|
2018-07-09 08:10:34 -04:00
|
|
|
.then(function() {
|
|
|
|
// Cleanup the added migrations
|
|
|
|
if (/redshift/.test(knex.client.driverName)) {
|
2018-02-03 08:33:02 -05:00
|
|
|
return knex('knex_migrations')
|
2018-07-09 08:10:34 -04:00
|
|
|
.where('name', 'like', '%foobar%')
|
|
|
|
.del();
|
|
|
|
}
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.where('id', migration1[0])
|
|
|
|
.orWhere('id', migration2[0])
|
|
|
|
.orWhere('id', migration3[0])
|
|
|
|
.del();
|
|
|
|
});
|
|
|
|
});
|
2015-11-18 16:31:54 -06:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-11-29 10:00:42 -05:00
|
|
|
describe('knex.migrate.latest', function() {
|
|
|
|
before(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
2013-11-29 10:00:42 -05:00
|
|
|
});
|
|
|
|
|
2019-05-13 12:21:36 +03:00
|
|
|
it('should remove the record in the lock table once finished (TODO: fix random oracle fail)', function() {
|
|
|
|
if (knex.client.driverName == 'oracledb') {
|
|
|
|
this.skip();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations_lock')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data[0]).to.have.property('is_locked');
|
|
|
|
expect(data[0].is_locked).to.not.be.ok;
|
|
|
|
});
|
2015-11-16 10:22:01 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw error if the migrations are already running', function() {
|
|
|
|
return knex('knex_migrations_lock')
|
|
|
|
.update({ is_locked: 1 })
|
|
|
|
.then(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.latest({ directory: 'test/integration/migrate/test' })
|
2015-11-16 10:22:01 -06:00
|
|
|
.then(function() {
|
|
|
|
throw new Error('then should not execute');
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(function(error) {
|
2018-07-09 08:10:34 -04:00
|
|
|
expect(error).to.have.property(
|
|
|
|
'message',
|
|
|
|
'Migration table is already locked'
|
|
|
|
);
|
2015-11-16 10:22:01 -06:00
|
|
|
return knex('knex_migrations_lock').select('*');
|
|
|
|
})
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data[0].is_locked).to.equal(1);
|
|
|
|
|
|
|
|
// Clean up lock for other tests
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations_lock').update({ is_locked: 0 });
|
2015-11-16 10:22:01 -06:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-11-15 16:23:13 -08:00
|
|
|
it('should report failing migration', function() {
|
|
|
|
const migrator = knex.migrate;
|
|
|
|
return migrator
|
|
|
|
.latest({ directory: 'test/integration/migrate/test_with_invalid' })
|
2015-11-16 10:22:01 -06:00
|
|
|
.then(function() {
|
|
|
|
throw new Error('then should not execute');
|
|
|
|
})
|
|
|
|
.catch(function(error) {
|
|
|
|
// This will fail because of the invalid migration
|
2018-11-15 16:23:13 -08:00
|
|
|
expect(error)
|
|
|
|
.to.have.property('message')
|
|
|
|
.that.includes('unknown_table');
|
|
|
|
expect(migrator)
|
|
|
|
.to.have.property('_activeMigration')
|
|
|
|
.to.have.property(
|
|
|
|
'fileName',
|
|
|
|
'20150109002832_invalid_migration.js'
|
|
|
|
);
|
2018-11-23 19:58:23 +08:00
|
|
|
})
|
|
|
|
.then(function(data) {
|
|
|
|
// Clean up lock for other tests
|
|
|
|
// TODO: Remove this code to reproduce https://github.com/tgriesser/knex/issues/2925
|
|
|
|
// It is only relevant for Oracle, most likely there is a bug somewhere that needs fixing
|
|
|
|
return knex('knex_migrations_lock').update({ is_locked: 0 });
|
2018-11-15 16:23:13 -08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should release lock if non-locking related error is thrown', function() {
|
|
|
|
return knex('knex_migrations_lock')
|
|
|
|
.select('*')
|
2015-11-16 10:22:01 -06:00
|
|
|
.then(function(data) {
|
|
|
|
expect(data[0].is_locked).to.not.be.ok;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-11-29 10:00:42 -05:00
|
|
|
it('should run all migration files in the specified directory', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(2);
|
|
|
|
});
|
2013-11-02 17:37:30 -04:00
|
|
|
});
|
2013-11-29 10:00:42 -05:00
|
|
|
|
|
|
|
it('should run the migrations from oldest to newest', function() {
|
2018-07-08 14:10:51 +03:00
|
|
|
if (knex.client.driverName === 'oracledb') {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.orderBy('migration_time', 'asc')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(path.basename(data[0].name)).to.equal(
|
|
|
|
'20131019235242_migration_1.js'
|
|
|
|
);
|
|
|
|
expect(path.basename(data[1].name)).to.equal(
|
|
|
|
'20131019235306_migration_2.js'
|
|
|
|
);
|
|
|
|
});
|
2014-08-11 12:25:39 +02:00
|
|
|
} else {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.orderBy('id', 'asc')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(path.basename(data[0].name)).to.equal(
|
|
|
|
'20131019235242_migration_1.js'
|
|
|
|
);
|
|
|
|
expect(path.basename(data[1].name)).to.equal(
|
|
|
|
'20131019235306_migration_2.js'
|
|
|
|
);
|
|
|
|
});
|
2014-08-11 12:25:39 +02:00
|
|
|
}
|
2013-11-29 10:00:42 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should create all specified tables and columns', function() {
|
|
|
|
// Map the table names to promises that evaluate chai expectations to
|
|
|
|
// confirm that the table exists and the 'id' and 'name' columns exist
|
|
|
|
// within the table
|
|
|
|
return Promise.map(tables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
2014-09-02 22:03:14 +02:00
|
|
|
expect(exists).to.equal(true);
|
2013-11-29 10:00:42 -05:00
|
|
|
if (exists) {
|
|
|
|
return Promise.all([
|
|
|
|
knex.schema.hasColumn(table, 'id').then(function(exists) {
|
2014-09-02 22:03:14 +02:00
|
|
|
expect(exists).to.equal(true);
|
2013-11-29 10:00:42 -05:00
|
|
|
}),
|
|
|
|
knex.schema.hasColumn(table, 'name').then(function(exists) {
|
2014-09-02 22:03:14 +02:00
|
|
|
expect(exists).to.equal(true);
|
2018-07-09 08:10:34 -04:00
|
|
|
}),
|
2013-11-29 10:00:42 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-08-24 11:39:20 +02:00
|
|
|
describe('knex.migrate.latest - multiple directories', () => {
|
|
|
|
before(() => {
|
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: [
|
|
|
|
'test/integration/migrate/test',
|
|
|
|
'test/integration/migrate/test2',
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
after(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: [
|
|
|
|
'test/integration/migrate/test',
|
|
|
|
'test/integration/migrate/test2',
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should create tables specified in both directories', () => {
|
|
|
|
// Map the table names to promises that evaluate chai expectations to
|
|
|
|
// confirm that the table exists
|
|
|
|
const expectedTables = [
|
|
|
|
'migration_test_1',
|
|
|
|
'migration_test_2',
|
|
|
|
'migration_test_2_1',
|
|
|
|
'migration_test_3',
|
|
|
|
'migration_test_4',
|
|
|
|
'migration_test_4_1',
|
|
|
|
];
|
|
|
|
|
|
|
|
return Promise.map(expectedTables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-11-29 10:00:42 -05:00
|
|
|
describe('knex.migrate.rollback', function() {
|
|
|
|
it('should delete the most recent batch from the migration log', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.rollback({ directory: 'test/integration/migrate/test' })
|
|
|
|
.spread(function(batchNo, log) {
|
|
|
|
expect(batchNo).to.equal(1);
|
|
|
|
expect(log).to.have.length(2);
|
2018-09-12 19:58:37 +08:00
|
|
|
expect(log[0]).to.contain(batchNo);
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(0);
|
|
|
|
});
|
2013-11-29 10:00:42 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should drop tables as specified in the batch', function() {
|
|
|
|
return Promise.map(tables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
2014-09-02 22:03:14 +02:00
|
|
|
expect(!!exists).to.equal(false);
|
2013-11-29 10:00:42 -05:00
|
|
|
});
|
2013-11-02 17:37:30 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2013-10-24 21:54:35 -04:00
|
|
|
|
2018-12-20 23:05:28 +00:00
|
|
|
describe('knex.migrate.rollback - all', () => {
|
|
|
|
before(() => {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: ['test/integration/migrate/test'],
|
|
|
|
})
|
|
|
|
.then(function() {
|
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: [
|
|
|
|
'test/integration/migrate/test',
|
|
|
|
'test/integration/migrate/test2',
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should delete all batches from the migration log', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.rollback(
|
|
|
|
{
|
|
|
|
directory: [
|
|
|
|
'test/integration/migrate/test',
|
|
|
|
'test/integration/migrate/test2',
|
|
|
|
],
|
|
|
|
},
|
|
|
|
true
|
|
|
|
)
|
|
|
|
.spread(function(batchNo, log) {
|
|
|
|
expect(batchNo).to.equal(2);
|
|
|
|
expect(log).to.have.length(4);
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should drop tables as specified in the batch', () => {
|
|
|
|
return Promise.map(tables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
|
|
|
expect(!!exists).to.equal(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-04-30 18:21:49 -04:00
|
|
|
describe('knex.migrate.rollback - all', () => {
|
|
|
|
before(() => {
|
|
|
|
return knex.migrate.latest({
|
|
|
|
directory: ['test/integration/migrate/test'],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should only rollback migrations that have been completed and in reverse chronological order', () => {
|
|
|
|
return knex.migrate
|
|
|
|
.rollback(
|
|
|
|
{
|
|
|
|
directory: [
|
|
|
|
'test/integration/migrate/test',
|
|
|
|
'test/integration/migrate/test2',
|
|
|
|
],
|
|
|
|
},
|
|
|
|
true
|
|
|
|
)
|
|
|
|
.spread(function(batchNo, log) {
|
|
|
|
expect(batchNo).to.equal(1);
|
|
|
|
expect(log).to.have.length(2);
|
|
|
|
|
|
|
|
fs.readdirSync('test/integration/migrate/test')
|
|
|
|
.reverse()
|
|
|
|
.forEach((fileName, index) => {
|
|
|
|
expect(fileName).to.equal(log[index]);
|
|
|
|
});
|
|
|
|
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should drop tables as specified in the batch', () => {
|
|
|
|
return Promise.map(tables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
|
|
|
expect(!!exists).to.equal(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-05-19 07:14:52 -04:00
|
|
|
describe('knex.migrate.up', () => {
|
|
|
|
afterEach(() => {
|
|
|
|
return knex.migrate.rollback(
|
|
|
|
{ directory: 'test/integration/migrate/test' },
|
|
|
|
true
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should only run the first migration if no migrations have run', function() {
|
|
|
|
return knex.migrate
|
|
|
|
.up({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data).to.have.length(1);
|
|
|
|
expect(path.basename(data[0].name)).to.equal(
|
|
|
|
'20131019235242_migration_1.js'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should only run the next migration that has not yet run if other migrations have already run', function() {
|
|
|
|
return knex.migrate
|
|
|
|
.up({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate
|
|
|
|
.up({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data).to.have.length(2);
|
|
|
|
expect(path.basename(data[0].name)).to.equal(
|
|
|
|
'20131019235242_migration_1.js'
|
|
|
|
);
|
|
|
|
expect(path.basename(data[1].name)).to.equal(
|
|
|
|
'20131019235306_migration_2.js'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not error if all migrations have already been run', function() {
|
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex.migrate
|
|
|
|
.up({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
})
|
|
|
|
.then((data) => {
|
|
|
|
expect(data).to.be.an('array');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-10-24 21:54:35 -04:00
|
|
|
after(function() {
|
|
|
|
rimraf.sync(path.join(__dirname, './migration'));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-03-27 17:39:08 +03:00
|
|
|
describe('knex.migrate.latest in parallel', function() {
|
|
|
|
afterEach(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
2017-03-27 17:39:08 +03:00
|
|
|
});
|
|
|
|
|
2018-07-08 14:10:51 +03:00
|
|
|
if (knex.client.driverName === 'pg' || knex.client.driverName === 'mssql') {
|
2018-07-09 08:10:34 -04:00
|
|
|
it('is able to run two migrations in parallel (if no implicit DDL commits)', function() {
|
2017-03-27 17:39:08 +03:00
|
|
|
return Promise.all([
|
2018-07-09 08:10:34 -04:00
|
|
|
knex.migrate.latest({ directory: 'test/integration/migrate/test' }),
|
|
|
|
knex.migrate.latest({ directory: 'test/integration/migrate/test' }),
|
|
|
|
]).then(function() {
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
2018-04-05 01:19:08 +03:00
|
|
|
expect(data.length).to.equal(2);
|
|
|
|
});
|
2018-07-09 08:10:34 -04:00
|
|
|
});
|
2017-03-27 17:39:08 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
it('is not able to run two migrations in parallel when transactions are disabled', function() {
|
|
|
|
return Promise.map(
|
|
|
|
[
|
|
|
|
knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
disableTransactions: true,
|
|
|
|
})
|
|
|
|
.catch(function(err) {
|
|
|
|
return err;
|
|
|
|
}),
|
|
|
|
knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
disableTransactions: true,
|
|
|
|
})
|
|
|
|
.catch(function(err) {
|
|
|
|
return err;
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
function(res) {
|
|
|
|
return res && res.name;
|
|
|
|
}
|
|
|
|
).then(function(res) {
|
|
|
|
// One should fail:
|
2018-08-24 11:39:20 +02:00
|
|
|
const hasLockError =
|
2018-07-09 08:10:34 -04:00
|
|
|
res[0] === 'MigrationLocked' || res[1] === 'MigrationLocked';
|
|
|
|
expect(hasLockError).to.equal(true);
|
|
|
|
|
|
|
|
// But the other should succeed:
|
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
2017-03-27 17:39:08 +03:00
|
|
|
expect(data.length).to.equal(2);
|
2018-06-29 10:47:06 +03:00
|
|
|
});
|
2018-07-09 08:10:34 -04:00
|
|
|
});
|
2017-03-27 17:39:08 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
describe('knex.migrate (transactions disabled)', function() {
|
2015-08-30 12:57:28 +03:00
|
|
|
describe('knex.migrate.latest (all transactions disabled)', function() {
|
|
|
|
before(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test_with_invalid',
|
|
|
|
disableTransactions: true,
|
|
|
|
})
|
|
|
|
.catch(function() {});
|
2015-08-30 12:57:28 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// Same test as before, but this time, because
|
|
|
|
// transactions are off, the column gets created for all dialects always.
|
|
|
|
it('should create column even in invalid migration', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.schema
|
|
|
|
.hasColumn('migration_test_1', 'transaction')
|
|
|
|
.then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
});
|
2015-08-30 12:57:28 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
after(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test_with_invalid',
|
|
|
|
});
|
2015-08-30 12:57:28 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-30 14:56:37 +03:00
|
|
|
describe('knex.migrate.latest (per-migration transaction disabled)', function() {
|
|
|
|
before(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/test_per_migration_trx_disabled',
|
|
|
|
})
|
|
|
|
.catch(function() {});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should run all working migration files in the specified directory', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(1);
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should create column in invalid migration with transaction disabled', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.schema
|
|
|
|
.hasColumn('migration_test_trx_1', 'transaction')
|
|
|
|
.then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
after(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test_per_migration_trx_disabled',
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('knex.migrate.latest (per-migration transaction enabled)', function() {
|
|
|
|
before(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory:
|
|
|
|
'test/integration/migrate/test_per_migration_trx_enabled',
|
|
|
|
disableTransactions: true,
|
|
|
|
})
|
|
|
|
.catch(function() {});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should run all working migration files in the specified directory', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex('knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(1);
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should not create column for invalid migration with transaction enabled', function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.schema
|
|
|
|
.hasColumn('migration_test_trx_1', 'transaction')
|
|
|
|
.then(function(exists) {
|
|
|
|
// MySQL / Oracle commit transactions implicit for most common
|
|
|
|
// migration statements (e.g. CREATE TABLE, ALTER TABLE, DROP TABLE),
|
|
|
|
// so we need to check for dialect
|
|
|
|
if (
|
|
|
|
knex.client.driverName === 'mysql' ||
|
|
|
|
knex.client.driverName === 'mysql2' ||
|
|
|
|
knex.client.driverName === 'oracledb'
|
|
|
|
) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
} else {
|
|
|
|
expect(exists).to.equal(false);
|
|
|
|
}
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
after(function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test_per_migration_trx_enabled',
|
|
|
|
});
|
2015-08-30 14:56:37 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-07-08 14:10:51 +03:00
|
|
|
if (knex.client.driverName === 'pg') {
|
2018-07-09 08:10:34 -04:00
|
|
|
describe('knex.migrate.latest with specific changelog schema', function() {
|
2018-04-05 01:19:08 +03:00
|
|
|
before(() => {
|
|
|
|
return knex.raw(`CREATE SCHEMA IF NOT EXISTS "testschema"`);
|
|
|
|
});
|
|
|
|
after(() => {
|
|
|
|
return knex.raw(`DROP SCHEMA "testschema" CASCADE`);
|
|
|
|
});
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
it('should create changelog in the correct schema without transactions', function(done) {
|
|
|
|
knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
disableTransactions: true,
|
|
|
|
schemaName: 'testschema',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex('testschema.knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(2);
|
|
|
|
done();
|
|
|
|
});
|
2018-04-05 01:19:08 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-07-09 08:10:34 -04:00
|
|
|
it('should create changelog in the correct schema with transactions', function(done) {
|
|
|
|
knex.migrate
|
|
|
|
.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
disableTransactions: false,
|
|
|
|
schemaName: 'testschema',
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return knex('testschema.knex_migrations')
|
|
|
|
.select('*')
|
|
|
|
.then(function(data) {
|
|
|
|
expect(data.length).to.equal(2);
|
|
|
|
done();
|
|
|
|
});
|
2018-04-05 01:19:08 +03:00
|
|
|
});
|
|
|
|
});
|
2015-08-30 12:57:28 +03:00
|
|
|
|
2018-04-05 01:19:08 +03:00
|
|
|
afterEach(function() {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
disableTransactions: true,
|
2018-07-09 08:10:34 -04:00
|
|
|
schemaName: 'testschema',
|
2018-04-05 01:19:08 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2018-09-12 19:58:37 +08:00
|
|
|
|
|
|
|
describe('migrationSource config', function() {
|
|
|
|
const migrationSource = {
|
|
|
|
getMigrations() {
|
|
|
|
return Promise.resolve(Object.keys(testMemoryMigrations).sort());
|
|
|
|
},
|
|
|
|
getMigrationName(migration) {
|
|
|
|
return migration;
|
|
|
|
},
|
|
|
|
getMigration(migration) {
|
|
|
|
return testMemoryMigrations[migration];
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
before(() => {
|
|
|
|
return knex.migrate.latest({
|
|
|
|
migrationSource,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
after(() => {
|
|
|
|
return knex.migrate.rollback({
|
|
|
|
migrationSource,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('can accept a custom migration source', function() {
|
|
|
|
return knex.schema
|
|
|
|
.hasColumn('migration_source_test_1', 'name')
|
|
|
|
.then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2018-09-26 22:27:59 +02:00
|
|
|
|
|
|
|
describe('knex.migrate.latest with custom config parameter for table name', function() {
|
|
|
|
before(function() {
|
|
|
|
return knex
|
|
|
|
.withUserParams({ customTableName: 'migration_test_2_1a' })
|
|
|
|
.migrate.latest({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should create all specified tables and columns', function() {
|
|
|
|
const tables = [
|
|
|
|
'migration_test_1',
|
|
|
|
'migration_test_2',
|
|
|
|
'migration_test_2_1a',
|
|
|
|
];
|
|
|
|
return Promise.map(tables, function(table) {
|
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
if (exists) {
|
|
|
|
return Promise.all([
|
|
|
|
knex.schema.hasColumn(table, 'id').then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
}),
|
|
|
|
knex.schema.hasColumn(table, 'name').then(function(exists) {
|
|
|
|
expect(exists).to.equal(true);
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not create unexpected tables', function() {
|
|
|
|
const table = 'migration_test_2_1';
|
2018-11-15 16:23:13 -08:00
|
|
|
return knex.schema.hasTable(table).then(function(exists) {
|
2018-09-26 22:27:59 +02:00
|
|
|
expect(exists).to.equal(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
after(function() {
|
|
|
|
return knex
|
|
|
|
.withUserParams({ customTableName: 'migration_test_2_1a' })
|
|
|
|
.migrate.rollback({
|
|
|
|
directory: 'test/integration/migrate/test',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-09-01 17:18:45 +02:00
|
|
|
};
|