Skip to content

Duplicate migrations when using 'enumName' ColumnOption in an 'enum' type Postgres #7647

@eranganovade

Description

@eranganovade

Issue Description

I have an enum column inside my TaskNotification entity.

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 updates as I wanted. But, when I try to create another migration without changing any of the entities, I am getting another migration like below.

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'`);
    }

}

I did some digging and found out that if I remove enumName from column options, typeorm will assign a default name taskNotifications_type_enum to the enum type and this behavior is no longer happening.

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"`);
    }

}

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

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

> [email protected] 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

Expected Behavior

I should see an error telling that there is no new migrations

Actual Behavior

I'm getting a new migration each time I build the app and generate migrations

Steps to Reproduce

N/A

My Environment

Dependency Version
Operating System macOS Big Sur - Version 11.3.1 (20E241)
Node.js version v14.15.1
Typescript version v4.2.3
TypeORM version v0.2.31

Additional Context

N/A

Relevant Database Driver(s)

  • aurora-data-api
  • aurora-data-api-pg
  • better-sqlite3
  • cockroachdb
  • cordova
  • expo
  • mongodb
  • mysql
  • nativescript
  • oracle
  • postgres
  • react-native
  • sap
  • sqlite
  • sqlite-abstract
  • sqljs
  • sqlserver

Are you willing to resolve this issue by submitting a Pull Request?

  • Yes, I have the time, and I know how to start.
  • Yes, I have the time, but I don't know how to start. I would need guidance.
  • No, I don't have the time, although I believe I could do it if I had the time...
  • No, I don't have the time and I wouldn't even know how to start.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions