66

In TypeORM, how can I create a postgres enum type Gender as in this raw query

CREATE TYPE public.Gender AS ENUM (
    'male', 'female'
);
ALTER TABLE public.person ALTER COLUMN gender TYPE public.gender USING gender::gender;

and use it in the Entity class?

I have tried

@Entity()
export class Person {
    @Column('enum')
    gender: 'male' | 'female'
}

but obviously this isn't the right way, since I got the error message "type enum does not exist".

I don't want to use typescript enum either, since it will give me a bunch of 0s and 1s in the database.

6 Answers 6

144

Enum is now supported on TypeOrm for postgres

By the docs

enum column type is supported by postgres and mysql. There are various possible column definitions:

Using typescript enums:

export enum UserRole {
    ADMIN = "admin",
    EDITOR = "editor",
    GHOST = "ghost"
}

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column({
        type: "enum",
        enum: UserRole,
        default: UserRole.GHOST
    })
    role: UserRole;

}

Using array with enum values:

export type UserRoleType = "admin" | "editor" | "ghost",

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column({
        type: "enum",
        enum: ["admin", "editor", "ghost"],
        default: "ghost"
    })
    role: UserRoleType;
}
Sign up to request clarification or add additional context in comments.

2 Comments

for the enum name in database it creates prefix with the table name. is it possible to avoid it somehow?
@kashlo Are you generating migrations automatically with the orm cli?
49

EDIT: This answer is still valid but a bit outdated as 0.1.0 alpha versions of TypeORM support enums for both PostgreSQL and MySQL.


PostgreSQL has a built in enum type, but unfortunately TypeORM currently only supports it for MySQL.

However, you could achieve a similar result with an int-type enum by using the @Column type as int and using the enum for your field type.

enum Gender {
  Male,
  Female,
  Other
}

@Entity()
export class Person {
    @Column('int')
    gender: Gender
}

(This approach lets you use the @IsEnum decorator from class-validator to validate the input if needed)

You could also use string enums (available on TypeScript 2.4, check Typescript `enum` from JSON string for older versions) and if that is the case just change the data type to string instead.

enum Gender {
  Male = 'male',
  Female = 'female',
  Other = 'other'
}

@Entity()
export class Person {
    @Column('text')
    gender: Gender
}

Comments

4

As the accepted answer states, it is now supported in postgres but still buggy: Github issue, the fix will be released in the next RC probably. Meanwhile, I saw on the thread a nice solution which I even liked it more than the actual feature fully working:

fwiw I've been using string enum with check constraint. It's a lot more flexible than actual postgres enum, which creates whole new data types in postgres index and are really hard to manage (alter table, etc.)

export function CheckEnum(tableName: string, fieldName: string, enumValue: any) {
  // Hash enum value and put it as part of constraint name so we can
  // force typeorm to generate migration for enum changes.
  const hash = crypto
    .createHash('sha1')
    .update(Object.values(enumValue).join(''))
    .digest('hex')
  return Check(
    // https://til.hashrocket.com/posts/8f87c65a0a-postgresqls-max-identifier-length-is-63-bytes
    `cke_${tableName}_${fieldName}_${hash}`.slice(0, 63),
    `${fieldName} in (${Object.values(enumValue).map(t => `'${t}'`)})`,
  )
}

And use it like so

export enum Gender {
  Male = 'male',
  Female = 'female',
  Other = 'other'
}

@Entity()
@CheckEnum('person', 'gender', Gender)
export class Person {

Comments

2

For Postgres, the column type should be 'text', not 'string', as string results in DataTypeNotSupportedError: Data type "string" in "" is not supported by "postgres" database.

Comments

2

It's worth mentioning that using the same enum in multiple entities might result in strange enum missing properties errors. It took me hours to figure out the issue.

Comments

0

See @noam steiner's answer but TypeORM will recognize the enum type without providing it explicitly, so this is enough:

enum SomeEnum{
  # ...
}

class Entity {
  @Field()
  @Column()
  someEnumField: SomeEnum;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.