diff --git a/src/persistence/SubjectExecutor.ts b/src/persistence/SubjectExecutor.ts index f423d39b3f..593a497a36 100644 --- a/src/persistence/SubjectExecutor.ts +++ b/src/persistence/SubjectExecutor.ts @@ -18,7 +18,6 @@ import {ClosureSubjectExecutor} from "./tree/ClosureSubjectExecutor"; import {MaterializedPathSubjectExecutor} from "./tree/MaterializedPathSubjectExecutor"; import {OrmUtils} from "../util/OrmUtils"; import { UpdateResult } from "../query-builder/result/UpdateResult"; -import {RelationMetadata} from "../metadata/RelationMetadata"; /** * Executes all database operations (inserts, updated, deletes) that must be executed @@ -608,12 +607,8 @@ export class SubjectExecutor { } else { // in this case identifier is just conditions object to update by softDeleteQueryBuilder.where(subject.identifier); } + updateResult = await softDeleteQueryBuilder.execute(); - // Move throw all the relation of the subject - for (const relation of subject.metadata.relations) { - // Call recursive function that get the parents primary keys that in used on the inverse side in all one to many relations - await this.executeSoftRemoveRecursive(relation, [Reflect.get(subject.identifier, subject.metadata.primaryColumns[0].propertyName)]); - } } subject.generatedMap = updateResult.generatedMaps[0]; @@ -640,45 +635,10 @@ export class SubjectExecutor { // } })); } + /** * Recovers all given subjects in the database. */ - - protected async executeSoftRemoveRecursive(relation: RelationMetadata, ids: any[]): Promise { - // We want to delete the entities just when the relation is cascade soft remove - if (relation.isCascadeSoftRemove){ - - let primaryPropertyName = relation.inverseEntityMetadata.primaryColumns[0].propertyName; - let updateResult: UpdateResult; - let softDeleteQueryBuilder = this.queryRunner - .manager - .createQueryBuilder() - .softDelete() - .from(relation.inverseEntityMetadata.target) - // We get back list of the affected rows primary keys for call again - .returning([primaryPropertyName]) - .updateEntity(this.options && this.options.reload === false ? false : true) - .callListeners(false); - // soft remove only where parent id is in the list - softDeleteQueryBuilder.where(`${relation.inverseSidePropertyPath} in (:...ids)`, {ids: ids}); - updateResult = await softDeleteQueryBuilder.execute(); - let parentIds; - // Only in oracle the returning value is a list of the affected row primary keys and not list of dictionary - if (this.queryRunner.connection.driver instanceof OracleDriver){ - parentIds = updateResult.raw[0]; - } - else { - parentIds = updateResult.raw.map((row: any) => row[Object.keys(row)[0]]); - } - if (parentIds.length) { - // This is the recursive - check the relations of the relation - for (const subRelation of relation.inverseEntityMetadata.relations) { - await this.executeSoftRemoveRecursive(subRelation, parentIds); - } - } - } - } - protected async executeRecoverOperations(): Promise { await Promise.all(this.recoverSubjects.map(async subject => { diff --git a/test/github-issues/8416/8416.ts b/test/github-issues/8416/8416.ts deleted file mode 100644 index 27a9db59e2..0000000000 --- a/test/github-issues/8416/8416.ts +++ /dev/null @@ -1,75 +0,0 @@ -import "reflect-metadata"; -import { Connection, Repository } from "../../../src/index"; -import { reloadTestingDatabases, createTestingConnections, closeTestingConnections } from "../../utils/test-utils"; -import { expect } from "chai"; -import { Category } from "./entity/Category"; -import { Post } from "./entity/Post"; -import {Author} from "./entity/Author"; - -describe("Soft Delete Recursive cascade", () => { - - // ------------------------------------------------------------------------- - // Configuration - // ------------------------------------------------------------------------- - - // connect to db - let connections: Connection[] = []; - - before(async () => connections = await createTestingConnections({ - entities: [__dirname + "/entity/*{.js,.ts}"], - - })); - beforeEach(() => reloadTestingDatabases(connections)); - after(() => closeTestingConnections(connections)); - - // ------------------------------------------------------------------------- - // Specifications - // ------------------------------------------------------------------------- - - describe("when a Post is removed from a Category", () => { - let categoryRepository: Repository; - let postRepository: Repository; - let authorRepository: Repository; - - beforeEach(async () => { - await Promise.all(connections.map(async connection => { - categoryRepository = connection.getRepository(Category); - postRepository = connection.getRepository(Post); - authorRepository = connection.getRepository(Author); - })); - const firstPost: Post = new Post(); - firstPost.authors = [ - new Author(), - new Author() - ]; - const secondPost: Post = new Post(); - secondPost.authors = [ - new Author(), - new Author() - ]; - const categoryToInsert = new Category(); - categoryToInsert.posts = [ - firstPost, - secondPost - ]; - - await categoryRepository.save(categoryToInsert); - let insertedCategory: Category = await categoryRepository.findOneOrFail(); - await categoryRepository.softRemove(insertedCategory); - }); - - it("should delete the category", async () => { - const categoryCount = await categoryRepository.count(); - expect(categoryCount).to.equal(0); - }); - - it("should delete the all the posts", async () => { - const postCount = await postRepository.count(); - expect(postCount).to.equal(0); - }); - it("should delete the all the authors", async () => { - const authorsCount = await authorRepository.count(); - expect(authorsCount).to.equal(0); - }); - }); -}); diff --git a/test/github-issues/8416/entity/Author.ts b/test/github-issues/8416/entity/Author.ts deleted file mode 100644 index 85283fcb10..0000000000 --- a/test/github-issues/8416/entity/Author.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Entity} from "../../../../src/decorator/entity/Entity"; -import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; -import {Column} from "../../../../src/decorator/columns/Column"; -import {ManyToOne} from "../../../../src/decorator/relations/ManyToOne"; -import {JoinColumn} from "../../../../src/decorator/relations/JoinColumn"; -import {DeleteDateColumn} from "../../../../src"; -import {Post} from "./Post"; - -@Entity() -export class Author { - - @PrimaryGeneratedColumn() - id: number; - - @Column() - postId: string; - - @ManyToOne(() => Post, post => post.authors) - @JoinColumn({ name: "postId" }) - post: Post; - - @DeleteDateColumn() - deletedAt?: Date; -} diff --git a/test/github-issues/8416/entity/Category.ts b/test/github-issues/8416/entity/Category.ts deleted file mode 100644 index d513d6a9f8..0000000000 --- a/test/github-issues/8416/entity/Category.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {Entity} from "../../../../src/decorator/entity/Entity"; -import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; -import {Post} from "./Post"; -import {OneToMany} from "../../../../src/decorator/relations/OneToMany"; -import {DeleteDateColumn} from "../../../../src"; - -@Entity() -export class Category { - - @PrimaryGeneratedColumn() - id: number; - - @OneToMany(() => Post, post => post.category, { - cascade: true - }) - posts: Post[]; - - @DeleteDateColumn() - deletedAt?: Date; -} diff --git a/test/github-issues/8416/entity/Post.ts b/test/github-issues/8416/entity/Post.ts deleted file mode 100644 index eb6bba2071..0000000000 --- a/test/github-issues/8416/entity/Post.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Category} from "./Category"; -import {Entity} from "../../../../src/decorator/entity/Entity"; -import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; -import {Column} from "../../../../src/decorator/columns/Column"; -import {ManyToOne} from "../../../../src/decorator/relations/ManyToOne"; -import {JoinColumn} from "../../../../src/decorator/relations/JoinColumn"; -import {DeleteDateColumn, OneToMany} from "../../../../src"; -import {Author} from "./Author"; - -@Entity() -export class Post { - - @PrimaryGeneratedColumn() - id: number; - - @Column() - categoryId: string; - - @ManyToOne(() => Category, category => category.posts) - @JoinColumn({ name: "categoryId" }) - category: Category; - - @OneToMany(() => Author, author => author.post, { - cascade: true - }) - authors: Author[]; - - @DeleteDateColumn() - deletedAt?: Date; -}