Skip to content

Commit

Permalink
🎨 run database population in transaction (#7448)
Browse files Browse the repository at this point in the history
* 🎨  run database population in transaction

refs #6574, refs #7432

- create transaction for creating tables
- if an error occurs or a container get's destroyed before population finishes, transaction is rolled back

* 🎨  simplify transaction creation and test
  • Loading branch information
kirrg001 authored and ErisDS committed Sep 30, 2016
1 parent 6842259 commit 1867e1a
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 24 deletions.
2 changes: 1 addition & 1 deletion core/server/data/migration/fixtures/populate.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ createOwner = function createOwner(logger, modelOptions) {
password: coreUtils.uid(50)
};

return models.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
return models.Role.findOne({name: 'Owner'}, modelOptions).then(function (ownerRole) {
if (ownerRole) {
user.roles = [ownerRole.id];

Expand Down
26 changes: 16 additions & 10 deletions core/server/data/migration/populate.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// # Populate
// Create a brand new database for a new install of ghost
var Promise = require('bluebird'),
_ = require('lodash'),
commands = require('../schema').commands,
fixtures = require('./fixtures'),
errors = require('../../errors'),
db = require('../../data/db'),
schema = require('../schema').tables,
schemaTables = Object.keys(schema),
populate, logger;
Expand All @@ -30,20 +32,24 @@ populate = function populate(options) {
context: {
internal: true
}
},
tableSequence = Promise.mapSeries(schemaTables, function createTable(table) {
logger.info('Creating table: ' + table);
return commands.createTable(table);
});
};

logger.info('Creating tables...');

if (tablesOnly) {
return tableSequence;
}
return db.knex.transaction(function populateDatabaseInTransaction(transaction) {
return Promise.mapSeries(schemaTables, function createTable(table) {
logger.info('Creating table: ' + table);
return commands.createTable(table, transaction);
}).then(function populateFixtures() {
if (tablesOnly) {
return;
}

return tableSequence.then(function () {
return fixtures.populate(logger, modelOptions);
return fixtures.populate(logger, _.merge({}, {transacting: transaction}, modelOptions));
});
}).catch(function populateDatabaseError(err) {
logger.warn('rolling back...');
return Promise.reject(new errors.InternalServerError('Unable to populate database: ' + err.message));
});
};

Expand Down
36 changes: 24 additions & 12 deletions core/test/unit/migration_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,12 @@ describe('Migrations', function () {
var createStub, fixturesStub;

beforeEach(function () {
createStub = sandbox.stub(schema.commands, 'createTable').returns(new Promise.resolve());
fixturesStub = sandbox.stub(fixtures, 'populate').returns(new Promise.resolve());
});

it('should create all tables, and populate fixtures', function (done) {
createStub = sandbox.stub(schema.commands, 'createTable').returns(new Promise.resolve());

populate().then(function (result) {
should.not.exist(result);

Expand All @@ -190,18 +191,29 @@ describe('Migrations', function () {
}).catch(done);
});

it('should should only create tables, with tablesOnly setting', function (done) {
populate({tablesOnly: true}).then(function (result) {
should.exist(result);
result.should.be.an.Array().with.lengthOf(schemaTables.length);
it('should rollback if error occurs', function (done) {
var i = 0;

createStub.called.should.be.true();
createStub.callCount.should.be.eql(schemaTables.length);
createStub.firstCall.calledWith(schemaTables[0]).should.be.true();
createStub.lastCall.calledWith(schemaTables[schemaTables.length - 1]).should.be.true();
fixturesStub.called.should.be.false();
done();
}).catch(done);
createStub = sandbox.stub(schema.commands, 'createTable', function () {
i = i + 1;

if (i > 10) {
return new Promise.reject(new Error('error on table creation :('));
}

return new Promise.resolve();
});

populate()
.then(function () {
done(new Error('should throw an error for database population'));
})
.catch(function (err) {
should.exist(err);
(err instanceof errors.InternalServerError).should.eql(true);
createStub.callCount.should.eql(11);
done();
});
});
});

Expand Down
8 changes: 7 additions & 1 deletion core/test/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,13 @@ getFixtureOps = function getFixtureOps(toDos) {
// Database initialisation
if (toDos.init || toDos.default) {
fixtureOps.push(function initDB() {
return migration.populate({tablesOnly: tablesOnly});
return new Promise(function initDb(resolve, reject) {
migration.populate({tablesOnly: tablesOnly})
.then(function () {
resolve();
})
.catch(reject);
});
});

delete toDos.default;
Expand Down

0 comments on commit 1867e1a

Please sign in to comment.