Продолжить миграцию, изменив столбец на FK, а затем отменить сбой

#node.js #mariadb #sequelize.js

#node.js #mariadb #sequelize.js

Вопрос:

Я пытаюсь создать файл миграции, чтобы изменить столбец на строку (из перечисления) и сослаться на другую таблицу.

 const enumStatus = ['PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE'];

module.exports = {
  up: async(queryInterface, Sequelize) => {
    return Promise.all([
      queryInterface.changeColumn('MeasurementTestResults', 'status', {
        type: Sequelize.STRING,
        allowNull: false
      }), queryInterface.addConstraint('MeasurementTestResults', {
        fields: ['status'],
        type: 'foreign key',
        name: 'statusFk',
        references: {
          table: 'MeasurementTestResultStatusEnums',
          field: 'code'
        },
        onDelete: 'cascade',
        onUpdate: 'cascade'
      })
    ]);
  },

  down: async(queryInterface, Sequelize) => {
    return Promise.all([
      queryInterface.removeConstraint('MeasurementTestResults', 'statusFk'),
      queryInterface.changeColumn('MeasurementTestResults', 'status', {
        type: Sequelize.ENUM(...enumStatus),
        allowNull: false
      })
    ]);
  }
};
 

db: migrate выполняется безупречно, но когда я пытаюсь вызвать db: migrate: undo, он будет выполнять команды не по порядку?

 == 20201217194748-measurementTestResult_changeColumn_status: reverting =======
Executing (default): SELECT CONSTRAINT_CATALOG AS constraintCatalog, CONSTRAINT_NAME AS constraintName, CONSTRAINT_SCHEMA AS constraintSchema, CONSTRAINT_TYPE AS constraintType, TABLE_NAME AS tableName, TABLE_SCHEMA AS tableSchema from INFORMATION_SCHEMA.TABLE_CONSTRA
INTS WHERE table_name='MeasurementTestResults' AND constraint_name = 'statusFk' AND TABLE_SCHEMA = 'iot_crcm_application_data1';
Executing (default): ALTER TABLE `MeasurementTestResults` CHANGE `status` `status` ENUM('PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE') NOT NULL;
Executing (default): ALTER TABLE `MeasurementTestResults`
      DROP FOREIGN KEY `statusFk`;

ERROR: (conn=143438, no: 1832, SQLState: HY000) Cannot change column 'status': used in a foreign key constraint 'statusFk'
sql: ALTER TABLE `MeasurementTestResults` CHANGE `status` `status` ENUM('PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE') NOT NULL; - parameters:[]
 

затем, когда я пытаюсь удалить queryInterface.removeConstraint('MeasurementTestResults', 'statusFk'), эту строку из down script, она работает, но не раньше, чем я попробую ее с ошибкой…

Ответ №1:

Не пытайтесь выполнять изменения структуры, которые зависят друг от друга при параллельном использовании Promise.all . Вам лучше называть их по одному:

 await queryInterface.removeConstraint('MeasurementTestResults', 'statusFk')
await queryInterface.changeColumn('MeasurementTestResults', 'status', {
   type: Sequelize.ENUM(...enumStatus),
   allowNull: false
})
 

То же самое относится и к up методу.

Комментарии:

1. Так просто, но эффективно большое спасибо за. Это довольно ново для меня, и это мой первый сценарий up down.

2. Не забудьте добавить транзакцию, если MariaDB поддерживает ее для изменения структуры.