From 0094f61d63d116ae33e7c1fdd01b14819a56f81f Mon Sep 17 00:00:00 2001 From: Dennie de Lange Date: Fri, 13 Sep 2019 16:58:20 +0200 Subject: [PATCH] feat: add referenced table metadata to NamingStrategy to resolve foreign key name (#4274) Feature allows to use foreignkey metadata to generate database foreignkey names. Closes #3847 and #1355 --- .../cockroachdb/CockroachQueryRunner.ts | 8 ++--- src/driver/mysql/MysqlQueryRunner.ts | 8 ++--- src/driver/oracle/OracleQueryRunner.ts | 8 ++--- src/driver/postgres/PostgresQueryRunner.ts | 8 ++--- .../AbstractSqliteQueryRunner.ts | 8 ++--- src/driver/sqlserver/SqlServerQueryRunner.ts | 8 ++--- src/metadata/ForeignKeyMetadata.ts | 2 +- src/naming-strategy/DefaultNamingStrategy.ts | 2 +- .../NamingStrategyInterface.ts | 2 +- test/functional/query-runner/rename-column.ts | 2 +- test/functional/query-runner/rename-table.ts | 2 +- test/github-issues/3847/entity/Animal.ts | 17 +++++++++++ test/github-issues/3847/entity/Category.ts | 9 ++++++ test/github-issues/3847/issue-3847.ts | 30 +++++++++++++++++++ .../3847/naming/NamingStrategyUnderTest.ts | 16 ++++++++++ 15 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 test/github-issues/3847/entity/Animal.ts create mode 100644 test/github-issues/3847/entity/Category.ts create mode 100644 test/github-issues/3847/issue-3847.ts create mode 100644 test/github-issues/3847/naming/NamingStrategyUnderTest.ts diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index 0e8468c4ce..10d6342bc1 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -505,7 +505,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner // rename foreign key constraints newTable.foreignKeys.forEach(foreignKey => { // build new constraint name - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE ${this.escapePath(newTable)} RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -702,7 +702,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner // build new constraint name foreignKey.columnNames.splice(foreignKey.columnNames.indexOf(oldColumn.name), 1); foreignKey.columnNames.push(newColumn.name); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -1123,7 +1123,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner // new FK may be passed without name. In this case we generate FK name manually. if (!foreignKey.name) - foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); const up = this.createForeignKeySql(table, foreignKey); const down = this.dropForeignKeySql(table, foreignKey); @@ -1618,7 +1618,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `"${columnName}"`).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `"${columnName}"`).join(", "); let constraint = `CONSTRAINT "${fk.name}" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(fk.referencedTableName)} (${referencedColumnNames})`; diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 57d97a84d6..1176e7eea5 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -408,7 +408,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { // build new constraint name const columnNames = foreignKey.columnNames.map(column => `\`${column}\``).join(", "); const referencedColumnNames = foreignKey.referencedColumnNames.map(column => `\`${column}\``).join(","); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries let up = `ALTER TABLE ${this.escapePath(newTable)} DROP FOREIGN KEY \`${foreignKey.name}\`, ADD CONSTRAINT \`${newForeignKeyName}\` FOREIGN KEY (${columnNames}) ` + @@ -599,7 +599,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { foreignKey.columnNames.push(newColumn.name); const columnNames = foreignKey.columnNames.map(column => `\`${column}\``).join(", "); const referencedColumnNames = foreignKey.referencedColumnNames.map(column => `\`${column}\``).join(","); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries let up = `ALTER TABLE ${this.escapePath(table)} DROP FOREIGN KEY \`${foreignKey.name}\`, ADD CONSTRAINT \`${newForeignKeyName}\` FOREIGN KEY (${columnNames}) ` + @@ -1004,7 +1004,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { // new FK may be passed without name. In this case we generate FK name manually. if (!foreignKey.name) - foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); const up = this.createForeignKeySql(table, foreignKey); const down = this.dropForeignKeySql(table, foreignKey); @@ -1462,7 +1462,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `\`${columnName}\``).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `\`${columnName}\``).join(", "); let constraint = `CONSTRAINT \`${fk.name}\` FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(fk.referencedTableName)} (${referencedColumnNames})`; diff --git a/src/driver/oracle/OracleQueryRunner.ts b/src/driver/oracle/OracleQueryRunner.ts index 91e68a2c8e..ac0f34dc67 100644 --- a/src/driver/oracle/OracleQueryRunner.ts +++ b/src/driver/oracle/OracleQueryRunner.ts @@ -430,7 +430,7 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { // rename foreign key constraints newTable.foreignKeys.forEach(foreignKey => { // build new constraint name - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE "${newTable.name}" RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -613,7 +613,7 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { // build new constraint name foreignKey.columnNames.splice(foreignKey.columnNames.indexOf(oldColumn.name), 1); foreignKey.columnNames.push(newColumn.name); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE "${table.name}" RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -1004,7 +1004,7 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { // new FK may be passed without name. In this case we generate FK name manually. if (!foreignKey.name) - foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); const up = this.createForeignKeySql(table, foreignKey); const down = this.dropForeignKeySql(table, foreignKey); @@ -1351,7 +1351,7 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `"${columnName}"`).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `"${columnName}"`).join(", "); let constraint = `CONSTRAINT "${fk.name}" FOREIGN KEY (${columnNames}) REFERENCES "${fk.referencedTableName}" (${referencedColumnNames})`; if (fk.onDelete && fk.onDelete !== "NO ACTION") // Oracle does not support NO ACTION, but we set NO ACTION by default in EntityMetadata diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 73633fff65..53747e61bc 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -470,7 +470,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner // rename foreign key constraints newTable.foreignKeys.forEach(foreignKey => { // build new constraint name - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE ${this.escapePath(newTable)} RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -687,7 +687,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner // build new constraint name foreignKey.columnNames.splice(foreignKey.columnNames.indexOf(oldColumn.name), 1); foreignKey.columnNames.push(newColumn.name); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} RENAME CONSTRAINT "${foreignKey.name}" TO "${newForeignKeyName}"`)); @@ -1174,7 +1174,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner // new FK may be passed without name. In this case we generate FK name manually. if (!foreignKey.name) - foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); const up = this.createForeignKeySql(table, foreignKey); const down = this.dropForeignKeySql(table, foreignKey); @@ -1702,7 +1702,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `"${columnName}"`).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `"${columnName}"`).join(", "); let constraint = `CONSTRAINT "${fk.name}" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(fk.referencedTableName)} (${referencedColumnNames})`; diff --git a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts index 21f975d424..e7587ecb92 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts @@ -304,7 +304,7 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen // rename foreign key constraints newTable.foreignKeys.forEach(foreignKey => { - foreignKey.name = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); }); // rename indices @@ -384,7 +384,7 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen changedTable.findColumnForeignKeys(changedColumnSet.oldColumn).forEach(fk => { fk.columnNames.splice(fk.columnNames.indexOf(changedColumnSet.oldColumn.name), 1); fk.columnNames.push(changedColumnSet.newColumn.name); - fk.name = this.connection.namingStrategy.foreignKeyName(changedTable, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(changedTable, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); }); changedTable.findColumnIndices(changedColumnSet.oldColumn).forEach(index => { @@ -848,7 +848,7 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen const columnNames = ownForeignKeys.map(dbForeignKey => dbForeignKey["from"]); const referencedColumnNames = ownForeignKeys.map(dbForeignKey => dbForeignKey["to"]); // build foreign key name, because we can not get it directly. - const fkName = this.connection.namingStrategy.foreignKeyName(table, columnNames); + const fkName = this.connection.namingStrategy.foreignKeyName(table, columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); return new TableForeignKey({ name: fkName, @@ -975,7 +975,7 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `"${columnName}"`).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `"${columnName}"`).join(", "); let constraint = `CONSTRAINT "${fk.name}" FOREIGN KEY (${columnNames}) REFERENCES "${fk.referencedTableName}" (${referencedColumnNames})`; diff --git a/src/driver/sqlserver/SqlServerQueryRunner.ts b/src/driver/sqlserver/SqlServerQueryRunner.ts index a9af96e463..9a3d96f0f9 100644 --- a/src/driver/sqlserver/SqlServerQueryRunner.ts +++ b/src/driver/sqlserver/SqlServerQueryRunner.ts @@ -622,7 +622,7 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner // rename foreign key constraints newTable.foreignKeys.forEach(foreignKey => { // build new constraint name - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(newTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`EXEC sp_rename "${this.buildForeignKeyName(foreignKey.name!, schemaName, dbName)}", "${newForeignKeyName}"`)); @@ -823,7 +823,7 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner // build new constraint name foreignKey.columnNames.splice(foreignKey.columnNames.indexOf(oldColumn.name), 1); foreignKey.columnNames.push(newColumn.name); - const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames); + const newForeignKeyName = this.connection.namingStrategy.foreignKeyName(clonedTable, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); // build queries upQueries.push(new Query(`EXEC sp_rename "${this.buildForeignKeyName(foreignKey.name!, schemaName, dbName)}", "${newForeignKeyName}"`)); @@ -1240,7 +1240,7 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner // new FK may be passed without name. In this case we generate FK name manually. if (!foreignKey.name) - foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames); + foreignKey.name = this.connection.namingStrategy.foreignKeyName(table.name, foreignKey.columnNames, foreignKey.referencedTableName, foreignKey.referencedColumnNames); const up = this.createForeignKeySql(table, foreignKey); const down = this.dropForeignKeySql(table, foreignKey); @@ -1816,7 +1816,7 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner const foreignKeysSql = table.foreignKeys.map(fk => { const columnNames = fk.columnNames.map(columnName => `"${columnName}"`).join(", "); if (!fk.name) - fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames); + fk.name = this.connection.namingStrategy.foreignKeyName(table.name, fk.columnNames, fk.referencedTableName, fk.referencedColumnNames); const referencedColumnNames = fk.referencedColumnNames.map(columnName => `"${columnName}"`).join(", "); let constraint = `CONSTRAINT "${fk.name}" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(fk.referencedTableName)} (${referencedColumnNames})`; diff --git a/src/metadata/ForeignKeyMetadata.ts b/src/metadata/ForeignKeyMetadata.ts index e72d56eb30..ece34699fc 100644 --- a/src/metadata/ForeignKeyMetadata.ts +++ b/src/metadata/ForeignKeyMetadata.ts @@ -106,7 +106,7 @@ export class ForeignKeyMetadata { this.columnNames = this.columns.map(column => column.databaseName); this.referencedColumnNames = this.referencedColumns.map(column => column.databaseName); this.referencedTablePath = this.referencedEntityMetadata.tablePath; - this.name = namingStrategy.foreignKeyName(this.entityMetadata.tablePath, this.columnNames); + this.name = namingStrategy.foreignKeyName(this.entityMetadata.tablePath, this.columnNames, this.referencedTablePath, this.referencedColumnNames); } } diff --git a/src/naming-strategy/DefaultNamingStrategy.ts b/src/naming-strategy/DefaultNamingStrategy.ts index 8880c9ef20..22bbf07f5f 100644 --- a/src/naming-strategy/DefaultNamingStrategy.ts +++ b/src/naming-strategy/DefaultNamingStrategy.ts @@ -78,7 +78,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface { return "DF_" + RandomGenerator.sha1(key).substr(0, 27); } - foreignKeyName(tableOrName: Table|string, columnNames: string[]): string { + foreignKeyName(tableOrName: Table|string, columnNames: string[], _referencedTablePath?: string, _referencedColumnNames?: string[]): string { // sort incoming column names to avoid issue when ["id", "name"] and ["name", "id"] arrays const clonedColumnNames = [...columnNames]; clonedColumnNames.sort(); diff --git a/src/naming-strategy/NamingStrategyInterface.ts b/src/naming-strategy/NamingStrategyInterface.ts index 77f8916a55..3f650e8c14 100644 --- a/src/naming-strategy/NamingStrategyInterface.ts +++ b/src/naming-strategy/NamingStrategyInterface.ts @@ -60,7 +60,7 @@ export interface NamingStrategyInterface { /** * Gets the name of the foreign key. */ - foreignKeyName(tableOrName: Table|string, columnNames: string[]): string; + foreignKeyName(tableOrName: Table|string, columnNames: string[], referencedTablePath?: string, referencedColumnNames?: string[]): string; /** * Gets the name of the index - simple and compose index. diff --git a/test/functional/query-runner/rename-column.ts b/test/functional/query-runner/rename-column.ts index 9f73f180f4..58497967f9 100644 --- a/test/functional/query-runner/rename-column.ts +++ b/test/functional/query-runner/rename-column.ts @@ -186,7 +186,7 @@ describe("query runner > rename column", () => { await queryRunner.renameColumn(categoryTableName, "questionId", "questionId2"); table = await queryRunner.getTable(categoryTableName); - const newForeignKeyName = connection.namingStrategy.foreignKeyName(table!, ["questionId2"]); + const newForeignKeyName = connection.namingStrategy.foreignKeyName(table!, ["questionId2"], "question", ["id"]); table!.foreignKeys[0].name!.should.be.equal(newForeignKeyName); await queryRunner.executeMemoryDownSql(); diff --git a/test/functional/query-runner/rename-table.ts b/test/functional/query-runner/rename-table.ts index 065f93086f..f731a79eaf 100644 --- a/test/functional/query-runner/rename-table.ts +++ b/test/functional/query-runner/rename-table.ts @@ -172,7 +172,7 @@ describe("query runner > rename table", () => { await queryRunner.renameTable(categoryTableName, "renamedCategory"); table = await queryRunner.getTable(renamedCategoryTableName); - const newForeignKeyName = connection.namingStrategy.foreignKeyName(table!, ["questionId"]); + const newForeignKeyName = connection.namingStrategy.foreignKeyName(table!, ["questionId"], "question", ["id"]); table!.foreignKeys[0].name!.should.be.equal(newForeignKeyName); await queryRunner.executeMemoryDownSql(); diff --git a/test/github-issues/3847/entity/Animal.ts b/test/github-issues/3847/entity/Animal.ts new file mode 100644 index 0000000000..adf55f281d --- /dev/null +++ b/test/github-issues/3847/entity/Animal.ts @@ -0,0 +1,17 @@ +import {Column, Entity, PrimaryGeneratedColumn} from "../../../../src/index"; +import {Category} from "./Category"; +import {ManyToOne} from "../../../../src/decorator/relations/ManyToOne"; + +@Entity() +export class Animal { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @ManyToOne(() => Category) + category: Category; + +} \ No newline at end of file diff --git a/test/github-issues/3847/entity/Category.ts b/test/github-issues/3847/entity/Category.ts new file mode 100644 index 0000000000..40bf5cdc19 --- /dev/null +++ b/test/github-issues/3847/entity/Category.ts @@ -0,0 +1,9 @@ +import {Entity, PrimaryGeneratedColumn} from "../../../../src/index"; + +@Entity() +export class Category { + + @PrimaryGeneratedColumn() + id: number; + +} \ No newline at end of file diff --git a/test/github-issues/3847/issue-3847.ts b/test/github-issues/3847/issue-3847.ts new file mode 100644 index 0000000000..d79a2be4b1 --- /dev/null +++ b/test/github-issues/3847/issue-3847.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {Animal} from "./entity/Animal"; +import {NamingStrategyUnderTest} from "./naming/NamingStrategyUnderTest"; + + +describe("github issues > #3847 FEATURE REQUEST - Naming strategy foreign key override name", () => { + + let connections: Connection[]; + let namingStrategy = new NamingStrategyUnderTest(); + + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + namingStrategy + })); + beforeEach(() => { + return reloadTestingDatabases(connections); + }); + after(() => closeTestingConnections(connections)); + + it("NamingStrategyUnderTest#", () => Promise.all(connections.map(async connection => { + await connection.getRepository(Animal).find(); + + let metadata = connection.getMetadata(Animal); + + expect(metadata.foreignKeys[0].name).to.eq("fk_animal_category_categoryId"); + }))); +}); diff --git a/test/github-issues/3847/naming/NamingStrategyUnderTest.ts b/test/github-issues/3847/naming/NamingStrategyUnderTest.ts new file mode 100644 index 0000000000..e7e9ed3661 --- /dev/null +++ b/test/github-issues/3847/naming/NamingStrategyUnderTest.ts @@ -0,0 +1,16 @@ +import { DefaultNamingStrategy } from "../../../../src/naming-strategy/DefaultNamingStrategy"; +import { NamingStrategyInterface } from "../../../../src/naming-strategy/NamingStrategyInterface"; +import { Table } from "../../../../src"; + +export class NamingStrategyUnderTest extends DefaultNamingStrategy implements NamingStrategyInterface { + + foreignKeyName(tableOrName: Table|string, columnNames: string[], referencedTablePath?: string, referencedColumnNames?: string[]): string { + tableOrName = + typeof tableOrName === "string" ? tableOrName : tableOrName.name; + + return columnNames.reduce( + (name, column) => `${name}_${column}`, + `fk_${tableOrName}_${referencedTablePath}`, + ); + } +} \ No newline at end of file