From 7e00cccf815f7b96cfc10816bf7a74817f4329f2 Mon Sep 17 00:00:00 2001 From: Alexey Gerasimov Date: Thu, 19 Mar 2020 00:12:06 +0500 Subject: [PATCH] fix: pass `ManyToMany` `onUpdate` option to foreign key metadata Closes: #4980 --- .../JunctionEntityMetadataBuilder.ts | 6 ++- test/github-issues/4980/entity/Author.ts | 26 ++++++++++++ test/github-issues/4980/entity/Book.ts | 15 +++++++ test/github-issues/4980/issue-4980.ts | 42 +++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/github-issues/4980/entity/Author.ts create mode 100644 test/github-issues/4980/entity/Book.ts create mode 100644 test/github-issues/4980/issue-4980.ts diff --git a/src/metadata-builder/JunctionEntityMetadataBuilder.ts b/src/metadata-builder/JunctionEntityMetadataBuilder.ts index 89e436c1f1..a7618471ca 100644 --- a/src/metadata-builder/JunctionEntityMetadataBuilder.ts +++ b/src/metadata-builder/JunctionEntityMetadataBuilder.ts @@ -148,14 +148,16 @@ export class JunctionEntityMetadataBuilder { referencedEntityMetadata: relation.entityMetadata, columns: junctionColumns, referencedColumns: referencedColumns, - onDelete: relation.onDelete || "CASCADE" + onDelete: relation.onDelete || "CASCADE", + onUpdate: relation.onUpdate || "CASCADE" }), new ForeignKeyMetadata({ entityMetadata: entityMetadata, referencedEntityMetadata: relation.inverseEntityMetadata, columns: inverseJunctionColumns, referencedColumns: inverseReferencedColumns, - onDelete: relation.onDelete || "CASCADE" + onDelete: relation.inverseRelation ? relation.inverseRelation.onDelete : "CASCADE", + onUpdate: relation.inverseRelation ? relation.inverseRelation.onUpdate : "CASCADE", }), ] : []; diff --git a/test/github-issues/4980/entity/Author.ts b/test/github-issues/4980/entity/Author.ts new file mode 100644 index 0000000000..00aff4d763 --- /dev/null +++ b/test/github-issues/4980/entity/Author.ts @@ -0,0 +1,26 @@ +import { PrimaryGeneratedColumn, JoinTable, ManyToMany, Entity } from "../../../../src"; +import { Book } from "./Book"; + +@Entity("author") +export class Author { + @PrimaryGeneratedColumn() + id: number; + + @ManyToMany( + () => Book, + book => book.authors, + { onDelete: "CASCADE", onUpdate: "CASCADE" } + ) + @JoinTable({ + name: "author_to_books", + joinColumn: { + name: "author_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "book_id", + referencedColumnName: "id", + }, + }) + books: Book[]; +} diff --git a/test/github-issues/4980/entity/Book.ts b/test/github-issues/4980/entity/Book.ts new file mode 100644 index 0000000000..2065bfd930 --- /dev/null +++ b/test/github-issues/4980/entity/Book.ts @@ -0,0 +1,15 @@ +import { PrimaryGeneratedColumn, ManyToMany, Entity } from "../../../../src"; +import { Author } from "./Author"; + +@Entity("book") +export class Book { + @PrimaryGeneratedColumn() + id: number; + + @ManyToMany( + () => Author, + author => author.books, + { onDelete: "NO ACTION", onUpdate: "CASCADE"} + ) + authors: Author[]; +} diff --git a/test/github-issues/4980/issue-4980.ts b/test/github-issues/4980/issue-4980.ts new file mode 100644 index 0000000000..d60e13ed66 --- /dev/null +++ b/test/github-issues/4980/issue-4980.ts @@ -0,0 +1,42 @@ +import { Connection } from "../../../src"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Author } from "./entity/Author"; +import { Book } from "./entity/Book"; +import { expect } from "chai"; + +describe("github issues > #4980 (Postgres) onUpdate: 'CASCADE' doesn't work on many-to-many relation", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Author, Book], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should generate onDelete: CASCADE and onUpdate: CASCADE for 'books' side of many-to-many relation", () => Promise.all(connections.map(async connection => { + const booksRelation = connection.getMetadata(Author).manyToManyRelations.find(mtm => mtm.propertyName === "books"); + expect(booksRelation).not.to.be.undefined; + expect(booksRelation!.onDelete).to.be.equal("CASCADE"); + expect(booksRelation!.onUpdate).to.be.equal("CASCADE"); + }))); + it("should generate onDelete: NO ACTION and onUpdate: CASCADE for 'authors' side of many-to-many relation", () => Promise.all(connections.map(async connection => { + const authorsRelation = connection.getMetadata(Book).manyToManyRelations.find(mtm => mtm.propertyName === "authors"); + expect(authorsRelation).not.to.be.undefined; + expect(authorsRelation!.onDelete).to.be.equal("NO ACTION"); + expect(authorsRelation!.onUpdate).to.be.equal("CASCADE"); + }))); + it("should generate onDelete: NO ACTION and onUpdate: CASCADE for foreign key pointing to Book", () => Promise.all(connections.map(async connection => { + const booksRelation = connection.getMetadata(Author).manyToManyRelations.find(mtm => mtm.propertyName === "books")!; + const booksFk = booksRelation.foreignKeys.find(fk => fk.referencedTablePath === "book"); + expect(booksFk).not.to.be.undefined; + expect(booksFk!.onDelete).to.be.equal("NO ACTION"); + expect(booksFk!.onUpdate).to.be.equal("CASCADE"); + }))); + it("should generate onDelete: CASCADE and onUpdate: CASCADE for foreign key pinting to Author", () => Promise.all(connections.map(async connection => { + // take books relation bc foreign keys are on owning side + const booksRelation = connection.getMetadata(Author).manyToManyRelations.find(mtm => mtm.propertyName === "books")!; + const authorsFk = booksRelation.foreignKeys.find(fk => fk.referencedTablePath === "author"); + expect(authorsFk).not.to.be.undefined; + expect(authorsFk!.onDelete).to.be.equal("CASCADE"); + expect(authorsFk!.onUpdate).to.be.equal("CASCADE"); + }))); +});