Duplicate migrations when using "enumName" ColumnOption for a Postgres enum type

Viewed 1418

I have an entity called TaskNotification where I have an enum field called type. I use enumName option to give a specific name TaskNotificationType to it inside the database.

import { Entity, Column } from 'typeorm';

export enum TaskNotificationType {
  ASSIGNED
}

@Entity('taskNotifications')
export class TaskNotification {
  @Column({
    type: 'enum',
    enum: TaskNotificationType,
    enumName: 'TaskNotificationType',
    default: TaskNotificationType.ASSIGNED,
  })
  type: TaskNotificationType;

  /* Some more code */
}

When I create the new migration for this entity class, I get the following migration. This is correct and what is expected.

import {MigrationInterface, QueryRunner} from "typeorm";

export class addNotifications1620795716886 implements MigrationInterface {
    name = 'addNotifications1620795716886'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TYPE "TaskNotificationType" AS ENUM('0')`);
        await queryRunner.query(`CREATE TABLE "taskNotifications" ("id" character varying(21) NOT NULL, "senderID" character varying(21) NOT NULL, "taskID" character varying(21) NOT NULL, "type" "TaskNotificationType" NOT NULL DEFAULT '0', CONSTRAINT "PK_bf03149248aee7c64532028321e" PRIMARY KEY ("id"))`);
        await queryRunner.query(`CREATE TABLE "notificationStatuses" ("id" character varying(21) NOT NULL, "receiverID" character varying(21) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "sentAt" TIMESTAMP WITH TIME ZONE, "readAt" TIMESTAMP WITH TIME ZONE, "taskNotificationID" character varying(21) NOT NULL, CONSTRAINT "PK_735fedb2f492dc91b0adf8233b0" PRIMARY KEY ("id"))`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" ADD CONSTRAINT "FK_9b92958e250c1f46393e0e88066" FOREIGN KEY ("taskID") REFERENCES "tasks"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
        await queryRunner.query(`ALTER TABLE "notificationStatuses" ADD CONSTRAINT "FK_14dbeaea4a320e7375cb22e7e7a" FOREIGN KEY ("taskNotificationID") REFERENCES "taskNotifications"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "notificationStatuses" DROP CONSTRAINT "FK_14dbeaea4a320e7375cb22e7e7a"`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" DROP CONSTRAINT "FK_9b92958e250c1f46393e0e88066"`);
        await queryRunner.query(`DROP TABLE "notificationStatuses"`);
        await queryRunner.query(`DROP TABLE "taskNotifications"`);
        await queryRunner.query(`DROP TYPE "TaskNotificationType"`);
    }

}

When I rebuild the app and run the migrations, the database gets updated as I wanted. So there is no issue upto now.

But, if I try to create another migration without changing any of the entities, I am getting another migration like below. Notice the name difference in the enum between up and down methods. (What is happening here? )

import {MigrationInterface, QueryRunner} from "typeorm";

export class addNotificationsDuplicate1620795984398 implements MigrationInterface {
    name = 'addNotificationsDuplicate1620795984398'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "taskNotifications" DROP COLUMN "type"`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" ADD "type" "TaskNotificationType" NOT NULL DEFAULT '0'`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "taskNotifications" DROP COLUMN "type"`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" ADD "type" "tasknotificationtype" NOT NULL DEFAULT '0'`);
    }

}

If I didn't use enumName in column options, typeorm would assign a default name taskNotifications_type_enum.

Here's the migration for that:

      
import {MigrationInterface, QueryRunner} from "typeorm";
    
export class addNotifications1620796454176 implements MigrationInterface {
    name = 'addNotifications1620796454176'
    
    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TYPE "taskNotifications_type_enum" AS ENUM('0')`);
        await queryRunner.query(`CREATE TABLE "taskNotifications" ("id" character varying(21) NOT NULL, "senderID" character varying(21) NOT NULL, "taskID" character varying(21) NOT NULL, "type" "taskNotifications_type_enum" NOT NULL DEFAULT '0', CONSTRAINT "PK_bf03149248aee7c64532028321e" PRIMARY KEY ("id"))`);
        await queryRunner.query(`CREATE TABLE "notificationStatuses" ("id" character varying(21) NOT NULL, "receiverID" character varying(21) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "sentAt" TIMESTAMP WITH TIME ZONE, "readAt" TIMESTAMP WITH TIME ZONE, "taskNotificationID" character varying(21) NOT NULL, CONSTRAINT "PK_735fedb2f492dc91b0adf8233b0" PRIMARY KEY ("id"))`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" ADD CONSTRAINT "FK_9b92958e250c1f46393e0e88066" FOREIGN KEY ("taskID") REFERENCES "tasks"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
        await queryRunner.query(`ALTER TABLE "notificationStatuses" ADD CONSTRAINT "FK_14dbeaea4a320e7375cb22e7e7a" FOREIGN KEY ("taskNotificationID") REFERENCES "taskNotifications"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
        }
    
    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "notificationStatuses" DROP CONSTRAINT "FK_14dbeaea4a320e7375cb22e7e7a"`);
        await queryRunner.query(`ALTER TABLE "taskNotifications" DROP CONSTRAINT "FK_9b92958e250c1f46393e0e88066"`);
        await queryRunner.query(`DROP TABLE "notificationStatuses"`);
        await queryRunner.query(`DROP TABLE "taskNotifications"`);
        await queryRunner.query(`DROP TYPE "taskNotifications_type_enum"`);
        }
    
}

Then if I try to generate a migration without changing entities, it would not generate new migrations. (This is correct and expected behavior)

However, if I add enumName after that, it would not generate a new migration for the name change. It will throw the usual error we see when we try to run migrations without changing any entity. (Busted again )

╰>>> npm run typeorm:novadelite migration:generate -- -n addNotificationsDuplicate

> novade-lite-backend@0.1.4 typeorm:novadelite /Users/eranga/Documents/Projects/Novade/NovadeLiteBackend
> ts-node ./node_modules/.bin/typeorm --config src/modules/Database/OrmConfigs/novadeLiteOrmConfig "migration:generate" "-n" "addNotificationsDuplicate"

No changes in database schema were found - cannot generate a migration. To create a new empty migration use "typeorm migration:create" command

What is wrong here and how can I give a specific name to my enum type using typeorm?

Any help is much appreciated!


(In the rare occasion of this being an issue in typeorm, I have already created an issue in Github)

1 Answers

This indeed was an issue in Typeorm and it was fixed by AlexMesser in this PR.

At the time of this writing the version of Typeorm is 0.2.32 and this fix will be released on the next release!

Related