diff --git a/.changeset/wet-gorillas-laugh.md b/.changeset/wet-gorillas-laugh.md new file mode 100644 index 0000000000..1c32e016f1 --- /dev/null +++ b/.changeset/wet-gorillas-laugh.md @@ -0,0 +1,6 @@ +--- +"@medusajs/orchestration": patch +"@medusajs/types": patch +--- + +fix(orchestration, types): Improve fieldAlias and prevent infinite loop by validating at development time diff --git a/packages/orchestration/src/joiner/remote-joiner.ts b/packages/orchestration/src/joiner/remote-joiner.ts index acf2f250e0..2838a29b87 100644 --- a/packages/orchestration/src/joiner/remote-joiner.ts +++ b/packages/orchestration/src/joiner/remote-joiner.ts @@ -128,15 +128,18 @@ export class RemoteJoiner { } private buildReferences(serviceConfigs: ModuleJoinerConfig[]) { - const expandedRelationships: Map = new Map() + const expandedRelationships: Map< + string, + { fieldAlias; relationships: JoinerRelationship[] } + > = new Map() for (const service of serviceConfigs) { if (this.serviceConfigCache.has(service.serviceName!)) { throw new Error(`Service "${service.serviceName}" is already defined.`) } - if (!service.relationships) { - service.relationships = [] - } + service.fieldAlias ??= {} + service.relationships ??= [] + service.extends ??= [] // add aliases const isReadOnlyDefinition = @@ -175,26 +178,47 @@ export class RemoteJoiner { this.cacheServiceConfig(serviceConfigs, service.serviceName) } - if (!service.extends) { - continue - } - for (const extend of service.extends) { if (!expandedRelationships.has(extend.serviceName)) { - expandedRelationships.set(extend.serviceName, []) + expandedRelationships.set(extend.serviceName, { + fieldAlias: {}, + relationships: [], + }) } - expandedRelationships.get(extend.serviceName)!.push(extend.relationship) + const service_ = expandedRelationships.get(extend.serviceName)! + service_.relationships.push(extend.relationship) + Object.assign(service_.fieldAlias ?? {}, extend.fieldAlias) } } - for (const [serviceName, relationships] of expandedRelationships) { + for (const [ + serviceName, + { fieldAlias, relationships }, + ] of expandedRelationships) { if (!this.serviceConfigCache.has(serviceName)) { throw new Error(`Service "${serviceName}" was not found`) } - const service = this.serviceConfigCache.get(serviceName) - service!.relationships?.push(...relationships) + const service_ = this.serviceConfigCache.get(serviceName)! + service_.relationships?.push(...relationships) + Object.assign(service_.fieldAlias!, fieldAlias ?? {}) + + if (Object.keys(service_.fieldAlias!).length) { + const conflictAliases = service_.relationships!.filter( + (relationship) => { + return fieldAlias[relationship.alias] + } + ) + + if (conflictAliases.length) { + throw new Error( + `Conflict configuration for service "${serviceName}". The following aliases are already defined as relationships: ${conflictAliases + .map((relationship) => relationship.alias) + .join(", ")}` + ) + } + } } return serviceConfigs diff --git a/packages/types/src/modules-sdk/index.ts b/packages/types/src/modules-sdk/index.ts index f3e2b62b2e..7734f3ae0e 100644 --- a/packages/types/src/modules-sdk/index.ts +++ b/packages/types/src/modules-sdk/index.ts @@ -124,6 +124,14 @@ export type ModuleJoinerConfig = Omit< relationships?: ModuleJoinerRelationship[] extends?: { serviceName: string + fieldAlias?: Record< + string, + | string + | { + path: string + forwardArgumentsOnPath: string[] + } + > // alias for deeper nested relationships (e.g. { 'price': 'prices.calculated_price_set.amount' }) relationship: ModuleJoinerRelationship }[] serviceName?: string