sequelize / sequelize

Feature-rich ORM for modern Node.js and TypeScript, it supports PostgreSQL (with JSON and JSONB support), MySQL, MariaDB, SQLite, MS SQL Server, Snowflake, Oracle DB (v6), DB2 and DB2 for IBM i.
https://sequelize.org/
MIT License
29.62k stars 4.28k forks source link

queryInterface.createTable() does not work with ARRAY(ENUM) with defaultValue #11285

Open papb opened 5 years ago

papb commented 5 years ago

What are you doing?

In postgres:

await sequelize.queryInterface.createTable('test', {
    test: {
        type: Sequelize.ARRAY(Sequelize.ENUM(['foo', 'bar', 'baz', 'qux'])),
        allowNull: false,
        defaultValue: ['foo']
    }
});

To Reproduce: Just run the snippet above, no models or other setup needed

  1. See error: TypeError: Cannot read property 'getTableName' of undefined

What do you expect to happen?

It should work

What is actually happening?

TypeError: Cannot read property 'getTableName' of undefined

Thrown at line:

https://github.com/sequelize/sequelize/blob/748f69080fdf86b8968e14c02e330b2a1cf41ebc/lib/dialects/postgres/data-types.js#L481

Environment

Dialect:

Tested with latest release:

Extra info

If the defaultValue is removed, it works:

await sequelize.queryInterface.createTable('test', {
    test: {
        type: Sequelize.ARRAY(Sequelize.ENUM(['foo', 'bar', 'baz', 'qux'])),
        allowNull: false
    }
});
harrytran998 commented 5 years ago

. (To watch to be notified the solve!)

jeremyputeaux commented 5 years ago

I experimented the same problem today. Any progress on this issue?

papb commented 5 years ago

@jetaimefrc You can subscribe by clicking the button

image

@jeremyputeaux No progress that I know of

rkneel123 commented 3 years ago

'use strict';

module.exports = { up: async (queryInterface, Sequelize) => { return [ await queryInterface.sequelize.query('CREATE TYPE "enum_tenants_access" AS ENUM (\'INSPECTION\', \'INSTRUCTION\')'), await queryInterface.sequelize.query('ALTER TABLE tenants ADD COLUMN access "enum_tenants_access"[]'), ] },

down: async (queryInterface, Sequelize) => { return [ await queryInterface.removeColumn('tenants', 'access') ] } };

You can use raw query for array of enum type. It will work.

SqrtMinusOne commented 3 years ago

Here is a workaround I found, if that helps anyone

    await queryInterface.sequelize.transaction(async (t) => {
      const rightsEnum = [
        "view",
        "edit",
        "coordinate",
        "coordinateDepartment",
        "approve",
        "assign",
        "viewDraft",
      ];
      await queryInterface.sequelize.query(
        `DROP TYPE IF EXISTS "enum_Faculties_facultyOpopRights"`,
        { transaction: t }
      );
      await queryInterface.createTable(
        "UserAisFaculties",
        {
          <<fields>>
          facultyOpopRights: {
            allowNull: false,
            defaultValue: [],
            type: Sequelize.ARRAY(Sequelize.ENUM(...rightsEnum)),
            fieldName: "facultyOpopRights",
            Model: {
              getTableName() {
                return "UserAisFaculties";
              },
            },
          },
        },
        { transaction: t }
      );
    });
github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it has been open for 7 days without activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment or remove the "stale" label. 🙂

LWanjiru commented 1 year ago

If anyone is still looking for a solution to this. I encountered it and this is how I went about solving it.

Environment I am using the following:-

SOLUTION

migration Just adding the relevant part here so use the migration schema when doing the actual thing

await queryInterface.createTable('Test', {
    myEnum: {
        type: Sequelize.ENUM,
        values: ['foo', 'bar', 'baz', 'qux'],
        field: 'myEnum', 
        defaultValue: 'foo'
        allowNull: false,
    },
 });

model

module.exports = (sequelize, DataTypes) => {
    const Test = sequelize.define('Test', {
        myEnum: {
            type: DataTypes.ENUM,
            values: ['foo', 'bar', 'baz', 'qux'],
            field: 'myEnum', 
            allowNull: false,
            // DO NOT add default value here
       },
    },{
       freezeTableName: true, // This ensures that sequelize will not change your table names to plural ie Tests as a default behaviour
    });
    // Define the associations
                 ..........
    return Test;
}

Post Notes

COLUMN NAME: myEnum,
TYPE: "enum_Test_myEnum",
DEFAULT: constant, foo

I hope this helps.

SqrtMinusOne commented 1 year ago

For anyone still struggling with this, somewhere before the version 6.35.0 fieldName was renamed to field.

The following seems to work:

 roles: {
  type: Sequelize.ARRAY(Sequelize.ENUM({ values: ['confirmer'] })),
  allowNull: false,
  defaultValue: [],
  field: 'roles', // Same as attribute name
  Model: {
    getTableName() {
      return 'DepartmentUsers'; // Table name
    },
  },
},
robotkoruslan commented 7 months ago

Works with the defaultValue

await sequelize.queryInterface.createTable('cars', {
    test: {
        type: Sequelize.ARRAY(Sequelize.ENUM(['foo', 'bar', 'baz', 'qux'])),
        allowNull: false,
        defaultValue: Sequelize.literal("ARRAY['foo']::enum_cars_test[]"),
    }
});