chore(utils): Soft delete should allow self referencing circular deps (#6504)
**What** Self referencing circular dep should not be an error and should be accepted
This commit is contained in:
1 parent
d983329481
commit
56cbf88115
5 files changed
+91
-5
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/utils": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore(utils): Soft delete should allow self referencing circular deps
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SuiteOptions, moduleIntegrationTestRunner } from "medusa-test-utils"
|
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
|
||||||
import { ITaxModuleService } from "@medusajs/types"
|
import { ITaxModuleService } from "@medusajs/types"
|
||||||
import { Modules } from "@medusajs/modules-sdk"
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,42 @@ class DeepRecursiveEntity4 {
|
|||||||
entity1: DeepRecursiveEntity1
|
entity1: DeepRecursiveEntity1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal circular dependency
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
class InternalCircularDependencyEntity1 {
|
||||||
|
constructor(props: {
|
||||||
|
id: string
|
||||||
|
deleted_at: Date | null
|
||||||
|
parent?: InternalCircularDependencyEntity1
|
||||||
|
}) {
|
||||||
|
this.id = props.id
|
||||||
|
this.deleted_at = props.deleted_at
|
||||||
|
|
||||||
|
if (props.parent) {
|
||||||
|
this.parent = props.parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKey()
|
||||||
|
id: string
|
||||||
|
|
||||||
|
@Property()
|
||||||
|
deleted_at: Date | null
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
() => InternalCircularDependencyEntity1,
|
||||||
|
(entity) => entity.parent,
|
||||||
|
{
|
||||||
|
cascade: ["soft-remove"] as any,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
children = new Collection<InternalCircularDependencyEntity1>(this)
|
||||||
|
|
||||||
|
@ManyToOne(() => InternalCircularDependencyEntity1)
|
||||||
|
parent: InternalCircularDependencyEntity1
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
RecursiveEntity1,
|
RecursiveEntity1,
|
||||||
RecursiveEntity2,
|
RecursiveEntity2,
|
||||||
@@ -198,4 +234,5 @@ export {
|
|||||||
DeepRecursiveEntity2,
|
DeepRecursiveEntity2,
|
||||||
DeepRecursiveEntity3,
|
DeepRecursiveEntity3,
|
||||||
DeepRecursiveEntity4,
|
DeepRecursiveEntity4,
|
||||||
|
InternalCircularDependencyEntity1,
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
DeepRecursiveEntity4,
|
DeepRecursiveEntity4,
|
||||||
Entity1,
|
Entity1,
|
||||||
Entity2,
|
Entity2,
|
||||||
|
InternalCircularDependencyEntity1,
|
||||||
RecursiveEntity1,
|
RecursiveEntity1,
|
||||||
RecursiveEntity2,
|
RecursiveEntity2,
|
||||||
} from "../__fixtures__/utils"
|
} from "../__fixtures__/utils"
|
||||||
@@ -38,6 +39,7 @@ describe("mikroOrmUpdateDeletedAtRecursively", () => {
|
|||||||
DeepRecursiveEntity2,
|
DeepRecursiveEntity2,
|
||||||
DeepRecursiveEntity3,
|
DeepRecursiveEntity3,
|
||||||
DeepRecursiveEntity4,
|
DeepRecursiveEntity4,
|
||||||
|
InternalCircularDependencyEntity1,
|
||||||
],
|
],
|
||||||
dbName: "test",
|
dbName: "test",
|
||||||
type: "postgresql",
|
type: "postgresql",
|
||||||
@@ -65,6 +67,26 @@ describe("mikroOrmUpdateDeletedAtRecursively", () => {
|
|||||||
expect(entity2.deleted_at).toEqual(deletedAt)
|
expect(entity2.deleted_at).toEqual(deletedAt)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should successfully mark the entities deleted_at recursively with internal parent/child relation", async () => {
|
||||||
|
const manager = orm.em.fork() as SqlEntityManager
|
||||||
|
const entity1 = new InternalCircularDependencyEntity1({
|
||||||
|
id: "1",
|
||||||
|
deleted_at: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const childEntity1 = new InternalCircularDependencyEntity1({
|
||||||
|
id: "2",
|
||||||
|
deleted_at: null,
|
||||||
|
parent: entity1,
|
||||||
|
})
|
||||||
|
|
||||||
|
const deletedAt = new Date()
|
||||||
|
await mikroOrmUpdateDeletedAtRecursively(manager, [entity1], deletedAt)
|
||||||
|
|
||||||
|
expect(entity1.deleted_at).toEqual(deletedAt)
|
||||||
|
expect(childEntity1.deleted_at).toEqual(deletedAt)
|
||||||
|
})
|
||||||
|
|
||||||
it("should throw an error when a circular dependency is detected", async () => {
|
it("should throw an error when a circular dependency is detected", async () => {
|
||||||
const manager = orm.em.fork() as SqlEntityManager
|
const manager = orm.em.fork() as SqlEntityManager
|
||||||
const entity1 = new RecursiveEntity1({ id: "1", deleted_at: null })
|
const entity1 = new RecursiveEntity1({ id: "1", deleted_at: null })
|
||||||
|
|||||||
@@ -5,8 +5,13 @@ import { SqlEntityManager } from "@mikro-orm/postgresql"
|
|||||||
function detectCircularDependency(
|
function detectCircularDependency(
|
||||||
manager: SqlEntityManager,
|
manager: SqlEntityManager,
|
||||||
entityMetadata: EntityMetadata,
|
entityMetadata: EntityMetadata,
|
||||||
visited: Set<string> = new Set()
|
visited: Set<string> = new Set(),
|
||||||
|
shouldStop: boolean = false
|
||||||
) {
|
) {
|
||||||
|
if (shouldStop) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
visited.add(entityMetadata.className)
|
visited.add(entityMetadata.className)
|
||||||
|
|
||||||
const relations = entityMetadata.relations
|
const relations = entityMetadata.relations
|
||||||
@@ -17,7 +22,9 @@ 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))
|
||||||
|
|
||||||
if (branchVisited.has(relation.name)) {
|
const isSelfCircularDependency = entityMetadata.class === relation.entity()
|
||||||
|
|
||||||
|
if (!isSelfCircularDependency && branchVisited.has(relation.name)) {
|
||||||
const dependencies = Array.from(visited)
|
const dependencies = Array.from(visited)
|
||||||
dependencies.push(entityMetadata.className)
|
dependencies.push(entityMetadata.className)
|
||||||
const circularDependencyStr = dependencies.join(" -> ")
|
const circularDependencyStr = dependencies.join(" -> ")
|
||||||
@@ -33,7 +40,12 @@ function detectCircularDependency(
|
|||||||
.getMetadata()
|
.getMetadata()
|
||||||
.get(relation.type)
|
.get(relation.type)
|
||||||
|
|
||||||
detectCircularDependency(manager, relationEntityMetadata, branchVisited)
|
detectCircularDependency(
|
||||||
|
manager,
|
||||||
|
relationEntityMetadata,
|
||||||
|
branchVisited,
|
||||||
|
isSelfCircularDependency
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +94,9 @@ async function performCascadingSoftDeletion<T>(
|
|||||||
if (!entityRelation) {
|
if (!entityRelation) {
|
||||||
// Fixes the case of many to many through pivot table
|
// Fixes the case of many to many through pivot table
|
||||||
entityRelation = await retrieveEntity()
|
entityRelation = await retrieveEntity()
|
||||||
|
if (!entityRelation) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCollection = "toArray" in entityRelation
|
const isCollection = "toArray" in entityRelation
|
||||||
@@ -94,10 +109,17 @@ async function performCascadingSoftDeletion<T>(
|
|||||||
}
|
}
|
||||||
relationEntities = entityRelation.getItems()
|
relationEntities = entityRelation.getItems()
|
||||||
} else {
|
} else {
|
||||||
const initializedEntityRelation = await wrap(entityRelation).init()
|
const wrappedEntity = wrap(entityRelation)
|
||||||
|
const initializedEntityRelation = wrappedEntity.isInitialized()
|
||||||
|
? entityRelation
|
||||||
|
: await wrap(entityRelation).init()
|
||||||
relationEntities = [initializedEntityRelation]
|
relationEntities = [initializedEntityRelation]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!relationEntities.length) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
await mikroOrmUpdateDeletedAtRecursively(manager, relationEntities, value)
|
await mikroOrmUpdateDeletedAtRecursively(manager, relationEntities, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user