Skip to content

Commit

Permalink
fix(utils): Cascade soft deletion management (#9534)
Browse files Browse the repository at this point in the history
* fix(utils): Cascade sOCoft deletion management

* fix(utils): Cascade sOCoft deletion management
  • Loading branch information
adrien2p authored Oct 14, 2024
1 parent 1b82f7a commit 5a60a2a
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 7 deletions.
9 changes: 8 additions & 1 deletion packages/core/utils/src/dal/mikro-orm/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Collection, EntityMetadata, FindOptions, wrap } from "@mikro-orm/core"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { buildQuery } from "../../modules-sdk/build-query"
import { isString } from "../../common/is-string"

function detectCircularDependency(
manager: SqlEntityManager,
Expand All @@ -23,7 +24,13 @@ function detectCircularDependency(
for (const relation of relationsToCascade) {
const branchVisited = new Set(Array.from(visited))

const isSelfCircularDependency = entityMetadata.class === relation.entity()
const relationEntity =
typeof relation.entity === "function"
? relation.entity()
: relation.entity
const isSelfCircularDependency = isString(relationEntity)
? entityMetadata.className === relationEntity
: entityMetadata.class === relationEntity

if (!isSelfCircularDependency && branchVisited.has(relation.name)) {
const dependencies = Array.from(visited)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import { MetadataStorage, MikroORM } from "@mikro-orm/core"
import { model } from "../../entity-builder"
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
import { createDatabase, dropDatabase } from "pg-god"
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../../dal"
import {
CustomTsMigrationGenerator,
mikroOrmSerializer,
mikroOrmUpdateDeletedAtRecursively,
SoftDeletableFilterKey,
} from "../../../dal"
import { EntityConstructor } from "@medusajs/types"
import { pgGodCredentials } from "../utils"
import { FileSystem } from "../../../common"
import { join } from "path"
import { SqlEntityManager } from "@mikro-orm/postgresql"

export const fileSystem = new FileSystem(
join(__dirname, "../../integration-tests-migrations-many-to-one")
Expand All @@ -31,11 +37,15 @@ describe("manyToOne - belongTo", () => {
user: model.belongsTo(() => user, { mappedBy: "teams" }),
})

const user = model.define("user", {
id: model.id().primaryKey(),
username: model.text(),
teams: model.hasMany(() => team, { mappedBy: "user" }),
})
const user = model
.define("user", {
id: model.id().primaryKey(),
username: model.text(),
teams: model.hasMany(() => team, { mappedBy: "user" }),
})
.cascades({
delete: ["teams"],
})

;[User, Team] = toMikroOrmEntities([user, team])

Expand Down Expand Up @@ -148,4 +158,115 @@ describe("manyToOne - belongTo", () => {
],
})
})

it(`should handle soft delete cascade`, async () => {
let manager = orm.em.fork()

const user1 = manager.create(User, {
username: "User 1",
})

await manager.persistAndFlush([user1])
manager = orm.em.fork()

const team1 = manager.create(Team, {
name: "Team 1",
user_id: user1.id,
})
const team2 = manager.create(Team, {
name: "Team 2",
user_id: user1.id,
})

await manager.persistAndFlush([team1, team2])
manager = orm.em.fork()

let teams = await manager.find(
Team,
{},
{
populate: ["user"],
}
)

const serializedTeams = await mikroOrmSerializer<InstanceType<typeof Team>>(
teams
)
expect(serializedTeams).toHaveLength(2)
expect(serializedTeams).toEqual(
expect.arrayContaining([
{
id: team1.id,
name: "Team 1",
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
user_id: user1.id,
user: {
id: user1.id,
username: "User 1",
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
},
},
{
id: team2.id,
name: "Team 2",
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
user_id: user1.id,
user: {
id: user1.id,
username: "User 1",
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
},
},
])
)

manager = orm.em.fork()
const userToDelete = await manager.findOne(User, {
id: user1.id,
})
await mikroOrmUpdateDeletedAtRecursively(
manager as SqlEntityManager,
[userToDelete],
new Date()
)

teams = await manager.find(
Team,
{},
{
populate: ["user"],
filters: {
[SoftDeletableFilterKey]: {
withDeleted: true,
},
},
}
)

expect(teams).toHaveLength(2)
expect(teams).toEqual(
expect.arrayContaining([
expect.objectContaining({
deleted_at: expect.any(Date),
user: expect.objectContaining({
deleted_at: expect.any(Date),
}),
}),
expect.objectContaining({
deleted_at: expect.any(Date),
user: expect.objectContaining({
deleted_at: expect.any(Date),
}),
}),
])
)
})
})

0 comments on commit 5a60a2a

Please sign in to comment.