From d3e725a9073825889c78e590fac7d5af15d9ccfc Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Wed, 2 Apr 2025 14:16:51 +0530 Subject: [PATCH] feat: add `hasMany` flag to enforce in app link uniqueness (#12039) * feat: add createMultiple flag to enforce inApp link uniqueness * changes * mocks * default * many to many --------- Co-authored-by: Carlos R. L. Rodrigues --- .../link-modules/define-link.spec.ts | 246 ++++++++++++++++-- .../src/__mocks__/inventory-module.ts | 1 + .../inventory-stock-location-link.ts | 1 + .../src/__mocks__/product-inventory-link.ts | 1 + .../src/__mocks__/product-module.ts | 1 + .../src/__mocks__/stock-location-module.ts | 1 + packages/core/modules-sdk/src/link.ts | 84 +++--- packages/core/types/src/modules-sdk/index.ts | 7 +- .../core/utils/src/modules-sdk/define-link.ts | 20 +- .../src/definitions/cart-promotion.ts | 2 + .../definitions/customer-account-holder.ts | 1 + .../fulfillment-provider-location.ts | 2 + .../definitions/fulfillment-set-location.ts | 1 + .../order-claim-payment-collection.ts | 1 + .../order-exchange-payment-collection.ts | 1 + .../src/definitions/order-fulfillment.ts | 1 + .../definitions/order-payment-collection.ts | 1 + .../src/definitions/order-promotion.ts | 2 + .../definitions/order-return-fulfillment.ts | 1 + .../src/definitions/product-sales-channel.ts | 2 + .../definitions/product-shipping-profile.ts | 1 + .../product-variant-inventory-item.ts | 2 + .../publishable-api-key-sales-channel.ts | 2 + .../definitions/region-payment-provider.ts | 2 + .../src/definitions/sales-channel-location.ts | 2 + 25 files changed, 316 insertions(+), 70 deletions(-) diff --git a/integration-tests/modules/__tests__/link-modules/define-link.spec.ts b/integration-tests/modules/__tests__/link-modules/define-link.spec.ts index 045fb18dd4..83cfa8ff64 100644 --- a/integration-tests/modules/__tests__/link-modules/define-link.spec.ts +++ b/integration-tests/modules/__tests__/link-modules/define-link.spec.ts @@ -46,7 +46,7 @@ medusaIntegrationTestRunner({ entity: "Currency", primaryKey: "code", foreignKey: "currency_code", - isList: true, + hasMany: false, alias: "currency", args: { methodSuffix: "Currencies", @@ -59,7 +59,7 @@ medusaIntegrationTestRunner({ primaryKey: "id", foreignKey: "region_id", alias: "region", - isList: false, + hasMany: false, args: { methodSuffix: "Regions", }, @@ -90,9 +90,9 @@ medusaIntegrationTestRunner({ serviceName: "region", entity: "Region", fieldAlias: { - currencies: { + currency: { path: "currency_link.currency", - isList: true, + isList: false, forwardArgumentsOnPath: ["currency_link.currency"], }, }, @@ -102,7 +102,7 @@ medusaIntegrationTestRunner({ primaryKey: "region_id", foreignKey: "id", alias: "currency_link", - isList: true, + isList: false, }, }, ], @@ -147,7 +147,7 @@ medusaIntegrationTestRunner({ entity: "ProductVariant", primaryKey: "id", foreignKey: "product_variant_id", - isList: true, + hasMany: false, alias: "product_variant", args: { methodSuffix: "ProductVariants", @@ -159,7 +159,7 @@ medusaIntegrationTestRunner({ entity: "Region", primaryKey: "id", foreignKey: "region_id", - isList: false, + hasMany: false, alias: "region", args: { methodSuffix: "Regions", @@ -191,9 +191,9 @@ medusaIntegrationTestRunner({ serviceName: "region", entity: "Region", fieldAlias: { - product_variants: { + product_variant: { path: "product_variant_link.product_variant", - isList: true, + isList: false, forwardArgumentsOnPath: [ "product_variant_link.product_variant", ], @@ -205,7 +205,7 @@ medusaIntegrationTestRunner({ primaryKey: "region_id", foreignKey: "id", alias: "product_variant_link", - isList: true, + isList: false, }, }, ], @@ -253,7 +253,7 @@ medusaIntegrationTestRunner({ entity: "Currency", primaryKey: "code", foreignKey: "currency_code", - isList: true, + hasMany: false, alias: "currency", args: { methodSuffix: "Currencies", @@ -265,7 +265,7 @@ medusaIntegrationTestRunner({ entity: "Region", primaryKey: "id", foreignKey: "region_id", - isList: false, + hasMany: false, alias: "region", args: { methodSuffix: "Regions", @@ -297,9 +297,9 @@ medusaIntegrationTestRunner({ serviceName: "region", entity: "Region", fieldAlias: { - currencies: { + currency: { path: "currency_link.currency", - isList: true, + isList: false, forwardArgumentsOnPath: ["currency_link.currency"], }, }, @@ -309,7 +309,7 @@ medusaIntegrationTestRunner({ primaryKey: "region_id", foreignKey: "id", alias: "currency_link", - isList: true, + isList: false, }, }, ], @@ -353,7 +353,7 @@ medusaIntegrationTestRunner({ entity: "Currency", primaryKey: "code", foreignKey: "currency_code", - isList: true, + hasMany: false, alias: "currency", args: { methodSuffix: "Currencies", @@ -365,7 +365,113 @@ medusaIntegrationTestRunner({ entity: "Region", primaryKey: "id", foreignKey: "region_id", - isList: true, + hasMany: true, + alias: "region", + args: { + methodSuffix: "Regions", + }, + deleteCascade: false, + }, + ], + extends: [ + { + serviceName: "currency", + entity: "Currency", + fieldAlias: { + regions: { + path: "region_link.region", + isList: true, + forwardArgumentsOnPath: ["region_link.region"], + }, + }, + relationship: { + serviceName: "CurrencyCurrencyRegionRegionLink", + entity: "LinkCurrencyCurrencyRegionRegion", + primaryKey: "currency_code", + foreignKey: "code", + alias: "region_link", + isList: true, + }, + }, + { + serviceName: "region", + entity: "Region", + fieldAlias: { + currency: { + path: "currency_link.currency", + isList: false, + forwardArgumentsOnPath: ["currency_link.currency"], + }, + }, + relationship: { + serviceName: "CurrencyCurrencyRegionRegionLink", + entity: "LinkCurrencyCurrencyRegionRegion", + primaryKey: "region_id", + foreignKey: "id", + alias: "currency_link", + isList: false, + }, + }, + ], + }) + }) + + it("should generate a proper link with both sides using explicit isList=true", async () => { + const currencyLinks = CurrencyModule.linkable + const regionLinks = RegionModule.linkable + + const link = defineLink( + { + linkable: currencyLinks.currency, + isList: true, + }, + { + linkable: regionLinks.region, + isList: true, + } + ) + + const linkDefinition = MedusaModule.getCustomLinks() + .map((linkDefinition: any) => { + const definition = linkDefinition( + MedusaModule.getAllJoinerConfigs() + ) + return definition.serviceName === link.serviceName && definition + }) + .filter(Boolean)[0] + + expect(link.serviceName).toEqual("CurrencyCurrencyRegionRegionLink") + expect(linkDefinition).toEqual({ + serviceName: "CurrencyCurrencyRegionRegionLink", + isLink: true, + alias: [ + { + name: ["currency_region"], + args: { + entity: "LinkCurrencyCurrencyRegionRegion", + }, + }, + ], + primaryKeys: ["id", "currency_code", "region_id"], + relationships: [ + { + serviceName: "currency", + entity: "Currency", + primaryKey: "code", + foreignKey: "currency_code", + hasMany: true, + alias: "currency", + args: { + methodSuffix: "Currencies", + }, + deleteCascade: false, + }, + { + serviceName: "region", + entity: "Region", + primaryKey: "id", + foreignKey: "region_id", + hasMany: true, alias: "region", args: { methodSuffix: "Regions", @@ -415,6 +521,112 @@ medusaIntegrationTestRunner({ ], }) }) + + it("should generate a proper link with both sides using explicit isList=false", async () => { + const currencyLinks = CurrencyModule.linkable + const regionLinks = RegionModule.linkable + + const link = defineLink( + { + linkable: currencyLinks.currency, + isList: false, + }, + { + linkable: regionLinks.region, + isList: false, + } + ) + + const linkDefinition = MedusaModule.getCustomLinks() + .map((linkDefinition: any) => { + const definition = linkDefinition( + MedusaModule.getAllJoinerConfigs() + ) + return definition.serviceName === link.serviceName && definition + }) + .filter(Boolean)[0] + + expect(link.serviceName).toEqual("CurrencyCurrencyRegionRegionLink") + expect(linkDefinition).toEqual({ + serviceName: "CurrencyCurrencyRegionRegionLink", + isLink: true, + alias: [ + { + name: ["currency_region"], + args: { + entity: "LinkCurrencyCurrencyRegionRegion", + }, + }, + ], + primaryKeys: ["id", "currency_code", "region_id"], + relationships: [ + { + serviceName: "currency", + entity: "Currency", + primaryKey: "code", + foreignKey: "currency_code", + hasMany: false, + alias: "currency", + args: { + methodSuffix: "Currencies", + }, + deleteCascade: false, + }, + { + serviceName: "region", + entity: "Region", + primaryKey: "id", + foreignKey: "region_id", + hasMany: false, + alias: "region", + args: { + methodSuffix: "Regions", + }, + deleteCascade: false, + }, + ], + extends: [ + { + serviceName: "currency", + entity: "Currency", + fieldAlias: { + region: { + path: "region_link.region", + isList: false, + forwardArgumentsOnPath: ["region_link.region"], + }, + }, + relationship: { + serviceName: "CurrencyCurrencyRegionRegionLink", + entity: "LinkCurrencyCurrencyRegionRegion", + primaryKey: "currency_code", + foreignKey: "code", + alias: "region_link", + isList: false, + }, + }, + { + serviceName: "region", + entity: "Region", + fieldAlias: { + currency: { + path: "currency_link.currency", + isList: false, + forwardArgumentsOnPath: ["currency_link.currency"], + }, + }, + relationship: { + serviceName: "CurrencyCurrencyRegionRegionLink", + entity: "LinkCurrencyCurrencyRegionRegion", + primaryKey: "region_id", + foreignKey: "id", + alias: "currency_link", + isList: false, + }, + }, + ], + }) + }) }) }, }) diff --git a/packages/core/modules-sdk/src/__mocks__/inventory-module.ts b/packages/core/modules-sdk/src/__mocks__/inventory-module.ts index 92831def50..e073c36cda 100644 --- a/packages/core/modules-sdk/src/__mocks__/inventory-module.ts +++ b/packages/core/modules-sdk/src/__mocks__/inventory-module.ts @@ -21,5 +21,6 @@ export const InventoryModule = { }, }, + list: jest.fn(async () => []), softDelete: jest.fn(() => {}), } diff --git a/packages/core/modules-sdk/src/__mocks__/inventory-stock-location-link.ts b/packages/core/modules-sdk/src/__mocks__/inventory-stock-location-link.ts index e45ba450f5..676fa290fe 100644 --- a/packages/core/modules-sdk/src/__mocks__/inventory-stock-location-link.ts +++ b/packages/core/modules-sdk/src/__mocks__/inventory-stock-location-link.ts @@ -65,5 +65,6 @@ export const InventoryStockLocationLink = { foreignKeyData?: string ) => {} ), + list: jest.fn(async () => []), softDelete: jest.fn(() => {}), } diff --git a/packages/core/modules-sdk/src/__mocks__/product-inventory-link.ts b/packages/core/modules-sdk/src/__mocks__/product-inventory-link.ts index 03f385d021..71d7a912e1 100644 --- a/packages/core/modules-sdk/src/__mocks__/product-inventory-link.ts +++ b/packages/core/modules-sdk/src/__mocks__/product-inventory-link.ts @@ -71,5 +71,6 @@ export const ProductInventoryLinkModule = { foreignKeyData?: string ) => {} ), + list: jest.fn(async () => []), softDelete: jest.fn(() => {}), } diff --git a/packages/core/modules-sdk/src/__mocks__/product-module.ts b/packages/core/modules-sdk/src/__mocks__/product-module.ts index 1a40b37e23..3ce5ac1b98 100644 --- a/packages/core/modules-sdk/src/__mocks__/product-module.ts +++ b/packages/core/modules-sdk/src/__mocks__/product-module.ts @@ -18,5 +18,6 @@ export const ProductModule = { alias: [], }, + list: jest.fn(async () => []), softDelete: jest.fn(() => {}), } diff --git a/packages/core/modules-sdk/src/__mocks__/stock-location-module.ts b/packages/core/modules-sdk/src/__mocks__/stock-location-module.ts index 045768a9f3..d4ae03b769 100644 --- a/packages/core/modules-sdk/src/__mocks__/stock-location-module.ts +++ b/packages/core/modules-sdk/src/__mocks__/stock-location-module.ts @@ -18,5 +18,6 @@ export const StockLocationModule = { alias: [], }, + list: jest.fn(async () => []), softDelete: jest.fn(() => {}), } diff --git a/packages/core/modules-sdk/src/link.ts b/packages/core/modules-sdk/src/link.ts index 4165db8a37..480e00d6e9 100644 --- a/packages/core/modules-sdk/src/link.ts +++ b/packages/core/modules-sdk/src/link.ts @@ -389,7 +389,7 @@ export class Link { { linksToCreate: [string | string[], string, Record?][] linksToValidateForUniqueness: { - filters: { [key: string]: string }[] + filters: { [key: string]: any }[] services: string[] } } @@ -418,55 +418,51 @@ export class Link { */ linksToValidateForUniqueness: { filters: [], - services: [], + services: relationships?.map((r) => r.serviceName) ?? [], }, }) } - relationships?.forEach((relationship) => { - const linksToValidateForUniqueness = serviceLinks.get( - service.__definition.key - )!.linksToValidateForUniqueness! + /** + * When isList is set on false on the relationship, then it means + * we have a one-to-one or many-to-one relationship with the + * other side and we have limit duplicate entries from other + * entity. For example: + * + * - A brand has a many to one relationship with a product. + * - A product can have only one brand. Aka (brand.isList = false) + * - A brand can have multiple products. Aka (products.isList = true) + * + * A result of this, we have to ensure that a product_id can only appear + * once in the pivot table that is used for tracking "brand<>products" + * relationship. + */ + const linksToValidateForUniqueness = serviceLinks.get( + service.__definition.key + )!.linksToValidateForUniqueness! - linksToValidateForUniqueness.services.push(relationship.serviceName) - - /** - * When isList is set on false on the relationship, then it means - * we have a one-to-one or many-to-one relationship with the - * other side and we have limit duplicate entries from other - * entity. For example: - * - * - A brand has a many to one relationship with a product. - * - A product can have only one brand. Aka (brand.isList = false) - * - A brand can have multiple products. Aka (products.isList = true) - * - * A result of this, we have to ensure that a product_id can only appear - * once in the pivot table that is used for tracking "brand<>products" - * relationship. - */ - if (relationship.isList === false) { - const otherSide = relationships.find( - (other) => other.foreignKey !== relationship.foreignKey - ) - if (!otherSide) { - return - } - - if (moduleBKey === otherSide.foreignKey) { - linksToValidateForUniqueness.filters.push({ - [otherSide.foreignKey]: link[moduleB][moduleBKey], - }) - } else { - primaryKeys.forEach((pk) => { - if (pk === otherSide.foreignKey) { - linksToValidateForUniqueness.filters.push({ - [otherSide.foreignKey]: link[moduleA][pk], - }) - } - }) - } + const modA = relationships?.[0]! + const modB = relationships?.[1]! + if (!modA.hasMany || !modB.hasMany) { + if (!modA.hasMany && !modB.hasMany) { + linksToValidateForUniqueness.filters.push({ + $or: [ + { [modA.foreignKey]: link[moduleA][modA.foreignKey] }, + { [modB.foreignKey]: link[moduleB][modB.foreignKey] }, + ], + }) + } else if (!modA.hasMany) { + linksToValidateForUniqueness.filters.push({ + [modA.foreignKey]: { $ne: link[moduleA][modA.foreignKey] }, + [modB.foreignKey]: link[moduleB][modB.foreignKey], + }) + } else if (!modB.hasMany) { + linksToValidateForUniqueness.filters.push({ + [modB.foreignKey]: { $ne: link[moduleB][modB.foreignKey] }, + [modA.foreignKey]: link[moduleA][modA.foreignKey], + }) } - }) + } const pkValue = primaryKeys.length === 1 diff --git a/packages/core/types/src/modules-sdk/index.ts b/packages/core/types/src/modules-sdk/index.ts index eae2050902..ca533ef85f 100644 --- a/packages/core/types/src/modules-sdk/index.ts +++ b/packages/core/types/src/modules-sdk/index.ts @@ -209,7 +209,7 @@ export type ModuleJoinerConfig = Omit< isList?: boolean } > // alias for deeper nested relationships (e.g. { 'price': 'prices.calculated_price_set.amount' }) - relationship: ModuleJoinerRelationship + relationship: Omit }[] serviceName?: string primaryKeys?: string[] @@ -248,6 +248,11 @@ export declare type ModuleJoinerRelationship = JoinerRelationship & { * If true, the link joiner will cascade deleting the relationship */ deleteCascade?: boolean + /** + * Allow multiple relationships to exist for this + * entity + */ + hasMany?: boolean } export type ModuleExports> = { diff --git a/packages/core/utils/src/modules-sdk/define-link.ts b/packages/core/utils/src/modules-sdk/define-link.ts index 8aadc0b4f8..a79c52afd0 100644 --- a/packages/core/utils/src/modules-sdk/define-link.ts +++ b/packages/core/utils/src/modules-sdk/define-link.ts @@ -85,6 +85,7 @@ type ModuleLinkableKeyConfig = { deleteCascade?: boolean primaryKey: string alias: string + hasMany?: boolean shortcut?: Shortcut | Shortcut[] } @@ -125,8 +126,7 @@ function buildFieldAlias(fieldAliases?: Shortcut | Shortcut[]) { } function prepareServiceConfig( - input: DefineLinkInputSource | DefineReadOnlyLinkInputSource, - defaultOptions?: { isList?: boolean } + input: DefineLinkInputSource | DefineReadOnlyLinkInputSource ) { let serviceConfig = {} as ModuleLinkableKeyConfig @@ -138,7 +138,8 @@ function prepareServiceConfig( alias: source.alias ?? camelToSnakeCase(source.field ?? ""), field: input.field ?? source.field, primaryKey: source.primaryKey, - isList: defaultOptions?.isList ?? false, + isList: false, + hasMany: false, deleteCascade: false, module: source.serviceName, entity: source.entity, @@ -148,12 +149,15 @@ function prepareServiceConfig( ? input.linkable.toJSON() : input.linkable + const hasMany = !!input.isList + serviceConfig = { key: source.linkable, alias: source.alias ?? camelToSnakeCase(source.field ?? ""), field: input.field ?? source.field, primaryKey: source.primaryKey, - isList: input.isList ?? defaultOptions?.isList ?? false, + isList: input.isList ?? false, + hasMany, deleteCascade: input.deleteCascade ?? false, module: source.serviceName, entity: source.entity, @@ -184,8 +188,8 @@ export function defineLink( rightService: DefineLinkInputSource | DefineReadOnlyLinkInputSource, linkServiceOptions?: ExtraOptions | ReadOnlyExtraOptions ): DefineLinkExport { - const serviceAObj = prepareServiceConfig(leftService, { isList: true }) - const serviceBObj = prepareServiceConfig(rightService, { isList: false }) + const serviceAObj = prepareServiceConfig(leftService) + const serviceBObj = prepareServiceConfig(rightService) if (linkServiceOptions?.readOnly) { return defineReadOnlyLink( @@ -374,7 +378,7 @@ ${serviceBObj.module}: { methodSuffix: serviceAMethodSuffix, }, deleteCascade: serviceAObj.deleteCascade, - isList: serviceAObj.isList, + hasMany: serviceAObj.hasMany, }, { serviceName: serviceBObj.module, @@ -386,7 +390,7 @@ ${serviceBObj.module}: { methodSuffix: serviceBMethodSuffix, }, deleteCascade: serviceBObj.deleteCascade, - isList: serviceBObj.isList, + hasMany: serviceBObj.hasMany, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/cart-promotion.ts b/packages/modules/link-modules/src/definitions/cart-promotion.ts index 0f60c52e7f..d6d1164a04 100644 --- a/packages/modules/link-modules/src/definitions/cart-promotion.ts +++ b/packages/modules/link-modules/src/definitions/cart-promotion.ts @@ -25,6 +25,7 @@ export const CartPromotion: ModuleJoinerConfig = { args: { methodSuffix: "Carts", }, + hasMany: true, }, { serviceName: Modules.PROMOTION, @@ -35,6 +36,7 @@ export const CartPromotion: ModuleJoinerConfig = { args: { methodSuffix: "Promotions", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/customer-account-holder.ts b/packages/modules/link-modules/src/definitions/customer-account-holder.ts index 9963e627cf..4858a4a682 100644 --- a/packages/modules/link-modules/src/definitions/customer-account-holder.ts +++ b/packages/modules/link-modules/src/definitions/customer-account-holder.ts @@ -35,6 +35,7 @@ export const CustomerAccountHolder: ModuleJoinerConfig = { args: { methodSuffix: "AccountHolders", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/fulfillment-provider-location.ts b/packages/modules/link-modules/src/definitions/fulfillment-provider-location.ts index 04f05cacb9..a31234acc2 100644 --- a/packages/modules/link-modules/src/definitions/fulfillment-provider-location.ts +++ b/packages/modules/link-modules/src/definitions/fulfillment-provider-location.ts @@ -23,6 +23,7 @@ export const LocationFulfillmentProvider: ModuleJoinerConfig = { foreignKey: "stock_location_id", alias: "location", args: { methodSuffix: "StockLocations" }, + hasMany: true, }, { serviceName: Modules.FULFILLMENT, @@ -31,6 +32,7 @@ export const LocationFulfillmentProvider: ModuleJoinerConfig = { foreignKey: "fulfillment_provider_id", alias: "fulfillment_provider", args: { methodSuffix: "FulfillmentProviders" }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/fulfillment-set-location.ts b/packages/modules/link-modules/src/definitions/fulfillment-set-location.ts index aa954213a2..dbdfc2a9e1 100644 --- a/packages/modules/link-modules/src/definitions/fulfillment-set-location.ts +++ b/packages/modules/link-modules/src/definitions/fulfillment-set-location.ts @@ -36,6 +36,7 @@ export const LocationFulfillmentSet: ModuleJoinerConfig = { methodSuffix: "FulfillmentSets", }, deleteCascade: true, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-claim-payment-collection.ts b/packages/modules/link-modules/src/definitions/order-claim-payment-collection.ts index 8678b429ec..32fb72047e 100644 --- a/packages/modules/link-modules/src/definitions/order-claim-payment-collection.ts +++ b/packages/modules/link-modules/src/definitions/order-claim-payment-collection.ts @@ -38,6 +38,7 @@ export const OrderClaimPaymentCollection: ModuleJoinerConfig = { args: { methodSuffix: "PaymentCollections", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-exchange-payment-collection.ts b/packages/modules/link-modules/src/definitions/order-exchange-payment-collection.ts index 03f944e794..ac0a5b5344 100644 --- a/packages/modules/link-modules/src/definitions/order-exchange-payment-collection.ts +++ b/packages/modules/link-modules/src/definitions/order-exchange-payment-collection.ts @@ -38,6 +38,7 @@ export const OrderExchangePaymentCollection: ModuleJoinerConfig = { args: { methodSuffix: "PaymentCollections", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-fulfillment.ts b/packages/modules/link-modules/src/definitions/order-fulfillment.ts index 97058bacac..3394189603 100644 --- a/packages/modules/link-modules/src/definitions/order-fulfillment.ts +++ b/packages/modules/link-modules/src/definitions/order-fulfillment.ts @@ -35,6 +35,7 @@ export const OrderFulfillment: ModuleJoinerConfig = { args: { methodSuffix: "Fulfillments", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-payment-collection.ts b/packages/modules/link-modules/src/definitions/order-payment-collection.ts index 77682525c9..b719099340 100644 --- a/packages/modules/link-modules/src/definitions/order-payment-collection.ts +++ b/packages/modules/link-modules/src/definitions/order-payment-collection.ts @@ -36,6 +36,7 @@ export const OrderPaymentCollection: ModuleJoinerConfig = { methodSuffix: "PaymentCollections", }, deleteCascade: true, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-promotion.ts b/packages/modules/link-modules/src/definitions/order-promotion.ts index 465286161c..c7987b2c6a 100644 --- a/packages/modules/link-modules/src/definitions/order-promotion.ts +++ b/packages/modules/link-modules/src/definitions/order-promotion.ts @@ -25,6 +25,7 @@ export const OrderPromotion: ModuleJoinerConfig = { args: { methodSuffix: "Orders", }, + hasMany: true, }, { serviceName: Modules.PROMOTION, @@ -35,6 +36,7 @@ export const OrderPromotion: ModuleJoinerConfig = { args: { methodSuffix: "Promotions", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts index 23fa3e3a58..180ee5cd8a 100644 --- a/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts +++ b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts @@ -35,6 +35,7 @@ export const ReturnFulfillment: ModuleJoinerConfig = { args: { methodSuffix: "Fulfillments", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/product-sales-channel.ts b/packages/modules/link-modules/src/definitions/product-sales-channel.ts index 5d0665c9a9..0563c24b1e 100644 --- a/packages/modules/link-modules/src/definitions/product-sales-channel.ts +++ b/packages/modules/link-modules/src/definitions/product-sales-channel.ts @@ -27,6 +27,7 @@ export const ProductSalesChannel: ModuleJoinerConfig = { args: { methodSuffix: "Products", }, + hasMany: true, }, { serviceName: Modules.SALES_CHANNEL, @@ -37,6 +38,7 @@ export const ProductSalesChannel: ModuleJoinerConfig = { args: { methodSuffix: "SalesChannels", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/product-shipping-profile.ts b/packages/modules/link-modules/src/definitions/product-shipping-profile.ts index 63654a6036..bbb23181ee 100644 --- a/packages/modules/link-modules/src/definitions/product-shipping-profile.ts +++ b/packages/modules/link-modules/src/definitions/product-shipping-profile.ts @@ -27,6 +27,7 @@ export const ProductShippingProfile: ModuleJoinerConfig = { args: { methodSuffix: "Products", }, + hasMany: true, }, { serviceName: Modules.FULFILLMENT, diff --git a/packages/modules/link-modules/src/definitions/product-variant-inventory-item.ts b/packages/modules/link-modules/src/definitions/product-variant-inventory-item.ts index 5f5d0bf696..121fc9b121 100644 --- a/packages/modules/link-modules/src/definitions/product-variant-inventory-item.ts +++ b/packages/modules/link-modules/src/definitions/product-variant-inventory-item.ts @@ -34,6 +34,7 @@ export const ProductVariantInventoryItem: ModuleJoinerConfig = { args: { methodSuffix: "ProductVariants", }, + hasMany: true, }, { serviceName: Modules.INVENTORY, @@ -44,6 +45,7 @@ export const ProductVariantInventoryItem: ModuleJoinerConfig = { args: { methodSuffix: "InventoryItems", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/publishable-api-key-sales-channel.ts b/packages/modules/link-modules/src/definitions/publishable-api-key-sales-channel.ts index 84ef51bb96..fff79094ae 100644 --- a/packages/modules/link-modules/src/definitions/publishable-api-key-sales-channel.ts +++ b/packages/modules/link-modules/src/definitions/publishable-api-key-sales-channel.ts @@ -27,6 +27,7 @@ export const PublishableApiKeySalesChannel: ModuleJoinerConfig = { args: { methodSuffix: "ApiKeys", }, + hasMany: true, }, { serviceName: Modules.SALES_CHANNEL, @@ -37,6 +38,7 @@ export const PublishableApiKeySalesChannel: ModuleJoinerConfig = { args: { methodSuffix: "SalesChannels", }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/region-payment-provider.ts b/packages/modules/link-modules/src/definitions/region-payment-provider.ts index e01103ca0a..3fc1762385 100644 --- a/packages/modules/link-modules/src/definitions/region-payment-provider.ts +++ b/packages/modules/link-modules/src/definitions/region-payment-provider.ts @@ -25,6 +25,7 @@ export const RegionPaymentProvider: ModuleJoinerConfig = { args: { methodSuffix: "Regions", }, + hasMany: true, }, { serviceName: Modules.PAYMENT, @@ -33,6 +34,7 @@ export const RegionPaymentProvider: ModuleJoinerConfig = { foreignKey: "payment_provider_id", alias: "payment_provider", args: { methodSuffix: "PaymentProviders" }, + hasMany: true, }, ], extends: [ diff --git a/packages/modules/link-modules/src/definitions/sales-channel-location.ts b/packages/modules/link-modules/src/definitions/sales-channel-location.ts index 45b887bfbf..86156abc50 100644 --- a/packages/modules/link-modules/src/definitions/sales-channel-location.ts +++ b/packages/modules/link-modules/src/definitions/sales-channel-location.ts @@ -25,6 +25,7 @@ export const SalesChannelLocation: ModuleJoinerConfig = { args: { methodSuffix: "SalesChannels", }, + hasMany: true, }, { serviceName: Modules.STOCK_LOCATION, @@ -35,6 +36,7 @@ export const SalesChannelLocation: ModuleJoinerConfig = { args: { methodSuffix: "StockLocations", }, + hasMany: true, }, ], extends: [