Files
medusa-store/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx
Shahed Nasser 728c5ee53c docs: preparations for preview (#7267)
* configured base paths + added development banner

* fix typelist site url

* added navbar and sidebar badges

* configure algolia filters

* remove AI assistant

* remove unused imports

* change navbar text and badge

* lint fixes

* fix build error

* add to api reference rewrites

* fix build error

* fix build errors in user-guide

* fix feedback component

* add parent title to pagination

* added breadcrumbs component

* remove user-guide links

* resolve todos

* fix details about authentication

* change documentation title

* lint content
2024-05-13 11:32:52 +03:00

318 lines
9.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { TypeList, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `${pageNumber} Module Relationships`,
}
# {metadata.title}
In this document, youll learn about creating relationships between modules.
## What is a Module Relationship?
A module can have a relationship to another module in the form of a reference.
The Medusa application resolves these relationships while maintaining isolation between the modules and allowing you to retrieve data across them.
<Note title="Use module relationships when" type="success">
- You want to build relationships between the data models of modules.
- You want to assoaciate more fields with the data model of another module.
</Note>
<Note title="Don't use module relationships if" type="error">
- Youre building relationships between data models in the same module. Use foreign keys instead.
</Note>
---
## How to Create a Module Relationship?
<Note title="Steps Summary">
1. Define a `__joinerConfig` method in the module's main service.
2. Configure module to be queryable.
</Note>
Consider youre creating a data model that adds custom fields associated with a product:
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["19"]]}
import { generateEntityId } from "@medusajs/utils"
import {
BeforeCreate,
Entity,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
@Entity()
export class CustomProductData {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text" })
custom_field: string
@Property({ columnType: "text", nullable: true })
product_id?: string
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "cpd")
}
@OnInit()
OnInit() {
this.id = generateEntityId(this.id, "cpd")
}
}
```
The `CustomProductData` data model has a `product_id` field to reference the product it adds custom fields for.
<Note title="Tip">
When you add a new data model, make sure to:
- [Create a migration for it.](../../../basics/data-models/page.mdx#create-a-migration)
- [Add it to the second parameter of the main service's factory function.](../service-factory/page.mdx#abstractModuleServiceFactory-parameters)
- Add it to the [container](../container/page.mdx) and [connection](../connection-loader/page.mdx) loaders.
</Note>
### 1. Define `__joinerConfig` Method
To create a relationship to the `product` data model of the Product Module, create a public `__joinerConfig` method in your main module's service:
export const relationshipsHighlight = [
["39", "serviceName", "The name of the module that this relationship is referencing."],
["40", "alias", "The alias of the data model youre referencing in the other module."],
["41", "primaryKey", "The name of the field youre referencing in the other modules data model."],
["42", "foreignKey", "The name of the field in your data models referencing the other modules model."],
]
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight}
// other imports...
import { MyCustom } from "./models/custom-product-data"
import { CustomProductData } from "./models/custom-product-data"
import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
// ...
__joinerConfig(): ModuleJoinerConfig {
return {
serviceName: "helloModuleService",
primaryKeys: ["id"],
alias: [
{
name: ["my_custom"],
args: {
entity: MyCustom.name,
},
},
{
name: ["custom_product_data"],
args: {
entity: CustomProductData.name,
// Only needed if data model isn't main data model
// of service
methodSuffix: "CustomProductDatas",
},
},
],
relationships: [
{
serviceName: Modules.PRODUCT,
alias: "product",
primaryKey: "id",
foreignKey: "product_id",
},
],
}
}
// ...
}
```
This creates a relationship to the `Product` data model of the Product Module using the alias `product`. The `product_id` fields in your data models are considered references to the `id` field of the `Product` data model.
#### `__joinerConfig` Return Type
<TypeList types={[
{
name: "serviceName",
type: "`string`",
optional: false,
description: "The name of your module (as added in `medusa-config.js`)."
},
{
name: "primaryKeys",
type: "`string[]`",
optional: false,
description: "The primary key field names used in your module's data models.",
},
{
name: "alias",
type: "`object[]`",
description: "The alias definitions for each data model in your module. This allows other modules to reference your module's data models in relationships.",
children: [
{
name: "name",
type: "`string[]`",
description: "The alias names of a data model used later when fetching or referencing the data model."
},
{
name: "args",
type: "`object`",
description: "The alias's arguments.",
children: [
{
name: "entity",
type: "string",
description: "The name of the data model this alias is defined for."
},
{
name: "methodSuffix",
type: "string",
description: "The plural name of the data model. This is only required if the data model isn't the main data model of the module's service."
}
]
}
]
},
{
name: "relationships",
type: "`object[]`",
description: "Your module's relationships to other modules.",
children: [
{
name: "serviceName",
type: "`string`",
optional: false,
description: "The name of the module (as added in `medusa-config.js`) that this relationship is referencing. When referencing a Medusa commerce module, use the `Modules` enum imported from `@medusajs/modules-sdk`."
},
{
name: "alias",
type: "`string`",
optional: false,
description: "The alias of the data model youre referencing in the other module. You can find it in the `__joinerConfig` method of the other module's service."
},
{
name: "primaryKey",
type: "`string`",
optional: false,
description: "The name of the field youre referencing in the other modules data model."
},
{
name: "foreignKey",
type: "`string`",
optional: false,
description: "The name of the field in your data models that references the other modules data model."
}
]
}
]} sectionTitle="Define __joinerConfig Method" />
### 2. Adjust Module Configuration
To use relationships in a module, adjust its configuration object passed to the `modules` object in `medusa-config.js`:
export const configHighlights = [
["7", "isQueryable", "Enable this property to use relationships in a module."]
]
```js title="medusa-config.js" highlights={configHighlights}
const modules = {
helloModuleService: {
// ...
definition: {
key: "helloModuleService",
registrationName: "helloModuleService",
isQueryable: true,
},
},
// ...
}
```
Enabling the `isQueryable` property is required to use relationships in a module.
The `definition` propertys value is an object that accepts the following properties, among others:
<TypeList types={[
{
name: "key",
type: "`string`",
optional: false,
description: "The module's key in the `modules` object."
},
{
name: "registrationName",
type: "`string`",
optional: false,
description: "The name that the main service is registered under in the Medusa container. Its recommended to be the same as `key`'s value.",
},
{
name: "isQueryable",
type: "`boolean`",
description: "Whether the module is queryable. This must be enabled to allow a module to have relationships."
}
]} sectionTitle="Adjust Module Configuration" />
---
## Reference Inner Data Models
If the data model youre referencing isnt the main data model of the main module service, pass to the relationship definition the `args` property:
```ts title="src/modules/hello/service.ts" highlights={[["20", "methodSuffix", "The suffix of the referenced data model's methods."]]}
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
// ...
__joinerConfig(): ModuleJoinerConfig {
return {
// ...
relationships: [
{
serviceName: Modules.PRODUCT,
primaryKey: "id",
foreignKey: "variant_id",
alias: "variant",
args: {
methodSuffix: "Variants",
},
},
],
}
}
}
```
The `args` propertys value is an object accepting a `methodSuffix` property. The `methodSuffix` propertys value is the plural name of the data model.
---
## Querying Module Relationships
The next chapter explains how to query data across module relationships.