Skip to content

Commit

Permalink
fix: resolve issue delete column null on after update event subscriber (
Browse files Browse the repository at this point in the history
#8318)

Closes: #6327
  • Loading branch information
spotykatch authored Nov 18, 2021
1 parent d494fcc commit 8a5e671
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/persistence/SubjectExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,11 +735,11 @@ export class SubjectExecutor {
this.updateSpecialColumnsInInsertedAndUpdatedEntities(this.updateSubjects);

// update soft-removed entity properties
if (this.updateSubjects.length)
if (this.softRemoveSubjects.length)
this.updateSpecialColumnsInInsertedAndUpdatedEntities(this.softRemoveSubjects);

// update recovered entity properties
if (this.updateSubjects.length)
if (this.recoverSubjects.length)
this.updateSpecialColumnsInInsertedAndUpdatedEntities(this.recoverSubjects);

// remove ids from the entities that were removed
Expand Down
14 changes: 12 additions & 2 deletions src/query-builder/ReturningResultsEntityUpdator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class ReturningResultsEntityUpdator {
} else {

// for driver which do not support returning/output statement we need to perform separate query and load what we need
const updationColumns = this.getUpdationReturningColumns();
const updationColumns = this.expressionMap.extraReturningColumns;
if (updationColumns.length > 0) {

// get entity id by which we will get needed data
Expand All @@ -62,9 +62,10 @@ export class ReturningResultsEntityUpdator {
const loadedReturningColumns = await this.queryRunner.manager
.createQueryBuilder()
.select(metadata.primaryColumns.map(column => metadata.targetName + "." + column.propertyPath))
.addSelect(this.getUpdationReturningColumns().map(column => metadata.targetName + "." + column.propertyPath))
.addSelect(updationColumns.map(column => metadata.targetName + "." + column.propertyPath))
.from(metadata.target, metadata.targetName)
.where(entityId)
.withDeleted()
.setOption("create-pojo") // use POJO because created object can contain default values, e.g. property = null and those properties maight be overridden by merge process
.getOne() as any;

Expand Down Expand Up @@ -194,4 +195,13 @@ export class ReturningResultsEntityUpdator {
});
}

/**
* Columns we need to be returned from the database when we soft delete and restore entity.
*/
getSoftDeletionReturningColumns(): ColumnMetadata[] {
return this.expressionMap.mainAlias!.metadata.columns.filter(column => {
return column.isUpdateDate || column.isVersion || column.isDeleteDate;
});
}

}
2 changes: 1 addition & 1 deletion src/query-builder/SoftDeleteQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class SoftDeleteQueryBuilder<Entity> extends QueryBuilder<Entity> impleme
if (this.expressionMap.updateEntity === true &&
this.expressionMap.mainAlias!.hasMetadata &&
this.expressionMap.whereEntities.length > 0) {
this.expressionMap.extraReturningColumns = returningResultsEntityUpdator.getUpdationReturningColumns();
this.expressionMap.extraReturningColumns = returningResultsEntityUpdator.getSoftDeletionReturningColumns();
}

// execute update query
Expand Down
13 changes: 13 additions & 0 deletions test/github-issues/6327/entity/Post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DeleteDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "../../../../src";

@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;

@UpdateDateColumn()
updatedAt: Date;

@DeleteDateColumn()
deletedAt: Date;
}
31 changes: 31 additions & 0 deletions test/github-issues/6327/issue-6327.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import "reflect-metadata";
import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Connection } from "../../../src/connection/Connection";
import { Post } from "./entity/Post";

describe("github issues > #6327 softRemove DeleteDateColumn is null at Susbscriber's AfterUpdate method", () => {

let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
subscribers: [__dirname + "/subscriber/*{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should send correct update and delete date columns to after update subscriber", () => Promise.all(connections.map(async connection => {

const manager = connection.manager;

const entity = new Post();
await manager.save(entity);

const deletedEntity = await manager.softRemove(entity, { data: { action: "soft-delete" } });

await manager.recover(deletedEntity, { data: { action: "restore" } });

})));

});
24 changes: 24 additions & 0 deletions test/github-issues/6327/subscriber/PostSubscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { expect } from "chai";
import { EntitySubscriberInterface, EventSubscriber, UpdateEvent } from "../../../../src";
import { Post } from "../entity/Post";

@EventSubscriber()
export class PostSubscriber implements EntitySubscriberInterface<Post> {
listenTo() {
return Post;
}

afterUpdate(event: UpdateEvent<Post>): void {
const { entity, queryRunner: { data } } = event;

expect(["soft-delete", "restore"]).to.include(data!.action);

if (data!.action === "soft-delete") {
expect(Object.prototype.toString.call(entity!.deletedAt)).to.be.eq("[object Date]");
}

if (data!.action === "restore") {
expect(entity!.deletedAt).to.be.null;
}
}
}

0 comments on commit 8a5e671

Please sign in to comment.