Generated migration files manages attribute's type update

This commit is contained in:
Aurélien Georget 2016-03-23 16:07:39 +01:00
parent cb433f57c0
commit aad090c62d
2 changed files with 119 additions and 124 deletions

View File

@ -76,24 +76,25 @@ module.exports = function (scope, cb) {
}
});
let history;
const history = () => {
try {
history = JSON.parse(fs.readFileSync(path.resolve(scope.rootPath, 'data', 'migrations', '.history'), 'utf8'));
return JSON.parse(fs.readFileSync(path.resolve(scope.rootPath, 'data', 'migrations', '.history'), 'utf8'));
} catch (err) {
// File not existing
history = {};
return {};
}
}();
// Register every model.
const migrations = glob.sync(path.resolve(scope.rootPath, 'api', '**', 'models', '*.json')).map((file) => {
let modelName;
const migrations = glob.sync(path.resolve(scope.rootPath, 'api', '**', 'models', '*.json')).map((filepath) => {
try {
const file = JSON.parse(fs.readFileSync(path.resolve(filepath)));
// Only create migration file for the models with the specified connection.
if (JSON.parse(fs.readFileSync(path.resolve(file))).connection === scope.connection) {
if (_.get(file, 'connection') === _.get(scope, 'connection')) {
// Save the model name thanks to the given table name.
modelName = JSON.parse(fs.readFileSync(path.resolve(file))).tableName;
scope.models[modelName] = JSON.parse(fs.readFileSync(path.resolve(file)));
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'));
@ -103,10 +104,8 @@ module.exports = function (scope, cb) {
// First, we need to know if the table already exists.
scope.db.schema.hasTable(modelName).then(function (exists) {
// If the table doesn't exist.
if (!exists) {
// Builder: add needed options specified in the model
// for each option.
_.forEach(scope.models[modelName].options, function (value, option) {
@ -125,34 +124,14 @@ module.exports = function (scope, cb) {
// Builder: create and drop the table.
builder.createTable(scope.models, modelName);
}
} else {
// If the table already exists.
else {
// Ideally, we need to verify the table properties here
// to see if they still are the same.
// Set new attributes object
_.set(scope.models[modelName], 'newAttributes', {});
// Parse every attribute.
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
// TODO:
// - Column is existing ?
// -- YES:
// --- Compare current type with last one (nullable, maxLenght, type, defaultValue).
// ---- Updated ? Drop column, and create a new one.
// ---- Not updated ? Do nothing.
// -- NO:
// --- Add the new column
// scope.db.schema.hasColumn(modelName, attribute).then(function (exists) {
//
// }).catch(function (err) {
// console.log(err);
// });
// Verify if a column already exists for the attribute.
scope.models[modelName].newAttributes = {};
// If it's a new attribute.
if (!scope.models[modelName].oldAttributes.hasOwnProperty(attribute)) {
// Save the attribute as a new attribute.
@ -165,33 +144,32 @@ module.exports = function (scope, cb) {
} else if (_.isString(details.collection) || _.isString(details.model)) {
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute);
}
// Builder: select the table.
builder.selectTable(scope.models, modelName);
} else {
// If the column already exists.
// If it's an existing attribute.
let toDrop = false;
// Try to identify relation attribute update
// Try to identify attribute updates
const toDrop = () => {
if (details.hasOwnProperty('collection') && details.hasOwnProperty('via') &&
(_.get(scope.models[modelName].oldAttributes[attribute], 'collection') !== details.collection || _.get(scope.models[modelName].oldAttributes[attribute], 'via') !== details.via)) {
toDrop = true;
return true;
} else if (details.hasOwnProperty('model') && details.hasOwnProperty('via') &&
(_.get(scope.models[modelName].oldAttributes[attribute], 'model') !== details.model || _.get(scope.models[modelName].oldAttributes[attribute], 'via') !== details.via)) {
toDrop = true;
return true;
} else if (details.hasOwnProperty('model') &&
(_.get(scope.models[modelName].oldAttributes[attribute], 'model') !== details.model)) {
toDrop = true;
return true;
} else if (!_.isUndefined(details.type) && _.get(scope.models[modelName].oldAttributes[attribute], 'type') !== _.get(details, 'type')) {
toDrop = true;
return true;
} else if (!_.isUndefined(details.defaultValue) && _.get(scope.models[modelName].oldAttributes[attribute], 'defaultValue') === _.get(details, 'defaultValue')) {
toDrop = true;
return true;
} else if (!_.isUndefined(details.maxLength) && _.get(scope.models[modelName].oldAttributes[attribute], 'maxLength') === _.get(details, 'maxLength')) {
toDrop = true;
return true;
} else if (!_.isUndefined(details.nullable) && _.get(scope.models[modelName].oldAttributes[attribute], 'nullable') === _.get(details, 'nullable')) {
toDrop = true;
return true;
} else {
return false;
}
}();
// The attribute has been updated.
// We will drop it then create it again with the new options.
@ -206,19 +184,26 @@ module.exports = function (scope, cb) {
} else if (_.isString(details.collection) || _.isString(details.model)) {
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute, toDrop);
}
}
}
});
// For lightweight migration file,
// only call this when new attributes are detected.
if (!_.isEmpty(scope.models[modelName].newAttributes)) {
// Builder: select the table.
builder.selectTable(scope.models, modelName);
}
}
});
}
});
return new Promise((resolve) => {
asyncFunction(file, resolve);
asyncFunction(filepath, resolve);
});
}
} catch (e) {
return cb.invalid(e);
}
});
function asyncFunction(item, cb) {

View File

@ -17,38 +17,48 @@ const _ = require('lodash');
module.exports = function (models, modelName) {
models[modelName].up = {};
if (!models[modelName].hasOwnProperty('up')) {
models[modelName].up = {
drop: '',
others: ''
};
}
// Template: select the table for the `up` export.
// Every attribute with `create` key will be added in this template.
const tplSelectTableUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'select', 'up.template'), 'utf8');
models[modelName].up.drop = _.unescape(_.template(tplSelectTableUp)({
models[modelName].up.drop += _.unescape(_.template(tplSelectTableUp)({
models: models,
tableName: modelName,
attributes: models[modelName].newAttributes,
toDrop: true
}));
models[modelName].up.others = _.unescape(_.template(tplSelectTableUp)({
models[modelName].up.others += _.unescape(_.template(tplSelectTableUp)({
models: models,
tableName: modelName,
attributes: models[modelName].newAttributes,
toDrop: false
}));
models[modelName].down = {};
if (!models[modelName].hasOwnProperty('down')) {
models[modelName].down = {
drop: '',
others: ''
};
}
// Template: select the table for the `down` export.
// Every attribute with `delete` key will be added in this template.
const tplSelectTableDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'select', 'down.template'), 'utf8');
models[modelName].down.drop = _.unescape(_.template(tplSelectTableDown)({
models[modelName].down.drop += _.unescape(_.template(tplSelectTableDown)({
models: models,
tableName: modelName,
attributes: models[modelName].newAttributes,
toDrop: true
}));
models[modelName].down.others = _.unescape(_.template(tplSelectTableDown)({
models[modelName].down.others += _.unescape(_.template(tplSelectTableDown)({
models: models,
tableName: modelName,
attributes: models[modelName].newAttributes,