fix(utils): Cascade soft deletion management (#9534)
* fix(utils): Cascade sOCoft deletion management * fix(utils): Cascade sOCoft deletion management
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { Collection, EntityMetadata, FindOptions, wrap } from "@mikro-orm/core"
|
import { Collection, EntityMetadata, FindOptions, wrap } from "@mikro-orm/core"
|
||||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
import { buildQuery } from "../../modules-sdk/build-query"
|
import { buildQuery } from "../../modules-sdk/build-query"
|
||||||
|
import { isString } from "../../common/is-string"
|
||||||
|
|
||||||
function detectCircularDependency(
|
function detectCircularDependency(
|
||||||
manager: SqlEntityManager,
|
manager: SqlEntityManager,
|
||||||
@@ -23,7 +24,13 @@ function detectCircularDependency(
|
|||||||
for (const relation of relationsToCascade) {
|
for (const relation of relationsToCascade) {
|
||||||
const branchVisited = new Set(Array.from(visited))
|
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)) {
|
if (!isSelfCircularDependency && branchVisited.has(relation.name)) {
|
||||||
const dependencies = Array.from(visited)
|
const dependencies = Array.from(visited)
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ import { MetadataStorage, MikroORM } from "@mikro-orm/core"
|
|||||||
import { model } from "../../entity-builder"
|
import { model } from "../../entity-builder"
|
||||||
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
|
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
import { createDatabase, dropDatabase } from "pg-god"
|
||||||
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../../dal"
|
import {
|
||||||
|
CustomTsMigrationGenerator,
|
||||||
|
mikroOrmSerializer,
|
||||||
|
mikroOrmUpdateDeletedAtRecursively,
|
||||||
|
SoftDeletableFilterKey,
|
||||||
|
} from "../../../dal"
|
||||||
import { EntityConstructor } from "@medusajs/types"
|
import { EntityConstructor } from "@medusajs/types"
|
||||||
import { pgGodCredentials } from "../utils"
|
import { pgGodCredentials } from "../utils"
|
||||||
import { FileSystem } from "../../../common"
|
import { FileSystem } from "../../../common"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
|
|
||||||
export const fileSystem = new FileSystem(
|
export const fileSystem = new FileSystem(
|
||||||
join(__dirname, "../../integration-tests-migrations-many-to-one")
|
join(__dirname, "../../integration-tests-migrations-many-to-one")
|
||||||
@@ -31,11 +37,15 @@ describe("manyToOne - belongTo", () => {
|
|||||||
user: model.belongsTo(() => user, { mappedBy: "teams" }),
|
user: model.belongsTo(() => user, { mappedBy: "teams" }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const user = model.define("user", {
|
const user = model
|
||||||
|
.define("user", {
|
||||||
id: model.id().primaryKey(),
|
id: model.id().primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
teams: model.hasMany(() => team, { mappedBy: "user" }),
|
teams: model.hasMany(() => team, { mappedBy: "user" }),
|
||||||
})
|
})
|
||||||
|
.cascades({
|
||||||
|
delete: ["teams"],
|
||||||
|
})
|
||||||
|
|
||||||
;[User, Team] = toMikroOrmEntities([user, team])
|
;[User, Team] = toMikroOrmEntities([user, team])
|
||||||
|
|
||||||
@@ -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),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user