Knex: Question: Update enum column types in knex migration

Created on 27 Sep 2016  ·  10Comments  ·  Source: knex/knex

Stackoverflow

I'm looking to write a migration string to add a new string to the enum column type. I'm trying to add gamma to the service column.

I tried with this code below. This collides because the table and the column already exists.

const table = 'user_associations'

export function up (knex, Promise) {
  return knex.schema.table(table, function (table) {
    table.enu('service', ['alpha', 'beta', 'gamma']).notNullable()
  })
}

export function down (knex, Promise) {
  return knex.schema.table(table, function (table) {
    table.enu('service', ['alpha', 'beta']).notNullable()
  })
}
PR please

Most helpful comment

Just for anyone wanting to know how the code _might_ look in Postgres 9

const formatAlterTableEnumSql = (
  tableName,
  columnName,
  enums,
) => {
  const constraintName = `${tableName}_${columnName}_check`;
  return [
    `ALTER TABLE ${tableName} DROP CONSTRAINT IF EXISTS ${constraintName};`,
    `ALTER TABLE ${tableName} ADD CONSTRAINT ${constraintName} CHECK (${columnName} = ANY (ARRAY['${enums.join(
      "'::text, '"
    )}'::text]));`,
  ].join('\n');
};


exports.up = async function up(knex) {
  await knex.raw(
    formatAlterTableEnumSql('myTableName', 'myColumnName', [
      'enum1',
      'enum2',
      'enum3',
    ])
  );
};

exports.down = async function down(knex) {
  await knex.raw(
    formatAlterTableEnumSql('myTableName', 'myColumnName', [
      'enum1',
      'enum2',
    ])
  );
};

All 10 comments

Bump on this, any way to use the alter API?

enums are done with check constraints currently and .alter() doesn't have any special treatment for them...

One problem is that .alter() doesn't know what is the original type of the column and thats why it doesn't know if it should drop the old check constraint of enum.

As far as I know currently one can change the allowed enum values only with knex.rawby dropping old and creating new check constraint...

I think it could be implemented by some drop old constraint if exist and then create new one if the altered type of the column is enum.

I would love to see this feature being implemented.

@elhigu I wrote a custom enum query so that I could use Postgres enums, however there is some debate in the Postgres community about check conditions vs enums

Just for anyone wanting to know how the code _might_ look in Postgres 9

const formatAlterTableEnumSql = (
  tableName,
  columnName,
  enums,
) => {
  const constraintName = `${tableName}_${columnName}_check`;
  return [
    `ALTER TABLE ${tableName} DROP CONSTRAINT IF EXISTS ${constraintName};`,
    `ALTER TABLE ${tableName} ADD CONSTRAINT ${constraintName} CHECK (${columnName} = ANY (ARRAY['${enums.join(
      "'::text, '"
    )}'::text]));`,
  ].join('\n');
};


exports.up = async function up(knex) {
  await knex.raw(
    formatAlterTableEnumSql('myTableName', 'myColumnName', [
      'enum1',
      'enum2',
      'enum3',
    ])
  );
};

exports.down = async function down(knex) {
  await knex.raw(
    formatAlterTableEnumSql('myTableName', 'myColumnName', [
      'enum1',
      'enum2',
    ])
  );
};

@holloway Thanks for the migration code example. Just what I was looking for. I'm running into one issue though. 'myColumnName' is throwing an error when migrating. The message says "column 'mycolumnname' does not exist". Notice the camelCase is now missing. Any ideas on how to get around that?

@Jordan24 Can you share your code?

'use strict';

const formatAlterTableEnumSql = (tableName, columnName, enums) => {

  const constraintName = `${tableName}_${columnName}_check`;
  return [
    `ALTER TABLE ${tableName} DROP CONSTRAINT IF EXISTS ${constraintName};`,
    `ALTER TABLE ${tableName} ADD CONSTRAINT ${constraintName} CHECK (${columnName} = ANY (ARRAY['${enums.join(
      `'::text, '`
    )}'::text]));`
  ].join('\n');
};


exports.up = async function up(knex) {

  await knex.raw(
    formatAlterTableEnumSql('item_messages', 'sentMethod', [
      'Web App', 'Email', 'Text Message', 'Log Conversation'
    ])
  );
};

exports.down = async function down(knex) {

  await knex.raw(
    formatAlterTableEnumSql('item_messages', 'sentMethod', [
      'Web App', 'Email', 'Text Message'
    ])
  );
};

If I wrap the columnName in double quotes I get a syntax error because the single quotes aren't removed in the raw code.
I think I might drop the function and just write the raw code out twice.

@Jordan24 Without the quotes PostgreSQL folds all identifiers to lowercase.

Hard coded all but the 'enum' to get around it. Thanks for the tip @kibertoad!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mattgrande picture mattgrande  ·  3Comments

hyperh picture hyperh  ·  3Comments

lanceschi picture lanceschi  ·  3Comments

aj0strow picture aj0strow  ·  3Comments

legomind picture legomind  ·  3Comments