Skip to content

Commit

Permalink
fix: resolve issue with find with relations returns soft-deleted enti…
Browse files Browse the repository at this point in the history
…ties (#7296)

This new feature changes the behavior of typeorm to allow avoiding entities that have soft delete
close: #6265
  • Loading branch information
luiseariass committed Feb 2, 2021
1 parent 2758502 commit d7cb338
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/query-builder/SelectQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,10 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
this.expressionMap.joinAttributes.push(joinAttribute);

if (joinAttribute.metadata) {

if (joinAttribute.metadata.deleteDateColumn && !this.expressionMap.withDeleted) {
const conditionDeleteColumn = `${aliasName}.${joinAttribute.metadata.deleteDateColumn.propertyName} IS NULL`;
joinAttribute.condition += joinAttribute.condition ? ` AND ${conditionDeleteColumn}`: `${conditionDeleteColumn}`;
}
// todo: find and set metadata right there?
joinAttribute.alias = this.expressionMap.createAlias({
type: "join",
Expand Down
23 changes: 23 additions & 0 deletions test/github-issues/6265/entity/Role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Entity } from "../../../../src/decorator/entity/Entity";
import {
OneToMany,
Column,
DeleteDateColumn,
PrimaryGeneratedColumn,
} from "../../../../src";
import { User } from "./User";

@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: string;

@Column()
title: string;

@OneToMany((_) => User, (user) => user.role, { cascade: true })
users: User[];

@DeleteDateColumn()
deleteDate?: Date;
}
23 changes: 23 additions & 0 deletions test/github-issues/6265/entity/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Entity } from "../../../../src/decorator/entity/Entity";
import {
ManyToOne,
Column,
DeleteDateColumn,
PrimaryGeneratedColumn,
} from "../../../../src";
import { Role } from "./Role";

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

@Column()
name: string;

@ManyToOne((_) => Role, (role) => role.users)
role: Role;

@DeleteDateColumn()
deleteAt?: Date;
}
97 changes: 97 additions & 0 deletions test/github-issues/6265/issue-6265.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import "reflect-metadata";
import { expect } from "chai";
import { Connection } from "../../../src";
import { User } from "./entity/User";
import { Role } from "./entity/Role";
import {
createTestingConnections,
reloadTestingDatabases,
closeTestingConnections,
} from "../../utils/test-utils";

describe("github issues > #6265 `fix: resolve issue with find with relations returns soft-deleted entities", () => {
let connections: Connection[];

before(async () => {
connections = await createTestingConnections({
entities: [User, Role],
schemaCreate: true,
dropSchema: true,
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should soft delete one record in relation table", () =>
Promise.all(
connections.map(async (connection) => {
const role = new Role();
role.title = "Manager";
await connection.manager.save(role);

const firstUser = new User();
firstUser.name = "Alex Messer";
firstUser.role = role;
await connection.manager.save(firstUser);

const secondUser = new User();
secondUser.name = "Timber Saw";
secondUser.role = role;
await connection.manager.save(secondUser);

const roleWithAllUser = await connection.manager
.createQueryBuilder(Role, "role")
.leftJoinAndSelect("role.users", "users")
.getMany();
expect(roleWithAllUser[0].users.length).eq(2);
expect(
roleWithAllUser.should.be.eql([
{
id: 1,
title: "Manager",
deleteDate: null,
users: [
{ id: 1, name: "Alex Messer", deleteAt: null },
{ id: 2, name: "Timber Saw", deleteAt: null },
],
},
])
);

await connection.manager
.createQueryBuilder(User, "user")
.softDelete()
.where({ name: "Timber Saw" })
.execute();

const roleWithUserIsNotSoftDelete = await connection.manager
.createQueryBuilder(Role, "role")
.leftJoinAndSelect("role.users", "users")
.getMany();

expect(roleWithUserIsNotSoftDelete[0].users.length).eq(1);

expect(
roleWithUserIsNotSoftDelete.should.be.eql([
{
id: 1,
title: "Manager",
deleteDate: null,
users: [
{ id: 1, name: "Alex Messer", deleteAt: null },
],
},
])
);
const roleWithUserSoftDelete = await connection.manager
.createQueryBuilder(Role, "role")
.withDeleted()
.leftJoinAndSelect("role.users", "users")
.getMany();

expect(roleWithUserSoftDelete[0].users.length).eq(2);
expect(roleWithUserSoftDelete[0].users[1].deleteAt).to.be.not
.null;
})
));
});

0 comments on commit d7cb338

Please sign in to comment.