Handle migration on many-to-many remove

This commit is contained in:
Aurélien Georget 2016-04-14 13:18:17 +02:00
parent 3efce9592e
commit 50ff64f6e9
5 changed files with 68 additions and 37 deletions

View File

@ -76,10 +76,14 @@ module.exports = function afterGenerate(scope, cb) {
return _.omitBy(model, _.isFunction);
});
const modelsKeyLowercased = _.mapKeys(models, function (model, key) {
return key.toLowerCase();
});
const historyFile = path.resolve(scope.rootPath, 'data', 'migrations', '.history');
// And rewrite it with the beautify node module.
fs.writeFile(historyFile, beautify(JSON.stringify(models), {
fs.writeFile(historyFile, beautify(JSON.stringify(modelsKeyLowercased), {
indent_size: 2,
keep_function_indentation: true,
space_before_conditional: true,

View File

@ -96,8 +96,8 @@ module.exports = function (scope, cb) {
const modelName = _.get(file, 'tableName');
scope.models[modelName] = file;
if (!_.isEmpty(history) && history.hasOwnProperty(_.capitalize(modelName))) {
_.set(scope.models, modelName + '.oldAttributes', _.get(history, _.capitalize(modelName) + '.attributes'));
if (!_.isEmpty(history) && history.hasOwnProperty(modelName)) {
_.set(scope.models, modelName + '.oldAttributes', _.get(history, modelName + '.attributes'));
} else {
_.set(scope.models, modelName + '.oldAttributes', {});
}

View File

@ -24,7 +24,7 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
let tplRelationUp;
let tplRelationDown;
const infos = utilsModels.getNature(details, attribute, models);
const infos = toDrop ? utilsModels.getNature(details, attribute, history) : utilsModels.getNature(details, attribute, models);
_.set(models[modelName].attributes, attribute + '.create', {});
_.set(models[modelName].attributes, attribute + '.delete', {});
@ -111,21 +111,26 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
} else if (infos.verbose === 'belongsToMany') {
// Otherwise if it's a "many-to-many" relationship.
// Save the relationship.
const relationship = models[details.collection].attributes[details.via];
let relationship;
let relationTable;
// Construct relation table name.
const relationTable = _.map(_.sortBy([relationship, details], 'collection'), function (table) {
return _.snakeCase(pluralize.plural(table.collection) + ' ' + pluralize.plural(table.via));
}).join('__');
if (!onlyDrop) {
// Save the relationship.
relationship = models[details.collection].attributes[details.via];
// Force singular foreign key.
relationship.attribute = pluralize.singular(relationship.collection);
details.attribute = pluralize.singular(details.collection);
// Construct relation table name.
relationTable = _.map(_.sortBy([relationship, details], 'collection'), function (table) {
return _.snakeCase(pluralize.plural(table.collection) + ' ' + pluralize.plural(table.via));
}).join('__');
// Define PK column.
details.column = utilsBookShelf.getPK(modelName, undefined, models);
relationship.column = utilsBookShelf.getPK(details.collection, undefined, models);
// Force singular foreign key.
relationship.attribute = pluralize.singular(relationship.collection);
details.attribute = pluralize.singular(details.collection);
// Define PK column.
details.column = utilsBookShelf.getPK(modelName, undefined, models);
relationship.column = utilsBookShelf.getPK(details.collection, undefined, models);
}
// Avoid to create table both times.
if (!models.hasOwnProperty(relationTable) || !_.isEmpty(_.get(models, relationTable + '.up.drop'))) {
@ -191,7 +196,6 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
toDrop: true
}));
} else {
console.log("test", attribute, modelName);
// Drop current relationships table on migration rollback.
models[relationTable].down.drop += _.unescape(_.template(tplTableDown)({
tableName: relationTable
@ -203,7 +207,7 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
const tplTableDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'dropTable.template'), 'utf8');
// Save the old relationship.
const oldRelationship = history[_.capitalize(details.collection)].attributes[details.via];
const oldRelationship = history[details.collection].attributes[details.via];
// Construct old relation table name.
const oldRelationTable = _.map(_.sortBy([oldRelationship, details], 'collection'), function (table) {
@ -212,15 +216,24 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
// Force singular foreign key.
oldRelationship.attribute = pluralize.singular(oldRelationship.collection);
details.attribute = pluralize.singular(details.collection);
// Define PK column.
oldRelationship.column = utilsBookShelf.getPK(details.collection, undefined, models);
details.column = utilsBookShelf.getPK(modelName, undefined, models);
// Drop current relationships table on migration run.
models[relationTable].up.drop += _.unescape(_.template(tplTableDown)({
const dropMigrationTable = _.unescape(_.template(tplTableDown)({
tableName: oldRelationTable || relationTable
}));
if (models[relationTable].up.drop.indexOf(dropMigrationTable) === -1) {
// Drop current relationships table on migration run.
models[relationTable].up.drop += _.unescape(_.template(tplTableDown)({
tableName: oldRelationTable || relationTable
}));
}
// Drop current relationships table on migration rollback.
// This allows us to identify, if this is an update on already existing many-to-many relationship or if this is a basic addition.
if (_.isUndefined(_.get(models, relationTable + '.attributes.fk'))) {
@ -231,15 +244,15 @@ module.exports = function (models, modelName, details, attribute, toDrop, onlyDr
}))
}
};
} else {
// Create previous relationships table on migration rollback.
models[relationTable].down.others += _.unescape(_.template(tplTableUp)({
models: models,
tableName: oldRelationTable || relationTable,
details: details,
relationship: oldRelationship || relationship
}));
}
// Create previous relationships table on migration rollback.
models[relationTable].down.others += _.unescape(_.template(tplTableUp)({
models: models,
tableName: oldRelationTable || relationTable,
details: details,
relationship: oldRelationship || relationship
}));
}
}
}

View File

@ -8,21 +8,29 @@
*/
exports.up = function(connection, Promise) {
<% var dropped = false;
<% var dropped = false; var onlyDrop = true;
_.forEach(models, function (definition, model) {
if (!_.isEmpty(_.get(models[model], 'up.drop'))) {
dropped = true;
}
if (!_.isEmpty(_.get(models[model], 'up.others'))) {
onlyDrop = false;
}
});
if (dropped) { %> return Promise.all([
if (dropped === true && onlyDrop === false) { %> return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'up.drop') %><% }); %>
]).then(function() {
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'up.others') %><% }); %>
]);
});
<% } else if (dropped === true && onlyDrop === true) { %>
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'up.drop') %><% }); %>
]);
<% } else { %>
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'up.others') %><% }); %>
@ -38,17 +46,19 @@ exports.up = function(connection, Promise) {
*/
exports.down = function(connection, Promise) {
<% var dropped = false;
<% var dropped = false; var onlyDrop = true;
_.forEach(models, function (definition, model) {
if (!_.isEmpty(_.get(models[model], 'down.drop'))) {
dropped = true;
}
if (!_.isEmpty(_.get(models[model], 'down.others'))) {
onlyDrop = false;
}
});
console.log("DROPPPED " + dropped);
if (dropped) { %>
if (dropped === true && onlyDrop === false) { %>
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'down.drop') %><% }); %>
]).then(function() {
@ -56,6 +66,10 @@ exports.down = function(connection, Promise) {
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'down.others') %><% }); %>
]);
});
<% } else if (dropped === true && onlyDrop === true) { %>
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'down.drop') %><% }); %>
]);
<% } else { %>
return Promise.all([
<% _.forEach(models, function(definition, model) { %><%= _.get(models[model], 'down.others') %><% }); %>

View File

@ -70,7 +70,7 @@ module.exports = {
};
if (association.hasOwnProperty('via') && association.hasOwnProperty('collection')) {
const relatedAttribute = strapi.models[association.collection].attributes[association.via];
const relatedAttribute = models[association.collection].attributes[association.via];
types.current = 'collection';
@ -83,7 +83,7 @@ module.exports = {
types.current = 'modelD';
// We have to find if they are a model linked to this key
_.forIn(strapi.models, function (model) {
_.forIn(models, function (model) {
_.forIn(model.attributes, function (attribute) {
if (attribute.hasOwnProperty('via') && attribute.via === key && attribute.hasOwnProperty('collection')) {
types.other = 'collection';
@ -102,7 +102,7 @@ module.exports = {
types.current = 'model';
// We have to find if they are a model linked to this key
_.forIn(strapi.models, function (model) {
_.forIn(models, function (model) {
_.forIn(model.attributes, function (attribute) {
if (attribute.hasOwnProperty('via') && attribute.via === key) {
if (attribute.hasOwnProperty('collection')) {