2017-08-01 5 views
3

Wie man ENUM-Typ mit Sequelize für Postgres in Migrationen korrekt fallenlassen und dann neu erstellen? Zum Beispiel lässt diese Migration enum_Users_status enum ... nicht fallen, so dass alle Versuche, status Werte neu zu erstellen/zu ändern, nachdem sie einmal erstellt wurden, fehlschlagen.Drop und erstellen ENUM mit Sequelize korrekt?

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

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

Schließlich habe ich es schaffe das Aufzählungstyp innerhalb down zu löschen, aber dann up Migration (die diese status Enum von Grund auf neu erstellen soll) ausfällt, etwas zu sagen, wie public.enum_Users_status Aufzählungstyp existiert nicht ..

Antwort

1

Ich habe ein Dienstprogramm, um dies zu tun, hoffe ich Ihnen es hilfreich.

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 })); 
 
    }); 
 
}

und das ist mein Beispiel Migration:

'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 Ich habe dies in drei Projekten bisher verwendet, also habe ich beschlossen, ein npm-Modul zu erstellen: https://www.npmjs.com/package/replace-enum-postgresql.

1

Wenn Sie Typ enum ändern/bearbeiten möchten, ohne Daten zu verlieren. Hier ist mein Migrationscode. Hoffentlich hilft es.

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'), 
    }, 
)),