UNPKG

replace-enum-postgresql

Version:

This package provides the methods needed to replace a PostgreSQL ENUM (ie., in migrations).

263 lines (247 loc) 6.31 kB
/** * 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 {Object} args * @param {String} args.tableName * @param {String} args.columnName * @param {String} args.defaultValue * @param {Array} args.newValues * @param {Object} args.queryInterface * @param {String} args.enumName - Optional. * * @return {Promise} */ export default (args) => { const { tableName, columnName, defaultValue, newValues, queryInterface, enumName = `enum_${tableName}_${columnName}` } = args; const newEnumName = `${enumName}_new`; return queryInterface.sequelize.transaction((t) => { const sequelizeOptions = { transaction: t }; // Create a copy of the type return createEnum( { queryInterface, name: newEnumName, values: newValues, sequelizeOptions } ) // Drop default value (ALTER COLUMN cannot cast default values) .then(() => unsetDefaultValueFromEnum( { queryInterface, tableName, columnName, sequelizeOptions } )) // Change column type to the new ENUM TYPE .then(() => setColumnTypeToEnum({ tableName, columnName, enumName: newEnumName, queryInterface, sequelizeOptions })) // Drop old ENUM .then(() => dropEnum({ enumName, sequelizeOptions, queryInterface })) // Rename new ENUM name .then(() => renameEnum({ oldEnumName: newEnumName, newEnumName: enumName, queryInterface, sequelizeOptions })) .then(() => setColumnDefault({ tableName, columnName, defaultValue, defaultValueType: enumName, queryInterface, sequelizeOptions })); }); } /** * Create a new ENUM. * * @param {Object} args * @param {String} args.name * @param {String[]} args.values * @param {Object} args.sequelizeOptions * @param {Object} args.queryInterface * * @return {Promise} */ export function createEnum(args) { return args.queryInterface.sequelize.query( getQueryToCreateEnum(args.name, args.values), args.sequelizeOptions ); } /** * Returns the query to create an Enum. * * @param {String} name * @param {String[]} values * * @return {String} */ export function getQueryToCreateEnum(name, values) { return `CREATE TYPE "${name}" AS ENUM ('${values.join('\', \'')}')`; } /** * Unset default value from ENUM. * * @param {Object} args * @param {String} args.tableName * @param {String} args.columnName * @param {Object} args.sequelizeOptions * @param {Object} args.queryInterface * * @return {Promise} */ export function unsetDefaultValueFromEnum(args) { return args.queryInterface.sequelize.query( getQueryToRemoveDefaultFromColumn(args.tableName, args.columnName), args.sequelizeOptions ); } /** * Get the query to drop default value for a column. * * @param {String} tableName * @param {String} columnName * * @return {String} */ export function getQueryToRemoveDefaultFromColumn(tableName, columnName) { return `ALTER TABLE "${tableName}" ALTER COLUMN "${columnName}" DROP DEFAULT`; } /** * Set the column type to an Enum. * * @param {Object} args * @param {String} args.tableName * @param {String} args.columnName * @param {String} args.enumName * @param {Object} args.sequelizeOptions * * @return {Promise} */ export function setColumnTypeToEnum(args) { return args.queryInterface.sequelize.query( getQueryToSetEnumType(args.tableName, args.columnName, args.enumName), args.sequelizeOptions ); } /** * Get the query to set a column type to an Enum. * * @param {String} tableName * @param {String} columnName * @param {String} enumName * * @return {String} */ export function getQueryToSetEnumType(tableName, columnName, enumName) { return ` ALTER TABLE "${tableName}" ALTER COLUMN "${columnName}" TYPE "${enumName}" USING ("${columnName}"::text::"${enumName}") `; } /** * Drop an Enum. * * @param {Object} args * @param {Object} args.queryInterface * @param {String} args.enumName * @param {Object} args.sequelizeOptions * * @return {Promise} */ export function dropEnum(args) { return args.queryInterface.sequelize.query( getQueryToDropEnum(args.enumName), args.sequelizeOptions ); } /** * Get the query to drop an Enum. * * @param {String} enumName * * @return {String} */ export function getQueryToDropEnum(enumName) { return `DROP TYPE "${enumName}"`; } /** * Rename an Enum. * * @param {Object} args * @param {Object} args.queryInterface * @param {String} args.oldEnumName * @param {String} args.newEnumName * @param {Object} args.sequelizeOptions * * @return {Promise} */ export function renameEnum(args) { return args.queryInterface.sequelize.query( getQueryToRenameEnum(args.oldEnumName, args.newEnumName), args.sequelizeOptions ); } /** * Get the query to rename an enum. * * @param {String} oldEnumName * @param {String} newEnumName * * @return {String} */ export function getQueryToRenameEnum(oldEnumName, newEnumName) { return `ALTER TYPE "${oldEnumName}" RENAME TO "${newEnumName}"`; } /** * Set the default value for a column. * * @param {Object} args * @param {Object} args.queryInterface * @param {String} args.tableName * @param {String} args.columnName * @param {String} args.defaultValue * @param {String} args.defaultValueType * @param {Object} args.sequelizeOptions * * @return {Promise} */ export function setColumnDefault(args) { return args.queryInterface.sequelize.query( getQueryToSetColumnDefault( args.tableName, args.columnName, args.defaultValue, args.defaultValueType ), args.sequelizeOptions ); } /** * Get the query to set the default value for a column. * * @param {String} tableName * @param {String} columnName * @param {String} defaultValue * @param {String} defaultValueType * * @return {String} */ export function getQueryToSetColumnDefault(tableName, columnName, defaultValue, defaultValueType) { return ` ALTER TABLE "${tableName}" ALTER COLUMN "${columnName}" SET DEFAULT '${defaultValue}'::${defaultValueType} `; }