Files
medusa-store/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx
Shahed Nasser 4fe28f5a95 chore: reorganize docs apps (#7228)
* reorganize docs apps

* add README

* fix directory

* add condition for old docs
2024-05-03 17:36:38 +03:00

240 lines
7.6 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 in queryable modules.
## What is a Relationship in a Queryable Module?
A queryable module can have a relationship to another queryable 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 using the remote query.
<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="Tip">
The next chapter provides a detailed example of implementing a relationship between two modules. This section gives the general steps to creating the relationship.
</Note>
Consider youre creating a data model that adds custom fields associated with a product:
```ts title="src/modules/hello/models/another-custom.ts" highlights={[["13"]]}
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.
To create a relationship to the `product` data model in the Product Module, add the following to the joiner configuration of your module:
export const relationshipsHighlight = [
["10", "serviceName", "The name of the module that this relationship is referencing."],
["11", "alias", "The alias of the data model youre referencing in the other module."],
["12", "primaryKey", "The name of the field youre referencing in the other modules data model."],
["13", "foreignKey", "The name of the field in your data models referencing the other modules model."],
]
```ts title="src/modules/hello/joiner-config.ts" highlights={relationshipsHighlight}
// other imports...
import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import { CustomProductData } from "./models/custom-product-data"
const joinerConfig: ModuleJoinerConfig = {
// ...
relationships: [
{
serviceName: Modules.PRODUCT,
alias: "product",
primaryKey: "id",
foreignKey: "product_id",
},
],
}
export default joinerConfig
```
You pass a new property `relationships` to the `joinerConfig`. This propertys value is an array of relationship definitions from your module to other modules.
Each relationship definition object accepts the following properties:
<TypeList types={[
{
name: "serviceName",
type: "`string`",
optional: false,
description: "The name of the module (as added in `medusa-config.js`) that this relationship is referencing. If youre 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. The alias is defined in the joiner configuration of that module, similar to your module."
},
{
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 referencing the other modules model."
}
]} />
So, the above example creates a relationship to the `Product` data model of the Product Module, which has the alias `product`. `product_id` fields in your modules data models are considered references to the `id` field of the `Product` data model in the Product Module.
---
## Query Data Across Relationships
The remote query allows you to query data across modules using their relationship without the actual dependency between the modules.
To do that, specify within the `fields` retrieved in the query the referenced data models fields. For example:
```ts highlights={[["3", '"product.title"', "Retrieve the referenced product's title."]]}
const query = remoteQueryObjectFromString({
entryPoint: "another_custom",
fields: ["id", "custom_field", "product.title"],
})
const result = await remoteQuery(query)
```
Use `alias`'s value in the relationship definition to reference the other modules data model. To specify its fields, use dot notation.
So, in the example above, the referenced products title is retrieved along with the ID under the `product` property of each record object in the result.
---
## 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/joiner-config.ts" highlights={[["10", "methodSuffix", "The suffix of the referenced data model's methods."]]}
const joinerConfig: ModuleJoinerConfig = {
// ...
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.
---
## Inverse Relationship
If youre creating a relationship between two custom modules, you can define the relationship on the referenced side using the `extends` property of the joiner configuration.
For example:
<CodeTabs groupId="inverse-relation">
<CodeTab label="Hello Module" value="hello-module">
```ts title="src/modules/hello/joiner-config.ts"
// Hello module
const joinerConfig: ModuleJoinerConfig = {
// ...
relationships: [
{
serviceName: "anotherHelloModuleService",
alias: "another_custom",
primaryKey: "id",
foreignKey: "another_custom_id",
},
],
}
```
</CodeTab>
<CodeTab label="Another Hello Module" value="another-hello-module">
```ts title="src/modules/another-hello/joiner-config.ts" highlights={[["6", "serviceName", "The name of the module this relationship was originally created in."], ["7", "relationship", "The relationship object as defined in the referencing module."]]}
// Another hello module
const joinerConfig: ModuleJoinerConfig = {
// ...
extends: [
{
serviceName: "helloModuleService",
relationship: {
serviceName: "anotherHelloModuleService",
alias: "another_custom",
primaryKey: "id",
foreignKey: "another_custom_id",
},
},
],
}
```
</CodeTab>
</CodeTabs>
The `extends` propertys value is an array of objects having the following properties:
1. `serviceName`: The name of the module this relationship was originally created in.
2. `relationship`: The relationship object as defined in the referencing module.