drizzle-orm icon indicating copy to clipboard operation
drizzle-orm copied to clipboard

[BUG]: enum as array, not possible?

Open nathanielrich opened this issue 2 years ago • 6 comments

What version of drizzle-orm are you using?

0.29.0

What version of drizzle-kit are you using?

0.20.4

Describe the Bug

a simple example:

export const userRoles = pgEnum("user_role", ["admin", "member"]);

export const user = pgTable("user", {
	id: uuid("id").notNull().defaultRandom().primaryKey(),
	roles: userRoles("roles").notNull().default("member").array(),
});

when i try to migrate this, i got the error:

...

/[email protected]/node_modules/postgres/cjs/src/connection.js:790
    const error = Errors.postgres(parseError(x))
                         ^
PostgresError: type "user_role[]" does not exist

...

is it not implemented or is this a bug...?

thx.

Expected behavior

No response

Environment & setup

No response

nathanielrich avatar Nov 27 '23 07:11 nathanielrich

so im not alone

IRediTOTO avatar Nov 30 '23 08:11 IRediTOTO

since you are using an array you cannot have the literal as default you need to do it like this

export const userRoles = pgEnum("user_role", ["admin", "member"]);

export const user = pgTable("user", {
	id: uuid("id").notNull().defaultRandom().primaryKey(),
	roles: userRoles("roles").array().notNull().default(sql`'{"member"}'`),
});

dvtkrlbs avatar Dec 01 '23 11:12 dvtkrlbs

The sql generated by Drizzle probably looks something like this

ALTER TABLE "users" ADD COLUMN "roles" userRoles[]

while it should be looking like

ALTER TABLE "users" ADD COLUMN "roles" "userRoles"[]

I cannot figure out where Drizzle actually loads the sql from but modifying db/migrations/00000_migration_file.sql does not seem to work. For I've chosen to run the migration manually as I am not in production yet

onursagir avatar Feb 13 '24 20:02 onursagir

I do not think this problem is related to the usage of .array(). I am also having this problem with the following code

export const methodEnum = pgEnum('method', ['email', 'sms', 'whatsapp'])

export const authCodes = pgTable('auth_codes', {
  id: serial('id').primaryKey(),
  userId: serial('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
  to: varchar('to', { length: 256 }).notNull(),
  method: methodEnum('method').notNull(),
  code: varchar('code', { length: 6 }).unique().notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  expiresAt: timestamp('expires_at'),
  verifiedAt: timestamp('verified_at'),
}, (table) => ({
  codeIdx: index('code_idx').on(table.code),
}));
Screenshot 2024-04-02 at 23 52 09

I do not think this problem is related to the usage of .array(). I am also having this problem with the following code

export const methodEnum = pgEnum('method', ['email', 'sms', 'whatsapp'])

export const authCodes = pgTable('auth_codes', {
  id: serial('id').primaryKey(),
  userId: serial('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
  to: varchar('to', { length: 256 }).notNull(),
  method: methodEnum('method').notNull(),
  code: varchar('code', { length: 6 }).unique().notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  expiresAt: timestamp('expires_at'),
  verifiedAt: timestamp('verified_at'),
}, (table) => ({
  codeIdx: index('code_idx').on(table.code),
}));
Screenshot 2024-04-02 at 23 52 09

I also encountered this issue. If I replace 'mood' with 'moodtype' or any other word, it will fail to execute!

// will success
// const menuTypeEnum = pgEnum('mood', SystemMenuTypeEnum);

// will fail
const menuTypeEnum = pgEnum('moodtype', SystemMenuTypeEnum);

Infiee avatar Apr 24 '24 03:04 Infiee

Any resolution on this?

ngethan avatar May 24 '24 07:05 ngethan

❌ Does not work: roles: userRoleEnum("roles").array().notNull().default(["user"]),

✅ Works roles: userRoleEnum("roles").array().default(sqlARRAY['user']::user_role_enum[]).notNull(),

Lukem121 avatar May 29 '24 22:05 Lukem121

Still an issue.. :/

mikkelwf avatar Jun 12 '24 11:06 mikkelwf

Should be fixed in drizzle-kit0.24.0 Please check release notes before updating

AndriiSherman avatar Aug 08 '24 14:08 AndriiSherman

Hi @AndriiSherman,

unfurtonuately, this issue is still not resolved by [email protected]. I just tried it with Postgres:

export const myEnum = pgEnum('my_enum', [
  'VALUE1',
  'VALUE2'
])

export const myTable = pgTable('my_table', {
  id: bigserial('id', { mode: 'bigint' }).primaryKey(),
  enum: myEnum('enum').array().notNull(), // <-- does not work
})

export const myTableWithDefault = pgTable('my_table_with_default', {
  id: bigserial('id', { mode: 'bigint' }).primaryKey(),
  enum: myEnum('enum').array().default([]).notNull(), // <-- does not work with default value either
})

Running drizzle-kit push still throws the same error type "my_enum[]" does not exist because the generated SQL remains wrong as pointed out by @onursagir.

Maybe someone else could confirm this behavior. My local ESM setup uses workarounds mentioned here. However, I checked the correct drizzle-kit version by running pnpm drizzle-kit --version and it is indeed 0.24.0. I don't think there would be any difference in classic ("no ESM") setups.

Charioteer avatar Aug 09 '24 12:08 Charioteer

You can work around this by using lowercase enum names.

The test cases for this use snake case, which works fine. If your enum is named using camel case (or any uppercase characters) it will trigger this bug, as @onursagir suggested here:

https://github.com/drizzle-team/drizzle-orm/issues/1564#issuecomment-1942390685

Postgres folds unquoted names to lowercase, so if your enum is named testEnum the sql generated looks like testenum[] which doesn't exist. Here are the existing test cases:

https://github.com/drizzle-team/drizzle-orm/blob/c8359a16fff4b05aff09445edd63fc65a7430ce9/drizzle-kit/tests/pg-array.test.ts#L302

I think the problem is here:

https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/pg-core/columns/common.ts#L305

As far as I can tell (I've only had a quick look) quoting the enum name in PgArray should fix it:

return `"${this.baseColumn.getSQLType()}"[${typeof this.size === 'number' ? this.size : ''}]`;

andygott avatar Aug 30 '24 09:08 andygott

I tried [email protected]:

muscleTargets: muscleTargetEnum("muscle_targets")
	.array()
	.$type<MuscleTarget[]>()
	.default([])
	.notNull(),

tested with postgres and works.

fendyk avatar Aug 30 '24 11:08 fendyk

This is still broken for PascalCase enums

export const GameType = pgEnum('GameType', ['boardgame', 'deckbuilder', 'generic', 'lcg', 'tcg', 'ttrpg', 'wargame']);

gameTypes: GameType('gameTypes').array().notNull(),

error: type "gametype[]" does not exist

agreenspan avatar Sep 24 '24 15:09 agreenspan

this still doesn't work for me on 0.24.2. I get: "day_of_week" day_of_week[] NOT NULL, but it needs to be: "day_of_week" "flt"."day_of_week"[] NOT NULL, So the issues are that it's not properly escaping and the schema isn't being included.

bestickley avatar Sep 30 '24 20:09 bestickley

The way I worked around this is I just created the enum at the top of the migration file.

icep0ps avatar Oct 12 '24 13:10 icep0ps