typeorm / typeorm/typeorm

MySQL: renameTable() updates foreign key constraint names but leaves supporting index names unchanged, causing invalid migrations

Open
#12,671 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
36.7k
Forks
6.7k
Avg merge
3d 1h
Merged PRs (30d)
6

Description

Issue description

After renaming a table using a migration, TypeORM generates incorrect migrations that attempt to drop indexes required by foreign key constraints.

Expected Behavior

One of the following should happen:

1 . renameTable() should also rename the supporting indexes to match the updated schema metadata,
or
2 The schema diff should recognize that these indexes are required by the foreign keys and should not generate DROP INDEX statement

Actual Behavior

await queryRunner.renameTable('reports', 'circle_reports'); only run the following:

query: RENAME TABLE `reports` TO `circle_reports`
query: ALTER TABLE `circle_reports` DROP FOREIGN KEY `FK_90128aa0533cf113b418de0304f`, ADD CONSTRAINT `FK_e8b4f00e21f04a1e8de2cd99338` FOREIGN KEY (`comment_id`) REFERENCES `comments`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION
query: ALTER TABLE `circle_reports` DROP FOREIGN KEY `FK_b84fcce5b84191fc4b8e5d0d6f9`, ADD CONSTRAINT `FK_3b4c6f59d3aeb0a197ad66dd48d` FOREIGN KEY (`post_id`) REFERENCES `posts`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION
query: ALTER TABLE `circle_reports` DROP FOREIGN KEY `FK_ca7a21eb95ca4625bd5eaef7e0c`, ADD CONSTRAINT `FK_8e204e8dab7cb9702cc83fa7a4c` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION
query: INSERT INTO `medchatter_typeorm`.`migrations`(`timestamp`, `name`) VALUES (?, ?) -- PARAMETERS: [1783342743130,"RenameReportsToCircleReports1783342743130"]

SHOW CREATE TABLE circle_reports;

'circle_reports', 'CREATE TABLE `circle_reports` (\n  `id` int NOT NULL AUTO_INCREMENT,\n  `reason` varchar(300) NOT NULL,\n  `user_id` int NOT NULL,\n  `post_id` int DEFAULT NULL,\n  `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `status` enum(\'pending\',\'keep\',\'remove\') NOT NULL DEFAULT \'pending\',\n  `resolved_at` datetime(3) DEFAULT NULL,\n  `comment_id` int DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `FK_ca7a21eb95ca4625bd5eaef7e0c` (`user_id`),\n  KEY `FK_b84fcce5b84191fc4b8e5d0d6f9` (`post_id`),\n  KEY `FK_90128aa0533cf113b418de0304f` (`comment_id`),\n  CONSTRAINT `FK_3b4c6f59d3aeb0a197ad66dd48d` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,\n  CONSTRAINT `FK_8e204e8dab7cb9702cc83fa7a4c` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,\n  CONSTRAINT `FK_e8b4f00e21f04a1e8de2cd99338` FOREIGN KEY (`comment_id`) REFERENCES `comments` (`id`) ON DELETE CASCADE\n) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci'

SHOW INDEX FROM circle_reports;

'circle_reports','0','PRIMARY','1','id','A','35',NULL,NULL,'','BTREE','','','YES',NULL
'circle_reports','1','FK_ca7a21eb95ca4625bd5eaef7e0c','1','user_id','A','7',NULL,NULL,'','BTREE','','','YES',NULL
'circle_reports','1','FK_b84fcce5b84191fc4b8e5d0d6f9','1','post_id','A','15',NULL,NULL,'YES','BTREE','','','YES',NULL
'circle_reports','1','FK_90128aa0533cf113b418de0304f','1','comment_id','A','10',NULL,NULL,'YES','BTREE','','','YES',NULL

Notice that the Index still using the old name even it was change

Steps to reproduce
  1. Create a table with foreign keys.
@Entity('reports')
export class Report {

  @PrimaryGeneratedColumn({ name: 'id' })
  id: number;
  
  ... 

  @ManyToOne(() => User, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'user_id' })
  user: User;

  @ManyToOne(() => Post, { onDelete: 'CASCADE', nullable: true })
  @JoinColumn({ name: 'post_id' })
  post?: Post;

  @ManyToOne(() => Comment, { onDelete: 'CASCADE', nullable: true })
  @JoinColumn({ name: 'comment_id' })
  comment?: Comment;
}
  1. rename table
@Entity('circle_reports')
export class CircleReport { ... }
  1. create migration using renameTable
import { MigrationInterface, QueryRunner } from 'typeorm';

export class RenameReportsToCircleReports1783342743130
  implements MigrationInterface
{
  name = 'RenameReportsToCircleReports1783342743130';

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.renameTable('reports', 'circle_reports');
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.renameTable('circle_reports', 'reports');
  }
}
  1. run migration
    5 generate new migration
DROP INDEX `FK_90128aa0533cf113b418de0304f` ON `circle_reports`;
DROP INDEX `FK_b84fcce5b84191fc4b8e5d0d6f9` ON `circle_reports`;
DROP INDEX `FK_ca7a21eb95ca4625bd5eaef7e0c` ON `circle_reports`;
My Environment
Dependency Version
Operating System macOS
Node.js version x.y.zzz
Typescript version ^5.9.3
TypeORM version ^0.3.28
Additional Context

Im not sure if this is the reason, but i notice the name in indexes and foreign keys are different. I seems that the foreign keys are change but the name in index are not changed

Relevant Database Driver(s)
  • aurora-mysql
  • aurora-postgres
  • better-sqlite3
  • capacitor
  • cockroachdb
  • cordova
  • expo
  • mongodb
  • mysql
  • nativescript
  • oracle
  • postgres
  • react-native
  • sap
  • spanner
  • sqlite
  • sqljs
  • sqlserver
Are you willing to resolve this issue by submitting a Pull Request?

No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the MySQL implementation of QueryRunner.renameTable and the schema-diff path that produces the DROP INDEX statements. Reproduce the migration and SHOW CREATE TABLE/SHOW INDEX results from the issue, then verify that a subsequent generated migration no longer tries to drop indexes required by the foreign keys.

Written by the indexing model from the issue text.

Assessment

Tech stack
mysql, typescript
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.