chore(): Prevent from soft deleting all entities (#6396)
**What** The internal service abstraction should return idempotently if an empty array is given in order to prevent full soft deletion of the full data
This commit is contained in:
1 parent
4d51f095b3
commit
6500f18b9b
4 files changed
+54
-28
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/utils": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore(): Prevent from soft deleting all entities
|
||||||
@@ -85,7 +85,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
instance = new abstractModuleService(containerMock)
|
instance = new abstractModuleService(containerMock)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have retrieve method", async () => {
|
it("should have retrieve method", async () => {
|
||||||
const result = await instance.retrieve("1")
|
const result = await instance.retrieve("1")
|
||||||
expect(result).toEqual({ id: "1", name: "Item" })
|
expect(result).toEqual({ id: "1", name: "Item" })
|
||||||
expect(containerMock.mainModelMockService.retrieve).toHaveBeenCalledWith(
|
expect(containerMock.mainModelMockService.retrieve).toHaveBeenCalledWith(
|
||||||
@@ -95,7 +95,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have list method", async () => {
|
it("should have list method", async () => {
|
||||||
const result = await instance.list()
|
const result = await instance.list()
|
||||||
expect(result).toEqual([{ id: "1", name: "Item" }])
|
expect(result).toEqual([{ id: "1", name: "Item" }])
|
||||||
expect(containerMock.mainModelMockService.list).toHaveBeenCalledWith(
|
expect(containerMock.mainModelMockService.list).toHaveBeenCalledWith(
|
||||||
@@ -105,7 +105,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have delete method", async () => {
|
it("should have delete method", async () => {
|
||||||
await instance.delete("1")
|
await instance.delete("1")
|
||||||
expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith(
|
expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith(
|
||||||
["1"],
|
["1"],
|
||||||
@@ -113,7 +113,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have softDelete method", async () => {
|
it("should have softDelete method", async () => {
|
||||||
const result = await instance.softDelete("1")
|
const result = await instance.softDelete("1")
|
||||||
expect(result).toEqual(undefined)
|
expect(result).toEqual(undefined)
|
||||||
expect(
|
expect(
|
||||||
@@ -121,7 +121,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
).toHaveBeenCalledWith(["1"], defaultTransactionContext)
|
).toHaveBeenCalledWith(["1"], defaultTransactionContext)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have restore method", async () => {
|
it("should have restore method", async () => {
|
||||||
const result = await instance.restore("1")
|
const result = await instance.restore("1")
|
||||||
expect(result).toEqual(undefined)
|
expect(result).toEqual(undefined)
|
||||||
expect(containerMock.mainModelMockService.restore).toHaveBeenCalledWith(
|
expect(containerMock.mainModelMockService.restore).toHaveBeenCalledWith(
|
||||||
@@ -130,7 +130,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have delete method with selector", async () => {
|
it("should have delete method with selector", async () => {
|
||||||
await instance.delete({ selector: { id: "1" } })
|
await instance.delete({ selector: { id: "1" } })
|
||||||
expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith(
|
expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith(
|
||||||
[{ selector: { id: "1" } }],
|
[{ selector: { id: "1" } }],
|
||||||
@@ -147,7 +147,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
instance = new abstractModuleService(containerMock)
|
instance = new abstractModuleService(containerMock)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have retrieve method for other models", async () => {
|
it("should have retrieve method for other models", async () => {
|
||||||
const result = await instance.retrieveOtherModelMock1("1")
|
const result = await instance.retrieveOtherModelMock1("1")
|
||||||
expect(result).toEqual({ id: "1", name: "Item" })
|
expect(result).toEqual({ id: "1", name: "Item" })
|
||||||
expect(
|
expect(
|
||||||
@@ -155,7 +155,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
).toHaveBeenCalledWith("1", undefined, defaultContext)
|
).toHaveBeenCalledWith("1", undefined, defaultContext)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have list method for other models", async () => {
|
it("should have list method for other models", async () => {
|
||||||
const result = await instance.listOtherModelMock1s()
|
const result = await instance.listOtherModelMock1s()
|
||||||
expect(result).toEqual([{ id: "1", name: "Item" }])
|
expect(result).toEqual([{ id: "1", name: "Item" }])
|
||||||
expect(containerMock.otherModelMock1Service.list).toHaveBeenCalledWith(
|
expect(containerMock.otherModelMock1Service.list).toHaveBeenCalledWith(
|
||||||
@@ -165,7 +165,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have delete method for other models", async () => {
|
it("should have delete method for other models", async () => {
|
||||||
await instance.deleteOtherModelMock1s("1")
|
await instance.deleteOtherModelMock1s("1")
|
||||||
expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith(
|
expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith(
|
||||||
["1"],
|
["1"],
|
||||||
@@ -173,7 +173,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have softDelete method for other models", async () => {
|
it("should have softDelete method for other models", async () => {
|
||||||
const result = await instance.softDeleteOtherModelMock1s("1")
|
const result = await instance.softDeleteOtherModelMock1s("1")
|
||||||
expect(result).toEqual(undefined)
|
expect(result).toEqual(undefined)
|
||||||
expect(
|
expect(
|
||||||
@@ -181,7 +181,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
).toHaveBeenCalledWith(["1"], defaultTransactionContext)
|
).toHaveBeenCalledWith(["1"], defaultTransactionContext)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have restore method for other models", async () => {
|
it("should have restore method for other models", async () => {
|
||||||
const result = await instance.restoreOtherModelMock1s("1")
|
const result = await instance.restoreOtherModelMock1s("1")
|
||||||
expect(result).toEqual(undefined)
|
expect(result).toEqual(undefined)
|
||||||
expect(containerMock.otherModelMock1Service.restore).toHaveBeenCalledWith(
|
expect(containerMock.otherModelMock1Service.restore).toHaveBeenCalledWith(
|
||||||
@@ -190,7 +190,7 @@ describe("Abstract Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should have delete method for other models with selector", async () => {
|
it("should have delete method for other models with selector", async () => {
|
||||||
await instance.deleteOtherModelMock1s({ selector: { id: "1" } })
|
await instance.deleteOtherModelMock1s({ selector: { id: "1" } })
|
||||||
expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith(
|
expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith(
|
||||||
[{ selector: { id: "1" } }],
|
[{ selector: { id: "1" } }],
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ describe("Internal Module Service Factory", () => {
|
|||||||
instance = new internalModuleService(containerMock)
|
instance = new internalModuleService(containerMock)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should throw model id undefined error on retrieve if id is not defined", async () => {
|
it("should throw model id undefined error on retrieve if id is not defined", async () => {
|
||||||
const err = await instance.retrieve().catch((e) => e)
|
const err = await instance.retrieve().catch((e) => e)
|
||||||
expect(err.message).toBe("model - id must be defined")
|
expect(err.message).toBe("model - id must be defined")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should throw an error on retrieve if composite key values are not defined", async () => {
|
it("should throw an error on retrieve if composite key values are not defined", async () => {
|
||||||
class CompositeModel {
|
class CompositeModel {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
@@ -66,14 +66,14 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(err.message).toBe("compositeModel - id, name must be defined")
|
expect(err.message).toBe("compositeModel - id, name must be defined")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should throw NOT_FOUND error on retrieve if entity not found", async () => {
|
it("should throw NOT_FOUND error on retrieve if entity not found", async () => {
|
||||||
containerMock[modelRepositoryName].find.mockResolvedValueOnce([])
|
containerMock[modelRepositoryName].find.mockResolvedValueOnce([])
|
||||||
|
|
||||||
const err = await instance.retrieve("1").catch((e) => e)
|
const err = await instance.retrieve("1").catch((e) => e)
|
||||||
expect(err.message).toBe("Model with id: 1 was not found")
|
expect(err.message).toBe("Model with id: 1 was not found")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should retrieve entity successfully", async () => {
|
it("should retrieve entity successfully", async () => {
|
||||||
const entity = { id: "1", name: "Item" }
|
const entity = { id: "1", name: "Item" }
|
||||||
containerMock[modelRepositoryName].find.mockResolvedValueOnce([entity])
|
containerMock[modelRepositoryName].find.mockResolvedValueOnce([entity])
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual(entity)
|
expect(result).toEqual(entity)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should retrieve entity successfully with composite key", async () => {
|
it("should retrieve entity successfully with composite key", async () => {
|
||||||
class CompositeModel {
|
class CompositeModel {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
@@ -103,7 +103,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual(entity)
|
expect(result).toEqual(entity)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should list entities successfully", async () => {
|
it("should list entities successfully", async () => {
|
||||||
const entities = [
|
const entities = [
|
||||||
{ id: "1", name: "Item" },
|
{ id: "1", name: "Item" },
|
||||||
{ id: "2", name: "Item2" },
|
{ id: "2", name: "Item2" },
|
||||||
@@ -114,7 +114,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual(entities)
|
expect(result).toEqual(entities)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should list and count entities successfully", async () => {
|
it("should list and count entities successfully", async () => {
|
||||||
const entities = [
|
const entities = [
|
||||||
{ id: "1", name: "Item" },
|
{ id: "1", name: "Item" },
|
||||||
{ id: "2", name: "Item2" },
|
{ id: "2", name: "Item2" },
|
||||||
@@ -129,7 +129,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual([entities, count])
|
expect(result).toEqual([entities, count])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should create entity successfully", async () => {
|
it("should create entity successfully", async () => {
|
||||||
const entity = { id: "1", name: "Item" }
|
const entity = { id: "1", name: "Item" }
|
||||||
|
|
||||||
containerMock[modelRepositoryName].find.mockReturnValue([entity])
|
containerMock[modelRepositoryName].find.mockReturnValue([entity])
|
||||||
@@ -142,7 +142,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual(entity)
|
expect(result).toEqual(entity)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should create entities successfully", async () => {
|
it("should create entities successfully", async () => {
|
||||||
const entities = [
|
const entities = [
|
||||||
{ id: "1", name: "Item" },
|
{ id: "1", name: "Item" },
|
||||||
{ id: "2", name: "Item2" },
|
{ id: "2", name: "Item2" },
|
||||||
@@ -156,7 +156,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual(entities)
|
expect(result).toEqual(entities)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should update entity successfully", async () => {
|
it("should update entity successfully", async () => {
|
||||||
const updateData = { id: "1", name: "UpdatedItem" }
|
const updateData = { id: "1", name: "UpdatedItem" }
|
||||||
|
|
||||||
containerMock[modelRepositoryName].find.mockResolvedValueOnce([
|
containerMock[modelRepositoryName].find.mockResolvedValueOnce([
|
||||||
@@ -171,7 +171,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
expect(result).toEqual([updateData])
|
expect(result).toEqual([updateData])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should update entities successfully", async () => {
|
it("should update entities successfully", async () => {
|
||||||
const updateData = { id: "1", name: "UpdatedItem" }
|
const updateData = { id: "1", name: "UpdatedItem" }
|
||||||
const entitiesToUpdate = [{ id: "1", name: "Item" }]
|
const entitiesToUpdate = [{ id: "1", name: "Item" }]
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should delete entity successfully", async () => {
|
it("should delete entity successfully", async () => {
|
||||||
await instance.delete("1")
|
await instance.delete("1")
|
||||||
expect(containerMock[modelRepositoryName].delete).toHaveBeenCalledWith(
|
expect(containerMock[modelRepositoryName].delete).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
@@ -203,7 +203,7 @@ describe("Internal Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should delete entities successfully", async () => {
|
it("should delete entities successfully", async () => {
|
||||||
const entitiesToDelete = [{ id: "1", name: "Item" }]
|
const entitiesToDelete = [{ id: "1", name: "Item" }]
|
||||||
containerMock[modelRepositoryName].find.mockResolvedValueOnce(
|
containerMock[modelRepositoryName].find.mockResolvedValueOnce(
|
||||||
entitiesToDelete
|
entitiesToDelete
|
||||||
@@ -222,14 +222,31 @@ describe("Internal Module Service Factory", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should soft delete entity successfully", async () => {
|
it("should prevent from deleting all entities", async () => {
|
||||||
|
const entitiesToDelete = [{ id: "1", name: "Item" }]
|
||||||
|
containerMock[modelRepositoryName].find.mockResolvedValueOnce(
|
||||||
|
entitiesToDelete
|
||||||
|
)
|
||||||
|
|
||||||
|
await instance.delete([])
|
||||||
|
expect(containerMock[modelRepositoryName].delete).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should soft delete entity successfully", async () => {
|
||||||
await instance.softDelete("1")
|
await instance.softDelete("1")
|
||||||
expect(
|
expect(
|
||||||
containerMock[modelRepositoryName].softDelete
|
containerMock[modelRepositoryName].softDelete
|
||||||
).toHaveBeenCalledWith("1", defaultContext)
|
).toHaveBeenCalledWith("1", defaultContext)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should restore entity successfully", async () => {
|
it("should prevent from soft deleting all data", async () => {
|
||||||
|
await instance.softDelete([])
|
||||||
|
expect(
|
||||||
|
containerMock[modelRepositoryName].softDelete
|
||||||
|
).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should restore entity successfully", async () => {
|
||||||
await instance.restore("1")
|
await instance.restore("1")
|
||||||
expect(containerMock[modelRepositoryName].restore).toHaveBeenCalledWith(
|
expect(containerMock[modelRepositoryName].restore).toHaveBeenCalledWith(
|
||||||
"1",
|
"1",
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ export function internalModuleServiceFactory<
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (
|
if (
|
||||||
!isDefined(idOrSelector) ||
|
!isDefined(idOrSelector) ||
|
||||||
(Array.isArray(idOrSelector) && idOrSelector.length === 0)
|
(Array.isArray(idOrSelector) && !idOrSelector.length)
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -402,6 +402,10 @@ export function internalModuleServiceFactory<
|
|||||||
idsOrFilter: string[] | InternalFilterQuery,
|
idsOrFilter: string[] | InternalFilterQuery,
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<[TEntity[], Record<string, unknown[]>]> {
|
): Promise<[TEntity[], Record<string, unknown[]>]> {
|
||||||
|
if (Array.isArray(idsOrFilter) && !idsOrFilter.length) {
|
||||||
|
return [[], {}]
|
||||||
|
}
|
||||||
|
|
||||||
return await this[propertyRepositoryName].softDelete(
|
return await this[propertyRepositoryName].softDelete(
|
||||||
idsOrFilter,
|
idsOrFilter,
|
||||||
sharedContext
|
sharedContext
|
||||||
|
|||||||
Reference in new issue
Block a user