From ab634a14ba709f1b1d12eb4cd5c7f3db6bfe6470 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 12 Jun 2025 17:55:49 +0200 Subject: [PATCH] fix(utils): medusa internal service returned data should match typings (#12715) FIXES SUP-1824 **What** The medusa internal service update should always return the data in the expected shape described by the interface. The medusa service should not have to handle the reshapre --- .changeset/big-olives-do.md | 10 ++++ .../modules-sdk/medusa-internal-service.ts | 15 +++++- .../utils/src/modules-sdk/medusa-service.ts | 7 +-- .../modules/auth/src/services/auth-module.ts | 4 +- .../customer/src/services/customer-module.ts | 2 +- .../services/fulfillment-module-service.ts | 6 ++- .../src/services/inventory-module.ts | 2 +- .../payment/src/services/payment-module.ts | 20 ++++--- .../integration-tests/__tests__/product.ts | 53 +++++++++++++++++++ 9 files changed, 94 insertions(+), 25 deletions(-) create mode 100644 .changeset/big-olives-do.md diff --git a/.changeset/big-olives-do.md b/.changeset/big-olives-do.md new file mode 100644 index 0000000000..fafa146a1f --- /dev/null +++ b/.changeset/big-olives-do.md @@ -0,0 +1,10 @@ +--- +"@medusajs/utils": patch +"@medusajs/auth": patch +"@medusajs/customer": patch +"@medusajs/fulfillment": patch +"@medusajs/inventory": patch +"@medusajs/payment": patch +--- + +fix(utils): medusa internal service returned data should match typings diff --git a/packages/core/utils/src/modules-sdk/medusa-internal-service.ts b/packages/core/utils/src/modules-sdk/medusa-internal-service.ts index 4c6be7e88e..2edc4af678 100644 --- a/packages/core/utils/src/modules-sdk/medusa-internal-service.ts +++ b/packages/core/utils/src/modules-sdk/medusa-internal-service.ts @@ -260,6 +260,13 @@ export function MedusaInternalService< | InferEntityType[] } + let shouldReturnArray = false + if (Array.isArray(input)) { + shouldReturnArray = true + } else if (isObject(input) && "selector" in input) { + shouldReturnArray = true + } + const primaryKeys = AbstractService_.retrievePrimaryKeys(model) const inputArray = Array.isArray(input) ? input : [input] @@ -352,7 +359,9 @@ export function MedusaInternalService< } if (!toUpdateData.length) { - return [] + return (shouldReturnArray ? [] : void 0) as + | InferEntityType + | InferEntityType[] } // Manage metadata if needed @@ -372,10 +381,12 @@ export function MedusaInternalService< } }) - return await this[propertyRepositoryName].update( + const entities = await this[propertyRepositoryName].update( toUpdateData, sharedContext ) + + return shouldReturnArray ? entities : entities[0] } delete(idOrSelector: string, sharedContext?: Context): Promise diff --git a/packages/core/utils/src/modules-sdk/medusa-service.ts b/packages/core/utils/src/modules-sdk/medusa-service.ts index bb0b7cea3b..ddf91048af 100644 --- a/packages/core/utils/src/modules-sdk/medusa-service.ts +++ b/packages/core/utils/src/modules-sdk/medusa-service.ts @@ -245,12 +245,7 @@ export function MedusaService< ): Promise { const serviceData = Array.isArray(data) ? data : [data] const service = this.__container__[serviceRegistrationName] - const models = await service.update(serviceData, sharedContext) - const response = models.length - ? Array.isArray(data) - ? models - : models[0] - : [] + const response = await service.update(serviceData, sharedContext) klassPrototype.aggregatedEvents.bind(this)({ action: CommonEvents.UPDATED, diff --git a/packages/modules/auth/src/services/auth-module.ts b/packages/modules/auth/src/services/auth-module.ts index d0af5f5a14..15002e34e2 100644 --- a/packages/modules/auth/src/services/auth-module.ts +++ b/packages/modules/auth/src/services/auth-module.ts @@ -129,7 +129,7 @@ export default class AuthModuleService populate: true, }) - return Array.isArray(data) ? serializedUsers : serializedUsers[0] + return serializedUsers } async register( @@ -206,7 +206,7 @@ export default class AuthModuleService AuthTypes.ProviderIdentityDTO[] >(updatedProviders) - return Array.isArray(data) ? serializedProviders : serializedProviders[0] + return serializedProviders } async updateProvider( diff --git a/packages/modules/customer/src/services/customer-module.ts b/packages/modules/customer/src/services/customer-module.ts index 000f393aec..b80dafc23e 100644 --- a/packages/modules/customer/src/services/customer-module.ts +++ b/packages/modules/customer/src/services/customer-module.ts @@ -218,7 +218,7 @@ export default class CustomerModuleService populate: true, }) - return isString(idsOrSelector) ? serialized[0] : serialized + return serialized } // @ts-expect-error diff --git a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts index 6ef34ea304..824d0a836d 100644 --- a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts +++ b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts @@ -2021,9 +2021,11 @@ export default class FulfillmentModuleService }) } - const result = await this.baseRepository_.serialize(fulfillment) + const result = await this.baseRepository_.serialize( + fulfillment + ) - return Array.isArray(result) ? result[0] : result + return result } async retrieveFulfillmentOptions( diff --git a/packages/modules/inventory/src/services/inventory-module.ts b/packages/modules/inventory/src/services/inventory-module.ts index 26515a2df2..6cbeb5da10 100644 --- a/packages/modules/inventory/src/services/inventory-module.ts +++ b/packages/modules/inventory/src/services/inventory-module.ts @@ -1052,7 +1052,7 @@ export default class InventoryModuleService context ) - return result[0] + return result } @InjectManager() diff --git a/packages/modules/payment/src/services/payment-module.ts b/packages/modules/payment/src/services/payment-module.ts index 25202e32d3..eeb2dfb4f4 100644 --- a/packages/modules/payment/src/services/payment-module.ts +++ b/packages/modules/payment/src/services/payment-module.ts @@ -359,15 +359,13 @@ export default class PaymentModuleService } ) - paymentSession = ( - await this.paymentSessionService_.update( - { - id: paymentSession!.id, - data: { ...input.data, ...providerPaymentSession.data }, - }, - sharedContext - ) - )[0] + paymentSession = await this.paymentSessionService_.update( + { + id: paymentSession!.id, + data: { ...input.data, ...providerPaymentSession.data }, + }, + sharedContext + ) } catch (error) { if (providerPaymentSession) { await this.paymentProviderService_.deleteSession(input.provider_id, { @@ -440,7 +438,7 @@ export default class PaymentModuleService sharedContext ) - return await this.baseRepository_.serialize(updated[0], { populate: true }) + return await this.baseRepository_.serialize(updated, { populate: true }) } @InjectManager() @@ -605,7 +603,7 @@ export default class PaymentModuleService // NOTE: currently there is no update with the provider but maybe data could be updated const result = await this.paymentService_.update(data, sharedContext) - return await this.baseRepository_.serialize(result[0]) + return await this.baseRepository_.serialize(result) } // TODO: This method should return a capture, not a payment diff --git a/packages/modules/product/integration-tests/__tests__/product.ts b/packages/modules/product/integration-tests/__tests__/product.ts index 945dbb6c49..d80a88de62 100644 --- a/packages/modules/product/integration-tests/__tests__/product.ts +++ b/packages/modules/product/integration-tests/__tests__/product.ts @@ -285,6 +285,59 @@ moduleIntegrationTestRunner({ ) }) + it("should update a product and its allowed relations using selector", async () => { + const updateData = [ + { + selector: { + id: productOne.id, + }, + data: { + title: "update test 1", + }, + }, + ] + + const products = await service.update(updateData) + + expect(products.length).toEqual(1) + + let result = await service.retrieve(productOne.id) + let serialized = JSON.parse(JSON.stringify(result)) + + expect(serialized).toEqual( + expect.objectContaining({ + id: productOne.id, + title: "update test 1", + }) + ) + }) + + it("should update a single product and its allowed relations", async () => { + const updateData = { + id: productOne.id, + title: "update test 1", + } + + const product = await service.update(updateData) + + expect(product).toEqual( + expect.objectContaining({ + id: productOne.id, + title: "update test 1", + }) + ) + + let result = await service.retrieve(productOne.id) + let serialized = JSON.parse(JSON.stringify(result)) + + expect(serialized).toEqual( + expect.objectContaining({ + id: productOne.id, + title: "update test 1", + }) + ) + }) + it("should throw an error when id is not present", async () => { let error const updateData = [