feat: Improve how options are defined and handled for product (#7007)

* feat: Improve how options are defined and handled for product

* fix: Updating option values supports passing without id
This commit is contained in:
Stevche Radevski
2024-04-08 15:29:41 +02:00
committed by GitHub
parent 7b4ff1ae57
commit fa5c9bbe8f
18 changed files with 320 additions and 437 deletions

View File

@@ -13,7 +13,10 @@ export const dbErrorMapper = (err: Error) => {
throw new MedusaError(MedusaError.Types.NOT_FOUND, err.message)
}
if (err instanceof UniqueConstraintViolationException) {
if (
err instanceof UniqueConstraintViolationException ||
(err as any).code === "23505"
) {
const info = getConstraintInfo(err)
if (!info) {
throw err
@@ -27,7 +30,10 @@ export const dbErrorMapper = (err: Error) => {
)
}
if (err instanceof NotNullConstraintViolationException) {
if (
err instanceof NotNullConstraintViolationException ||
(err as any).code === "23502"
) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Cannot set field '${(err as any).column}' of ${upperCaseFirst(
@@ -36,7 +42,10 @@ export const dbErrorMapper = (err: Error) => {
)
}
if (err instanceof InvalidFieldNameException) {
if (
err instanceof InvalidFieldNameException ||
(err as any).code === "42703"
) {
const userFriendlyMessage = err.message.match(/(column.*)/)?.[0]
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
@@ -44,7 +53,10 @@ export const dbErrorMapper = (err: Error) => {
)
}
if (err instanceof ForeignKeyConstraintViolationException) {
if (
err instanceof ForeignKeyConstraintViolationException ||
(err as any).code === "23503"
) {
const info = getConstraintInfo(err)
throw new MedusaError(
MedusaError.Types.NOT_FOUND,

View File

@@ -656,8 +656,7 @@ describe("mikroOrmRepository", () => {
expect(listedEntities[0].entity3.getItems()).toEqual(
expect.arrayContaining([
expect.objectContaining({
// title: "en3-1",
title: "newen3-1",
title: "en3-1",
}),
expect.objectContaining({
title: "en3-4",
@@ -744,8 +743,7 @@ describe("mikroOrmRepository", () => {
expect(listedEntities[0].entity3.getItems()).toEqual(
expect.arrayContaining([
expect.objectContaining({
// title: "en3-1",
title: "newen3-1",
title: "en3-1",
}),
expect.objectContaining({
title: "en3-4",
@@ -817,31 +815,34 @@ describe("mikroOrmRepository", () => {
)
})
// it("should correctly handle many-to-many upserts with a uniqueness constriant on a non-primary key", async () => {
// const entity1 = {
// id: "1",
// title: "en1",
// entity3: [{ title: "en3-1" }, { title: "en3-2" }] as any,
// }
it("should correctly handle many-to-many upserts with a uniqueness constriant on a non-primary key", async () => {
const entity1 = {
id: "1",
title: "en1",
entity3: [
{ id: "4", title: "en3-1" },
{ id: "5", title: "en3-2" },
] as any,
}
// await manager1().upsertWithReplace([entity1], {
// relations: ["entity3"],
// })
await manager1().upsertWithReplace([entity1], {
relations: ["entity3"],
})
// await manager1().upsertWithReplace([{ ...entity1, id: "2" }], {
// relations: ["entity3"],
// })
await manager1().upsertWithReplace([{ ...entity1, id: "2" }], {
relations: ["entity3"],
})
// const listedEntities = await manager1().find({
// where: {},
// options: { populate: ["entity3"] },
// })
const listedEntities = await manager1().find({
where: {},
options: { populate: ["entity3"] },
})
// expect(listedEntities).toHaveLength(2)
// expect(listedEntities[0].entity3.getItems()).toEqual(
// listedEntities[1].entity3.getItems()
// )
// })
expect(listedEntities).toHaveLength(2)
expect(listedEntities[0].entity3.getItems()).toEqual(
listedEntities[1].entity3.getItems()
)
})
})
describe("error mapping", () => {

View File

@@ -602,8 +602,7 @@ export function mikroOrmBaseRepositoryFactory<T extends object = object>(
return normalizedData
}
// TODO: Currently we will also do an update of the data on the other side of the many-to-many relationship. Reevaluate if we should avoid that.
await this.upsertMany_(manager, relation.type, normalizedData)
await this.upsertMany_(manager, relation.type, normalizedData, true)
const pivotData = normalizedData.map((currModel) => {
return {
@@ -721,39 +720,17 @@ export function mikroOrmBaseRepositoryFactory<T extends object = object>(
return { id: (created as any).id, ...data }
}
protected async upsertManyToOneRelations_(
manager: SqlEntityManager,
upsertsPerType: Record<string, any[]>
) {
const typesToUpsert = Object.entries(upsertsPerType)
if (!typesToUpsert.length) {
return []
}
return (
await promiseAll(
typesToUpsert.map(([type, data]) => {
return this.upsertMany_(manager, type, data)
})
)
).flat()
}
protected async upsertMany_(
manager: SqlEntityManager,
entityName: string,
entries: any[]
entries: any[],
skipUpdate: boolean = false
) {
const existingEntities: any[] = await manager.find(
entityName,
{
id: { $in: entries.map((d) => d.id) },
},
{
populate: [],
disableIdentityMap: true,
}
)
const selectQb = manager.qb(entityName)
const existingEntities: any[] = await selectQb.select("*").where({
id: { $in: entries.map((d) => d.id) },
})
const existingEntitiesMap = new Map(
existingEntities.map((e) => [e.id, e])
)
@@ -762,12 +739,21 @@ export function mikroOrmBaseRepositoryFactory<T extends object = object>(
await promiseAll(
entries.map(async (data) => {
orderedEntities.push(data)
const existingEntity = existingEntitiesMap.get(data.id)
orderedEntities.push(data)
if (existingEntity) {
if (skipUpdate) {
return
}
await manager.nativeUpdate(entityName, { id: data.id }, data)
} else {
await manager.insert(entityName, data)
const qb = manager.qb(entityName)
if (skipUpdate) {
await qb.insert(data).onConflict().ignore().execute()
} else {
await manager.insert(entityName, data)
// await manager.insert(entityName, data)
}
}
})
)