mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
Generated migration files manages attribute's type update
This commit is contained in:
parent
cb433f57c0
commit
aad090c62d
@ -76,148 +76,133 @@ module.exports = function (scope, cb) {
|
||||
}
|
||||
});
|
||||
|
||||
let history;
|
||||
try {
|
||||
history = JSON.parse(fs.readFileSync(path.resolve(scope.rootPath, 'data', 'migrations', '.history'), 'utf8'));
|
||||
} catch (err) {
|
||||
// File not existing
|
||||
history = {};
|
||||
}
|
||||
const history = () => {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(path.resolve(scope.rootPath, 'data', 'migrations', '.history'), 'utf8'));
|
||||
} catch (err) {
|
||||
// File not existing
|
||||
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) {
|
||||
// Only create migration file for the models with the specified connection.
|
||||
if (_.get(file, 'connection') === _.get(scope, 'connection')) {
|
||||
// Save the model name thanks to the given table name.
|
||||
const modelName = _.get(file, 'tableName');
|
||||
scope.models[modelName] = file;
|
||||
|
||||
// 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)));
|
||||
|
||||
if (!_.isEmpty(history) && history.hasOwnProperty(_.capitalize(modelName))) {
|
||||
_.set(scope.models, modelName + '.oldAttributes', _.get(history, _.capitalize(modelName) + '.attributes'));
|
||||
} else {
|
||||
_.set(scope.models, modelName + '.oldAttributes', {});
|
||||
}
|
||||
|
||||
// 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) {
|
||||
builder.options(scope.models, modelName, value, option);
|
||||
});
|
||||
|
||||
// Builder: create template for each attribute-- either with a column type
|
||||
// or with a relationship.
|
||||
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
|
||||
if (details.type && _.isString(details.type)) {
|
||||
builder.types(scope.models, modelName, details, attribute);
|
||||
} else if (_.isString(details.collection) || _.isString(details.model)) {
|
||||
builder.relations(scope.models, modelName, details, attribute);
|
||||
}
|
||||
});
|
||||
|
||||
// Builder: create and drop the table.
|
||||
builder.createTable(scope.models, modelName);
|
||||
if (!_.isEmpty(history) && history.hasOwnProperty(_.capitalize(modelName))) {
|
||||
_.set(scope.models, modelName + '.oldAttributes', _.get(history, _.capitalize(modelName) + '.attributes'));
|
||||
} else {
|
||||
_.set(scope.models, modelName + '.oldAttributes', {});
|
||||
}
|
||||
|
||||
// If the table already exists.
|
||||
else {
|
||||
// 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) {
|
||||
builder.options(scope.models, modelName, value, option);
|
||||
});
|
||||
|
||||
// Ideally, we need to verify the table properties here
|
||||
// to see if they still are the same.
|
||||
|
||||
// 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.
|
||||
scope.models[modelName].newAttributes[attribute] = _.cloneDeep(details);
|
||||
|
||||
// Builder: create template for each attribute-- either with a column type
|
||||
// or with a relationship.
|
||||
// Builder: create template for each attribute-- either with a column type
|
||||
// or with a relationship.
|
||||
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
|
||||
if (details.type && _.isString(details.type)) {
|
||||
builder.types(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute);
|
||||
builder.types(scope.models, modelName, details, attribute);
|
||||
} else if (_.isString(details.collection) || _.isString(details.model)) {
|
||||
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute);
|
||||
builder.relations(scope.models, modelName, details, attribute);
|
||||
}
|
||||
});
|
||||
|
||||
// Builder: select the table.
|
||||
builder.selectTable(scope.models, modelName);
|
||||
} else {
|
||||
// If the column already exists.
|
||||
// Builder: create and drop the table.
|
||||
builder.createTable(scope.models, modelName);
|
||||
} else {
|
||||
// If the table already exists.
|
||||
|
||||
let toDrop = false;
|
||||
// Set new attributes object
|
||||
_.set(scope.models[modelName], 'newAttributes', {});
|
||||
|
||||
// Try to identify relation attribute update
|
||||
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;
|
||||
} 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;
|
||||
} else if (details.hasOwnProperty('model') &&
|
||||
(_.get(scope.models[modelName].oldAttributes[attribute], 'model') !== details.model)) {
|
||||
toDrop = true;
|
||||
} else if (!_.isUndefined(details.type) && _.get(scope.models[modelName].oldAttributes[attribute], 'type') !== _.get(details, 'type')) {
|
||||
toDrop = true;
|
||||
} else if (!_.isUndefined(details.defaultValue) && _.get(scope.models[modelName].oldAttributes[attribute], 'defaultValue') === _.get(details, 'defaultValue')) {
|
||||
toDrop = true;
|
||||
} else if (!_.isUndefined(details.maxLength) && _.get(scope.models[modelName].oldAttributes[attribute], 'maxLength') === _.get(details, 'maxLength')) {
|
||||
toDrop = true;
|
||||
} else if (!_.isUndefined(details.nullable) && _.get(scope.models[modelName].oldAttributes[attribute], 'nullable') === _.get(details, 'nullable')) {
|
||||
toDrop = true;
|
||||
}
|
||||
|
||||
// The attribute has been updated.
|
||||
// We will drop it then create it again with the new options.
|
||||
if (toDrop) {
|
||||
// Parse every attribute.
|
||||
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
|
||||
// If it's a new attribute.
|
||||
if (!scope.models[modelName].oldAttributes.hasOwnProperty(attribute)) {
|
||||
// Save the attribute as a new attribute.
|
||||
scope.models[modelName].newAttributes[attribute] = _.cloneDeep(details);
|
||||
|
||||
// Builder: create template for each attribute-- either with a column type
|
||||
// or with a relationship.
|
||||
if (details.type && _.isString(details.type)) {
|
||||
builder.types(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute, toDrop);
|
||||
builder.types(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute);
|
||||
} else if (_.isString(details.collection) || _.isString(details.model)) {
|
||||
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute, toDrop);
|
||||
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute);
|
||||
}
|
||||
} else {
|
||||
// If it's an existing attribute.
|
||||
|
||||
// Builder: select the table.
|
||||
builder.selectTable(scope.models, modelName);
|
||||
// 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)) {
|
||||
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)) {
|
||||
return true;
|
||||
} else if (details.hasOwnProperty('model') &&
|
||||
(_.get(scope.models[modelName].oldAttributes[attribute], 'model') !== details.model)) {
|
||||
return true;
|
||||
} else if (!_.isUndefined(details.type) && _.get(scope.models[modelName].oldAttributes[attribute], 'type') !== _.get(details, 'type')) {
|
||||
return true;
|
||||
} else if (!_.isUndefined(details.defaultValue) && _.get(scope.models[modelName].oldAttributes[attribute], 'defaultValue') === _.get(details, 'defaultValue')) {
|
||||
return true;
|
||||
} else if (!_.isUndefined(details.maxLength) && _.get(scope.models[modelName].oldAttributes[attribute], 'maxLength') === _.get(details, 'maxLength')) {
|
||||
return true;
|
||||
} else if (!_.isUndefined(details.nullable) && _.get(scope.models[modelName].oldAttributes[attribute], 'nullable') === _.get(details, 'nullable')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}();
|
||||
|
||||
// The attribute has been updated.
|
||||
// We will drop it then create it again with the new options.
|
||||
if (toDrop) {
|
||||
// Save the attribute as a new attribute.
|
||||
scope.models[modelName].newAttributes[attribute] = _.cloneDeep(details);
|
||||
|
||||
// Builder: create template for each attribute-- either with a column type
|
||||
// or with a relationship.
|
||||
if (details.type && _.isString(details.type)) {
|
||||
builder.types(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute, toDrop);
|
||||
} else if (_.isString(details.collection) || _.isString(details.model)) {
|
||||
builder.relations(scope.models, modelName, scope.models[modelName].newAttributes[attribute], attribute, toDrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
asyncFunction(file, resolve);
|
||||
});
|
||||
// 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(filepath, resolve);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
return cb.invalid(e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user