diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 97cc738684..acb3d94abd 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -1774,13 +1774,13 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner tableColumn.isNullable = dbColumn["is_nullable"] === "YES"; tableColumn.isPrimary = !!columnConstraints.find(constraint => constraint["constraint_type"] === "PRIMARY"); - const uniqueConstraint = columnConstraints.find(constraint => constraint["constraint_type"] === "UNIQUE"); - const isConstraintComposite = uniqueConstraint - ? !!dbConstraints.find(dbConstraint => dbConstraint["constraint_type"] === "UNIQUE" - && dbConstraint["constraint_name"] === uniqueConstraint["constraint_name"] - && dbConstraint["column_name"] !== dbColumn["column_name"]) - : false; - tableColumn.isUnique = !!uniqueConstraint && !isConstraintComposite; + const uniqueConstraints = columnConstraints.filter(constraint => constraint["constraint_type"] === "UNIQUE"); + const isConstraintComposite = uniqueConstraints.every((uniqueConstraint) => { + return dbConstraints.some(dbConstraint => dbConstraint["constraint_type"] === "UNIQUE" + && dbConstraint["constraint_name"] === uniqueConstraint["constraint_name"] + && dbConstraint["column_name"] !== dbColumn["column_name"]) + }) + tableColumn.isUnique = uniqueConstraints.length > 0 && !isConstraintComposite; if (dbColumn.is_identity === "YES") { // Postgres 10+ Identity column tableColumn.isGenerated = true; diff --git a/test/github-issues/8158/entity/User.ts b/test/github-issues/8158/entity/User.ts new file mode 100644 index 0000000000..4e1554fd4d --- /dev/null +++ b/test/github-issues/8158/entity/User.ts @@ -0,0 +1,27 @@ +import {Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, Unique} from "../../../../src"; +import {UserMeta} from "./UserMeta"; + +@Entity() +@Unique(["userMetaId"]) +@Unique(["id", "userMetaId"]) +export class User { + @PrimaryGeneratedColumn({ type:"bigint" }) + id: number; + + @Column() + firstName: string; + + @Column() + lastName: string; + + @Column() + age: number; + + @Column({ nullable: false, }) + userMetaId: number; + + @OneToOne(() => UserMeta) + @JoinColumn({ name: "userMetaId", referencedColumnName: "id" }) + userMeta: UserMeta; + +} diff --git a/test/github-issues/8158/entity/UserMeta.ts b/test/github-issues/8158/entity/UserMeta.ts new file mode 100644 index 0000000000..6704b22e7d --- /dev/null +++ b/test/github-issues/8158/entity/UserMeta.ts @@ -0,0 +1,21 @@ +import {Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn} from "../../../../src"; +import {User} from "./User"; + +@Entity() +export class UserMeta { + @PrimaryGeneratedColumn({ type:"bigint" }) + id: number; + + @Column() + foo: number; + + @Column() + bar: number; + + @Column({ nullable: false, }) + userId: number; + + @OneToOne(() => User) + @JoinColumn({ name: "userId", referencedColumnName: "id" }) + user: User; +} diff --git a/test/github-issues/8158/issue-8158.ts b/test/github-issues/8158/issue-8158.ts new file mode 100644 index 0000000000..8e01a6fd2f --- /dev/null +++ b/test/github-issues/8158/issue-8158.ts @@ -0,0 +1,32 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {UserMeta} from "./entity/UserMeta"; +import {User} from "./entity/User"; + +describe("github issues > #8158 Typeorm creates migration that creates already existing unique constraint", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["postgres"], + schemaCreate: false, + dropSchema: true, + entities: [UserMeta, User], + })); + after(() => closeTestingConnections(connections)); + + it("should recognize model changes", () => Promise.all(connections.map(async connection => { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.length.should.be.greaterThan(0); + sqlInMemory.downQueries.length.should.be.greaterThan(0); + }))); + + it("should not generate queries when no model changes", () => Promise.all(connections.map(async connection => { + await connection.driver.createSchemaBuilder().build(); + + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + console.log(sqlInMemory); + sqlInMemory.upQueries.length.should.be.equal(0); + sqlInMemory.downQueries.length.should.be.equal(0); + }))); +});