不要怂,就是干,撸起袖子干!

Commit bc87076a by Florian Schmidt Committed by Sushant

feat(sync): allow to bypass drop statements when sync with alter enabled (#11708)

1 parent 4dbabc0e
......@@ -1309,35 +1309,39 @@ class Model {
changes.push(() => this.QueryInterface.addColumn(this.getTableName(options), attributes[columnName].field || columnName, attributes[columnName]));
}
});
_.each(columns, (columnDesc, columnName) => {
const currentAttribute = rawAttributes[columnName];
if (!currentAttribute) {
changes.push(() => this.QueryInterface.removeColumn(this.getTableName(options), columnName, options));
} else if (!currentAttribute.primaryKey) {
if (options.alter === true || typeof options.alter === 'object' && options.alter.drop !== false) {
_.each(columns, (columnDesc, columnName) => {
const currentAttribute = rawAttributes[columnName];
if (!currentAttribute) {
changes.push(() => this.QueryInterface.removeColumn(this.getTableName(options), columnName, options));
} else if (!currentAttribute.primaryKey) {
// Check foreign keys. If it's a foreign key, it should remove constraint first.
const references = currentAttribute.references;
if (currentAttribute.references) {
const database = this.sequelize.config.database;
const schema = this.sequelize.config.schema;
// Find existed foreign keys
_.each(foreignKeyReferences, foreignKeyReference => {
const constraintName = foreignKeyReference.constraintName;
if (!!constraintName
&& foreignKeyReference.tableCatalog === database
&& (schema ? foreignKeyReference.tableSchema === schema : true)
&& foreignKeyReference.referencedTableName === references.model
&& foreignKeyReference.referencedColumnName === references.key
&& (schema ? foreignKeyReference.referencedTableSchema === schema : true)
&& !removedConstraints[constraintName]) {
// Remove constraint on foreign keys.
changes.push(() => this.QueryInterface.removeConstraint(this.getTableName(options), constraintName, options));
removedConstraints[constraintName] = true;
}
});
const references = currentAttribute.references;
if (currentAttribute.references) {
const database = this.sequelize.config.database;
const schema = this.sequelize.config.schema;
// Find existed foreign keys
_.each(foreignKeyReferences, foreignKeyReference => {
const constraintName = foreignKeyReference.constraintName;
if (!!constraintName
&& foreignKeyReference.tableCatalog === database
&& (schema ? foreignKeyReference.tableSchema === schema : true)
&& foreignKeyReference.referencedTableName === references.model
&& foreignKeyReference.referencedColumnName === references.key
&& (schema ? foreignKeyReference.referencedTableSchema === schema : true)
&& !removedConstraints[constraintName]) {
// Remove constraint on foreign keys.
changes.push(() => this.QueryInterface.removeConstraint(this.getTableName(options), constraintName, options));
removedConstraints[constraintName] = true;
}
});
}
changes.push(() => this.QueryInterface.changeColumn(this.getTableName(options), columnName, currentAttribute));
}
changes.push(() => this.QueryInterface.changeColumn(this.getTableName(options), columnName, currentAttribute));
}
});
});
}
return Promise.each(changes, f => f());
});
})
......
......@@ -775,7 +775,8 @@ class Sequelize {
* @param {string} [options.schema='public'] The schema that the tables should be created in. This can be overridden for each table in sequelize.define
* @param {string} [options.searchPath=DEFAULT] An optional parameter to specify the schema search_path (Postgres only)
* @param {boolean} [options.hooks=true] If hooks is true then beforeSync, afterSync, beforeBulkSync, afterBulkSync hooks will be called
* @param {boolean} [options.alter=false] Alters tables to fit models. Not recommended for production use. Deletes data in columns that were removed or had their type changed in the model.
* @param {boolean|Object} [options.alter=false] Alters tables to fit models. Provide an object for additional configuration. Not recommended for production use. If not further configured deletes data in columns that were removed or had their type changed in the model.
* @param {boolean} [options.alter.drop=true] Prevents any drop statements while altering a table when set to `false`
*
* @returns {Promise}
*/
......
......@@ -56,6 +56,40 @@ describe(Support.getTestDialectTeaser('Model'), () => {
});
});
it('should not remove columns if drop is set to false in alter configuration', function() {
const testSync = this.sequelize.define('testSync', {
name: Sequelize.STRING,
age: Sequelize.INTEGER
});
return this.sequelize.sync()
.then(() => this.sequelize.define('testSync', {
name: Sequelize.STRING
}))
.then(() => this.sequelize.sync({ alter: { drop: false } }))
.then(() => testSync.describe())
.then(data => {
expect(data).to.have.ownProperty('name');
expect(data).to.have.ownProperty('age');
});
});
it('should remove columns if drop is set to true in alter configuration', function() {
const testSync = this.sequelize.define('testSync', {
name: Sequelize.STRING,
age: Sequelize.INTEGER
});
return this.sequelize.sync()
.then(() => this.sequelize.define('testSync', {
name: Sequelize.STRING
}))
.then(() => this.sequelize.sync({ alter: { drop: true } }))
.then(() => testSync.describe())
.then(data => {
expect(data).to.have.ownProperty('name');
expect(data).not.to.have.ownProperty('age');
});
});
it('should alter a column using the correct column name (#9515)', function() {
const testSync = this.sequelize.define('testSync', {
name: Sequelize.STRING
......
......@@ -34,6 +34,16 @@ import { validator } from './utils/validator-extras';
import { ConnectionManager } from './connection-manager';
/**
* Additional options for table altering during sync
*/
export interface SyncAlterOptions {
/**
* Prevents any drop statements while altering a table when set to `false`
*/
drop?: boolean;
}
/**
* Sync Options
*/
export interface SyncOptions extends Logging {
......@@ -44,9 +54,9 @@ export interface SyncOptions extends Logging {
/**
* If alter is true, each DAO will do ALTER TABLE ... CHANGE ...
* Alters tables to fit models. Not recommended for production use. Deletes data in columns that were removed or had their type changed in the model.
* Alters tables to fit models. Provide an object for additional configuration. Not recommended for production use. If not further configured deletes data in columns that were removed or had their type changed in the model.
*/
alter?: boolean;
alter?: boolean | SyncAlterOptions;
/**
* Match a regex against the database name before syncing, a safety check for cases where force: true is
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!