2017-08-01 5 views
3

Postgresの移行でENUMタイプを正しく削除してから再作成するにはどうすればいいですか?たとえば、この移行はenum_Users_status列挙型をドロップしません。したがって、一度作成した後にstatus値を再作成/変更しようとすると失敗します。sequelizeでENUMを削除して正しく作成しますか?

..

module.exports = { 
    up: function (queryInterface, DataTypes) { 
     queryInterface.createTable('Users', { 
      //... 
      status: { 
       type: DataTypes.ENUM, 
       values: [ 
        'online', 
        'offline', 
       ], 
       defaultValue: 'online' 
      } 
      //... 
     }) 
    }, 

    down: function (queryInterface) { 
     queryInterface.dropTable('Users') 
    }, 
} 

は最終的に私はdown内の列挙型を削除するために管理しましたが、その後(最初からこのstatus列挙型を作成することになっている)up移行が失敗し、public.enum_Users_status列挙型のようなものが存在しないと言って

答えて

1

私はこれを行うためのユーティリティを作ってくれました。

utils/replace_enum.js

'use strict'; 
 

 
/** 
 
* Since PostgreSQL still does not support remove values from an ENUM, 
 
* the workaround is to create a new ENUM with the new values and use it 
 
* to replace the other. 
 
* 
 
* @param {String} tableName 
 
* @param {String} columnName 
 
* @param {String} defaultValue 
 
* @param {Array} newValues 
 
* @param {Object} queryInterface 
 
* @param {String} enumName - Optional. 
 
* 
 
* @return {Promise} 
 
*/ 
 
module.exports = function replaceEnum({ 
 
    tableName, 
 
    columnName, 
 
    defaultValue, 
 
    newValues, 
 
    queryInterface, 
 
    enumName = `enum_${tableName}_${columnName}` 
 
}) { 
 
    const newEnumName = `${enumName}_new`; 
 

 
    return queryInterface.sequelize.transaction((t) => { 
 
    // Create a copy of the type 
 
    return queryInterface.sequelize.query(` 
 
     CREATE TYPE ${newEnumName} 
 
     AS ENUM ('${newValues.join('\', \'')}') 
 
    `, { transaction: t }) 
 
     // Drop default value (ALTER COLUMN cannot cast default values) 
 
     .then(() => queryInterface.sequelize.query(` 
 
     ALTER TABLE ${tableName} 
 
      ALTER COLUMN ${columnName} 
 
      DROP DEFAULT 
 
     `, { transaction: t })) 
 
     // Change column type to the new ENUM TYPE 
 
     .then(() => queryInterface.sequelize.query(` 
 
     ALTER TABLE ${tableName} 
 
      ALTER COLUMN ${columnName} 
 
      TYPE ${newEnumName} 
 
      USING (${columnName}::text::${newEnumName}) 
 
     `, { transaction: t })) 
 
     // Drop old ENUM 
 
     .then(() => queryInterface.sequelize.query(` 
 
     DROP TYPE ${enumName} 
 
     `, { transaction: t })) 
 
     // Rename new ENUM name 
 
     .then(() => queryInterface.sequelize.query(` 
 
     ALTER TYPE ${newEnumName} 
 
      RENAME TO ${enumName} 
 
     `, { transaction: t })) 
 
     .then(() => queryInterface.sequelize.query(` 
 
     ALTER TABLE ${tableName} 
 
      ALTER COLUMN ${columnName} 
 
      SET DEFAULT '${defaultValue}'::${enumName} 
 
     `, { transaction: t })); 
 
    }); 
 
}
、これは私の 移行です:

'use strict'; 
 

 
const replaceEnum = require('./utils/replace_enum'); 
 

 
module.exports = { 
 
    up: (queryInterface, Sequelize) => { 
 
    return replaceEnum({ 
 
     tableName: 'invoices', 
 
     columnName: 'state', 
 
     enumName: 'enum_invoices_state', 
 
     defaultValue: 'created', 
 
     newValues: ['archived', 'created', 'paid'], 
 
     queryInterface 
 
    }); 
 
    }, 
 

 
    down: (queryInterface, Sequelize) => { 
 
    return replaceEnum({ 
 
     tableName: 'invoices', 
 
     columnName: 'state', 
 
     enumName: 'enum_invoices_state', 
 
     defaultValue: 'draft', 
 
     newValues: ['archived', 'draft', 'paid', 'sent'], 
 
     queryInterface 
 
    }); 
 
    } 
 
};

UPDATEこれまで3つのプロジェクトでこれを使用していたので、npmモジュールを作成することにしました:https://www.npmjs.com/package/replace-enum-postgresql

1

データを失うことなくタイプenumを変更/編集したい場合。私の移行コードはここにあります。うまくいけば助けてくれます。

queryInterface.changeColumn(
    'table_name', 
    'Column_name', 
    { 
    type: Sequelize.TEXT, 
    }, 
), 
queryInterface.sequelize.query('drop type enum_tableName_columnName;') 
.then(() => queryInterface.changeColumn(
    'table_name', 
    'column_name', 
    { 
    type: Sequelize.ENUM('value1','value2'), 
    }, 
)), 
関連する問題