Merge pull request #3891 from jaswilli/import-tests

Run import run operations in order.
This commit is contained in:
Hannah Wolfe 2014-08-28 18:43:53 +01:00
commit 589da7deee
4 changed files with 89 additions and 42 deletions

View File

@ -93,10 +93,9 @@ Importer000.prototype.doUserImport = function (t, tableData, users, errors) {
Importer000.prototype.doImport = function (data) {
var self = this,
ops = [],
errors = [],
tableData = data.data,
imported = {},
errors = [],
users = {},
owner = {};
@ -108,6 +107,8 @@ Importer000.prototype.doImport = function (data) {
// Step 1: Attempt to handle adding new users
self.doUserImport(t, tableData, users, errors).then(function (result) {
var importResults = [];
imported.users = result;
_.each(imported.users, function (user) {
@ -126,33 +127,28 @@ Importer000.prototype.doImport = function (data) {
tableData = utils.preProcessPostTags(tableData);
}
// Import things in the right order:
if (tableData.tags && tableData.tags.length) {
utils.importTags(ops, tableData.tags, t);
}
// Import things in the right order
if (tableData.posts && tableData.posts.length) {
utils.importPosts(ops, tableData.posts, t);
}
return utils.importTags(tableData.tags, t).then(function (results) {
if (results) {
importResults = importResults.concat(results);
}
if (tableData.settings && tableData.settings.length) {
utils.importSettings(ops, tableData.settings, t);
}
return utils.importPosts(tableData.posts, t);
}).then(function (results) {
if (results) {
importResults = importResults.concat(results);
}
/** do nothing with these tables, the data shouldn't have changed from the fixtures
* permissions
* roles
* permissions_roles
* permissions_users
*/
// Write changes to DB, if successful commit, otherwise rollback
Promise.settle(ops).then(function (descriptors) {
var errors = [];
descriptors.forEach(function (d) {
if (d.isRejected()) {
errors = errors.concat(d.reason());
return utils.importSettings(tableData.settings, t);
}).then(function (results) {
if (results) {
importResults = importResults.concat(results);
}
}).then(function () {
importResults.forEach(function (p) {
if (p.isRejected()) {
errors = errors.concat(p.reason());
}
});
@ -162,6 +158,13 @@ Importer000.prototype.doImport = function (data) {
t.rollback(errors);
}
});
/** do nothing with these tables, the data shouldn't have changed from the fixtures
* permissions
* roles
* permissions_roles
* permissions_users
*/
});
}).then(function () {
//TODO: could return statistics of imported items

View File

@ -30,11 +30,13 @@ cleanError = function cleanError(error) {
offendingProperty = temp.length === 2 ? temp[1] : error.model;
temp = offendingProperty.split('.');
value = temp.length === 2 ? error.data[temp[1]] : 'unknown';
} else if (error.raw.detail) {
value = error.raw.detail;
offendingProperty = error.model;
}
message = 'Duplicate entry found. Multiple values of "' + value + '" found for ' + offendingProperty + '.';
}
offendingProperty = offendingProperty || error.model;
value = value || 'unknown';
message = message || error.raw.message;

View File

@ -149,7 +149,13 @@ utils = {
return tableData;
},
importTags: function importTags(ops, tableData, transaction) {
importTags: function importTags(tableData, transaction) {
if (!tableData) {
return Promise.resolve();
}
var ops = [];
tableData = stripProperties(['id'], tableData);
_.each(tableData, function (tag) {
// Validate minimum tag fields
@ -160,7 +166,6 @@ utils = {
ops.push(models.Tag.findOne({name: tag.name}, {transacting: transaction}).then(function (_tag) {
if (!_tag) {
return models.Tag.add(tag, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) {
return Promise.reject({raw: error, model: 'tag', data: tag});
});
@ -169,21 +174,46 @@ utils = {
return _tag;
}));
});
return Promise.settle(ops);
},
importPosts: function importPosts(ops, tableData, transaction) {
importPosts: function importPosts(tableData, transaction) {
if (!tableData) {
return Promise.resolve();
}
var ops = [];
tableData = stripProperties(['id'], tableData);
_.each(tableData, function (post) {
// Validate minimum post fields
if (areEmpty(post, 'title', 'slug', 'markdown')) {
return;
}
ops.push(models.Post.add(post, _.extend(internal, {transacting: transaction, importing: true}))
// add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) {
return Promise.reject({raw: error, model: 'post', data: post});
}));
ops.push(function () {
return models.Post.add(post, _.extend(internal, {transacting: transaction, importing: true}))
.catch(function (error) {
return Promise.reject({raw: error, model: 'post', data: post});
});
});
});
return Promise.reduce(ops, function (results, op) {
return op().then(function (result) {
results.push(result);
return results;
}).catch(function (error) {
if (error) {
results.push(error);
}
return results;
});
}, []).settle();
},
importUsers: function importUsers(tableData, existingUsers, transaction) {
@ -206,7 +236,6 @@ utils = {
user.status = 'locked';
ops.push(models.User.add(user, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) {
return Promise.reject({raw: error, model: 'user', data: user});
}));
@ -215,11 +244,16 @@ utils = {
return ops;
},
importSettings: function importSettings(ops, tableData, transaction) {
importSettings: function importSettings(tableData, transaction) {
if (!tableData) {
return Promise.resolve();
}
// for settings we need to update individual settings, and insert any missing ones
// settings we MUST NOT update are 'core' and 'theme' settings
// as all of these will cause side effects which don't make sense for an import
var blackList = ['core', 'theme'];
var blackList = ['core', 'theme'],
ops = [];
tableData = stripProperties(['id'], tableData);
tableData = _.filter(tableData, function (data) {
@ -232,21 +266,27 @@ utils = {
});
ops.push(models.Settings.edit(tableData, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) {
return Promise.reject({raw: error, model: 'setting', data: tableData});
}));
return Promise.settle(ops);
},
/** For later **/
importApps: function importApps(ops, tableData, transaction) {
importApps: function importApps(tableData, transaction) {
if (!tableData) {
return Promise.resolve();
}
var ops = [];
tableData = stripProperties(['id'], tableData);
_.each(tableData, function (app) {
// Avoid duplicates
ops.push(models.App.findOne({name: app.name}, {transacting: transaction}).then(function (_app) {
if (!_app) {
return models.App.add(app, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) {
return Promise.reject({raw: error, model: 'app', data: app});
});
@ -255,6 +295,8 @@ utils = {
return _app;
}));
});
return Promise.settle(ops);
}
};

View File

@ -144,7 +144,7 @@ Post = ghostBookshelf.Model.extend({
createdTag = createdTag.toJSON();
// _.omit(options, 'query') is a fix for using bookshelf 0.6.8
// (https://github.com/tgriesser/bookshelf/issues/294)
return post.tags().attach(createdTag.id, createdTag.name, _.omit(options, 'query'));
return post.tags().attach(createdTag.id, _.omit(options, 'query'));
});
tagOps.push(createAndAttachOperation);