Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
2 of 21 tasks
eranganovade opened this issue May 12, 2021 · 1 comment · Fixed by #7661
Closed
2 of 21 tasks

Comments

@eranganovade
Copy link

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

> 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

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.
AlexMesser added a commit that referenced this issue May 16, 2021
AlexMesser added a commit that referenced this issue May 18, 2021
* fix #7614

* updated test for #7541

* added test for #7647

* fixed failing test

* fixed failing test;
fixed `enumName` renaming;

* fixed failing test

* added test for #6540
kauz added a commit to kauz/typeorm that referenced this issue May 25, 2021
This makes sure updated regex does not break migrations chnages introduced in typeorm#7647
AlexMesser pushed a commit that referenced this issue May 30, 2021
…7681)

* fix: correctly strip type conversion in postgres for default values

Use better regex to remove only type conversion, not the whole string to the end

Closes: 7110

* fix: better regex

* fix: modify postgres default regex to not break #1532

* fix: modify postgres default regex to support user-defined types

This makes sure updated regex does not break migrations chnages introduced in #7647

* test: add test case for #5132
@Distortedlogic
Copy link

is an issue again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants