mirror of
https://github.com/strapi/strapi.git
synced 2025-11-16 01:57:56 +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;
|
const history = () => {
|
||||||
try {
|
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) {
|
} catch (err) {
|
||||||
// File not existing
|
// File not existing
|
||||||
history = {};
|
return {};
|
||||||
}
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
// Register every model.
|
// Register every model.
|
||||||
const migrations = glob.sync(path.resolve(scope.rootPath, 'api', '**', 'models', '*.json')).map((file) => {
|
const migrations = glob.sync(path.resolve(scope.rootPath, 'api', '**', 'models', '*.json')).map((filepath) => {
|
||||||
let modelName;
|
try {
|
||||||
|
const file = JSON.parse(fs.readFileSync(path.resolve(filepath)));
|
||||||
|
|
||||||
// Only create migration file for the models with the specified connection.
|
// 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.
|
||||||
|
const modelName = _.get(file, 'tableName');
|
||||||
|
scope.models[modelName] = file;
|
||||||
|
|
||||||
// Save the model name thanks to the given table name.
|
if (!_.isEmpty(history) && history.hasOwnProperty(_.capitalize(modelName))) {
|
||||||
modelName = JSON.parse(fs.readFileSync(path.resolve(file))).tableName;
|
_.set(scope.models, modelName + '.oldAttributes', _.get(history, _.capitalize(modelName) + '.attributes'));
|
||||||
scope.models[modelName] = JSON.parse(fs.readFileSync(path.resolve(file)));
|
} else {
|
||||||
|
_.set(scope.models, modelName + '.oldAttributes', {});
|
||||||
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 the table already exists.
|
// First, we need to know if the table already exists.
|
||||||
else {
|
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
|
// Builder: create template for each attribute-- either with a column type
|
||||||
// to see if they still are the same.
|
// or with a relationship.
|
||||||
|
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
|
||||||
// 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.
|
|
||||||
if (details.type && _.isString(details.type)) {
|
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)) {
|
} 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: create and drop the table.
|
||||||
builder.selectTable(scope.models, modelName);
|
builder.createTable(scope.models, modelName);
|
||||||
} else {
|
} else {
|
||||||
// If the column already exists.
|
// If the table already exists.
|
||||||
|
|
||||||
let toDrop = false;
|
// Set new attributes object
|
||||||
|
_.set(scope.models[modelName], 'newAttributes', {});
|
||||||
|
|
||||||
// Try to identify relation attribute update
|
// Parse every attribute.
|
||||||
if (details.hasOwnProperty('collection') && details.hasOwnProperty('via') &&
|
_.forEach(scope.models[modelName].attributes, function (details, attribute) {
|
||||||
(_.get(scope.models[modelName].oldAttributes[attribute], 'collection') !== details.collection || _.get(scope.models[modelName].oldAttributes[attribute], 'via') !== details.via)) {
|
// If it's a new attribute.
|
||||||
toDrop = true;
|
if (!scope.models[modelName].oldAttributes.hasOwnProperty(attribute)) {
|
||||||
} 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) {
|
|
||||||
// Save the attribute as a new attribute.
|
// Save the attribute as a new attribute.
|
||||||
scope.models[modelName].newAttributes[attribute] = _.cloneDeep(details);
|
scope.models[modelName].newAttributes[attribute] = _.cloneDeep(details);
|
||||||
|
|
||||||
// Builder: create template for each attribute-- either with a column type
|
// Builder: create template for each attribute-- either with a column type
|
||||||
// or with a relationship.
|
// or with a relationship.
|
||||||
if (details.type && _.isString(details.type)) {
|
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)) {
|
} 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.
|
// Try to identify attribute updates
|
||||||
builder.selectTable(scope.models, modelName);
|
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) => {
|
// For lightweight migration file,
|
||||||
asyncFunction(file, resolve);
|
// 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) {
|
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.
|
// Template: select the table for the `up` export.
|
||||||
// Every attribute with `create` key will be added in this template.
|
// 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');
|
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,
|
models: models,
|
||||||
tableName: modelName,
|
tableName: modelName,
|
||||||
attributes: models[modelName].newAttributes,
|
attributes: models[modelName].newAttributes,
|
||||||
toDrop: true
|
toDrop: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
models[modelName].up.others = _.unescape(_.template(tplSelectTableUp)({
|
models[modelName].up.others += _.unescape(_.template(tplSelectTableUp)({
|
||||||
models: models,
|
models: models,
|
||||||
tableName: modelName,
|
tableName: modelName,
|
||||||
attributes: models[modelName].newAttributes,
|
attributes: models[modelName].newAttributes,
|
||||||
toDrop: false
|
toDrop: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
models[modelName].down = {};
|
if (!models[modelName].hasOwnProperty('down')) {
|
||||||
|
models[modelName].down = {
|
||||||
|
drop: '',
|
||||||
|
others: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Template: select the table for the `down` export.
|
// Template: select the table for the `down` export.
|
||||||
// Every attribute with `delete` key will be added in this template.
|
// 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');
|
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,
|
models: models,
|
||||||
tableName: modelName,
|
tableName: modelName,
|
||||||
attributes: models[modelName].newAttributes,
|
attributes: models[modelName].newAttributes,
|
||||||
toDrop: true
|
toDrop: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
models[modelName].down.others = _.unescape(_.template(tplSelectTableDown)({
|
models[modelName].down.others += _.unescape(_.template(tplSelectTableDown)({
|
||||||
models: models,
|
models: models,
|
||||||
tableName: modelName,
|
tableName: modelName,
|
||||||
attributes: models[modelName].newAttributes,
|
attributes: models[modelName].newAttributes,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user