fix(product, utils): handle metadata key deletion on product update (#12478)

This commit is contained in:
Frane Polić
2025-05-21 21:32:12 +02:00
committed by GitHub
parent 4e49cebcf0
commit c5a6573e26
5 changed files with 18 additions and 54 deletions

View File

@@ -0,0 +1,6 @@
---
"@medusajs/product": patch
"@medusajs/utils": patch
---
fix(product, utils): handle metadata key deletion on product update

View File

@@ -1912,7 +1912,7 @@ medusaIntegrationTestRunner({
const payload = {
metadata: {
"test-key": "",
"test-key": "", // item is deleted by setting to empty string
"test-key-2": null,
},
}
@@ -1924,13 +1924,11 @@ medusaIntegrationTestRunner({
)
expect(response.status).toEqual(200)
expect(response.data.product.metadata).toEqual(
// BREAKING: Metadata updates are all-or-nothing in v2
{
"test-key": "",
"test-key-2": null,
}
)
expect(response.data.product.metadata).toEqual({
// "test-key" is deleted
"test-key-2": null, // updated
"test-key-3": "test-value-3", // preserved
})
})
it("updates products sales channels", async () => {

View File

@@ -72,7 +72,6 @@ export * from "./resolve-exports"
export * from "./rules"
export * from "./selector-constraints-to-string"
export * from "./serialize-error"
export * from "./set-metadata"
export * from "./simple-hash"
export * from "./string-to-select-relation-object"
export * from "./stringify-circular"

View File

@@ -1,45 +0,0 @@
import { MedusaError } from "./errors"
/**
* Dedicated method to set metadata.
* @param obj - the entity to apply metadata to.
* @param metadata - the metadata to set
* @return resolves to the updated result.
*/
export function setMetadata(
obj: { metadata: Record<string, unknown> | null },
metadata: Record<string, unknown>
): Record<string, unknown> {
const existing = obj.metadata || {}
const newData = {}
for (const [key, value] of Object.entries(metadata)) {
if (typeof key !== "string") {
throw new MedusaError(
MedusaError.Types.INVALID_ARGUMENT,
"Key type is invalid. Metadata keys must be strings"
)
}
/**
* We reserve the empty string as a way to delete a key.
* If the value is an empty string, we don't
* set it, and if it exists in the existing metadata, we
* unset the field.
*/
if (value === "") {
if (key in existing) {
delete existing[key]
}
continue
}
newData[key] = value
}
return {
...existing,
...newData,
}
}

View File

@@ -6,6 +6,8 @@ import {
buildQuery,
DALUtils,
MedusaError,
isPresent,
mergeMetadata,
} from "@medusajs/framework/utils"
import { SqlEntityManager, wrap } from "@mikro-orm/postgresql"
@@ -148,6 +150,10 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory(
)
}
if (isPresent(productToUpdate.metadata)) {
productToUpdate.metadata = mergeMetadata(product.metadata ?? {}, productToUpdate.metadata)
}
wrappedProduct.assign(productToUpdate)
}