Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(utils): defineReadOnlyLink #9459

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CurrencyModule from "@medusajs/currency"
import { MedusaModule } from "@medusajs/modules-sdk"
import ProductModule from "@medusajs/product"
import RegionModule from "@medusajs/region"
import { defineLink } from "@medusajs/utils"
import { defineLink, defineReadOnlyLink, Modules } from "@medusajs/utils"

jest.setTimeout(50000)

Expand Down Expand Up @@ -400,5 +400,217 @@ medusaIntegrationTestRunner({
})
})
})

it("should define read-only links", async () => {
defineReadOnlyLink(
CurrencyModule.linkable.currency,
RegionModule.linkable.region
)
defineReadOnlyLink(
{
linkable: CurrencyModule.linkable.currency,
field: "my_custom_currency_code",
},
RegionModule.linkable.region
)
defineReadOnlyLink(
{
linkable: CurrencyModule.linkable.currency,
field: "my_custom_id",
},
{
module: Modules.REGION,
entity: "Country",
field: "region_country_code_id",
alias: "my_custom_region",
}
)
defineReadOnlyLink(
{
linkable: CurrencyModule.linkable.currency,
field: "custom_currency_id",
},
{
linkable: CurrencyModule.linkable.currency,
field: "country_code",
alias: "custom_region_code",
}
)
defineReadOnlyLink(
{
linkable: CurrencyModule.linkable.currency,
field: "my_custom_id",
},
{
module: Modules.REGION,
entity: "Country",
field: "region_country_code_id",
alias: "my_custom_region",
}
)
defineReadOnlyLink(
{
module: Modules.REGION,
entity: "Country",
field: "country_code",
},
{
module: "Weather",
field: "country_code_id",
alias: "weather_forecast",
isList: true,
}
)
defineReadOnlyLink(
{
module: Modules.PRODUCT,
field: "season_id",
},
{
module: "Weather",
field: "season_id",
alias: "season_forecast",
}
)

const linkDefinition = MedusaModule.getCustomLinks()
.map((linkDefinition: any) => {
const mods = MedusaModule.getAllJoinerConfigs()
mods.push({
serviceName: "Weather",
primaryKeys: ["id"],
})
return linkDefinition(mods)
})
.filter((a) => a.isReadOnlyLink)

const expectReadOnlyLinks = [
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "currency",
entity: "Currency",
relationship: expect.objectContaining({
serviceName: "region",
entity: "Region",
primaryKey: "id",
foreignKey: "currency",
alias: "region",
isList: false,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "currency",
entity: "Currency",
relationship: expect.objectContaining({
serviceName: "region",
entity: "Region",
primaryKey: "id",
foreignKey: "my_custom_currency_code",
alias: "region",
isList: false,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "currency",
entity: "Currency",
relationship: expect.objectContaining({
serviceName: "region",
entity: "Country",
primaryKey: "region_country_code_id",
foreignKey: "my_custom_id",
alias: "my_custom_region",
isList: false,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "currency",
entity: "Currency",
relationship: expect.objectContaining({
serviceName: "currency",
entity: "Currency",
primaryKey: "code",
foreignKey: "custom_currency_id",
alias: "custom_region_code",
isList: false,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "currency",
entity: "Currency",
relationship: expect.objectContaining({
serviceName: "region",
entity: "Country",
primaryKey: "region_country_code_id",
foreignKey: "my_custom_id",
alias: "my_custom_region",
isList: false,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "region",
entity: "Country",
relationship: expect.objectContaining({
serviceName: "Weather",
primaryKey: "country_code_id",
foreignKey: "country_code",
alias: "weather_forecast",
isList: true,
}),
},
],
}),
expect.objectContaining({
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: "product",
relationship: expect.objectContaining({
serviceName: "Weather",
primaryKey: "season_id",
foreignKey: "season_id",
alias: "season_forecast",
isList: false,
}),
},
],
}),
]

expect(linkDefinition).toEqual(expectReadOnlyLinks)
})
},
})
49 changes: 37 additions & 12 deletions packages/core/orchestration/src/joiner/remote-joiner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,20 @@ export class RemoteJoiner {
}

private buildReferences(serviceConfigs: ModuleJoinerConfig[]) {
const expandedRelationships: Map<
string,
const expandedRelationships: WeakMap<
{
serviceName: string
entity?: string
},
{
fieldAlias
relationships: Map<string, JoinerRelationship | JoinerRelationship[]>
}
> = new Map()
> = new WeakMap()
const expandedRelationshipsSet = new Set<{
serviceName: string
entity?: string
}>()

for (const service of serviceConfigs) {
const service_ = service as Omit<ModuleJoinerConfig, "relationships"> & {
Expand Down Expand Up @@ -283,14 +290,20 @@ export class RemoteJoiner {
}

for (const extend of service_.extends) {
if (!expandedRelationships.has(extend.serviceName)) {
expandedRelationships.set(extend.serviceName, {
const extendKey = {
serviceName: extend.serviceName,
entity: extend.entity,
}

if (!expandedRelationships.has(extendKey)) {
expandedRelationships.set(extendKey, {
fieldAlias: {},
relationships: new Map(),
})
expandedRelationshipsSet.add(extendKey)
}

const service_ = expandedRelationships.get(extend.serviceName)!
const service_ = expandedRelationships.get(extendKey)!

const aliasName = extend.relationship.alias
const rel = extend.relationship
Expand All @@ -309,15 +322,27 @@ export class RemoteJoiner {
}
}

for (const [
serviceName,
{ fieldAlias, relationships },
] of expandedRelationships) {
if (!this.serviceConfigCache.has(serviceName)) {
for (const expandRelKey of expandedRelationshipsSet) {
const { serviceName, entity } = expandRelKey

const { fieldAlias, relationships } =
expandedRelationships.get(expandRelKey)!

const service_ = this.getServiceConfig({
serviceName,
entity,
})

if (!service_) {
if (entity) {
throw new Error(
`Entity "${entity}" was not found for service "${serviceName}"`
)
}

throw new Error(`Service "${serviceName}" was not found`)
}

const service_ = this.serviceConfigCache.get(serviceName)!
relationships.forEach((relationship, alias) => {
const rel = relationship as JoinerRelationship
if (service_.relationships?.has(alias)) {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/types/src/joiner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ export interface JoinerServiceConfig {
| string
| {
path: string
forwardArgumentsOnPath: string[]
forwardArgumentsOnPath?: string[]
isList?: boolean
}
>
primaryKeys: string[]
relationships?: JoinerRelationship[]
extends?: {
serviceName: string
entity?: string
relationship: JoinerRelationship
}[]
/**
Expand Down
1 change: 1 addition & 0 deletions packages/core/types/src/modules-sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export type ModuleJoinerConfig = Omit<
relationships?: ModuleJoinerRelationship[]
extends?: {
serviceName: string
entity?: string
fieldAlias?: Record<
string,
| string
Expand Down
Loading
Loading