docs: general fixes and overall changes (#7258)

* editing halfway

* edited second half

* adjust starter steps

* fix build

* typo fix
This commit is contained in:
Shahed Nasser
2024-05-07 18:00:28 +02:00
committed by GitHub
parent 8db62827ac
commit 327e446974
57 changed files with 872 additions and 1849 deletions
@@ -6,13 +6,13 @@ export const metadata = {
# {metadata.title}
In this document, youll learn about creating relationships in queryable modules.
In this document, youll learn about creating relationships between modules.
## What is a Relationship in a Queryable Module?
## What is a Module Relationship?
A queryable module can have a relationship to another queryable module in the form of a reference.
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 using the remote query.
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">
@@ -31,15 +31,16 @@ The Medusa application resolves these relationships while maintaining isolation
## How to Create a Module Relationship?
<Note title="Tip">
<Note title="Steps Summary">
The next chapter provides a detailed example of implementing a relationship between two modules. This section gives the general steps to creating the relationship.
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/another-custom.ts" highlights={[["13"]]}
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["19"]]}
import { generateEntityId } from "@medusajs/utils"
import {
BeforeCreate,
@@ -74,89 +75,203 @@ export class CustomProductData {
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:
<Note title="Tip">
When you add a new data model, make sure to:
- Create a migration for it.
- Add it to the second parameter of the main service's factory function.
- Add it to the container and connection 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 = [
["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."],
["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/joiner-config.ts" highlights={relationshipsHighlight}
```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"
import { CustomProductData } from "./models/custom-product-data"
const joinerConfig: ModuleJoinerConfig = {
// ...
relationships: [
{
serviceName: Modules.PRODUCT,
alias: "product",
primaryKey: "id",
foreignKey: "product_id",
},
],
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",
},
],
}
}
// ...
}
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.
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.
Each relationship definition object accepts the following properties:
#### `__joinerConfig` Return Type
<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`."
description: "The name of the module (as added in `medusa-config.js`)."
},
{
name: "primaryKeys",
type: "`string[]`",
optional: false,
description: "The primary key field names used in the module's data models.",
},
{
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."
type: "`object[]`",
description: "The alias definitions for each data model in the module. This allows other modules to reference your module's data models in relationships.",
children: [
{
name: "name",
type: "`string[]`",
description: "The alias names used later when fetching or referencing the data in the 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: "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."
name: "relationships",
type: "`object[]`",
description: "The 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. 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. You can find it in the `__joinerConfig` method of the other 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 that references the other modules data model."
}
]
}
]} />
]} sectionTitle="Define __joinerConfig Method" />
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.
### 2. Adjust Module Configuration
---
To use relationships in a module, adjust its configuration object passed to the `modules` object in `medusa-config.js`:
## Query Data Across Relationships
export const configHighlights = [
["7", "isQueryable", "Enable this property to use relationships in a module."]
]
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)
```js title="medusa-config.js" highlights={configHighlights}
const modules = {
helloModuleService: {
// ...
definition: {
key: "helloModuleService",
registrationName: "helloModuleService",
isQueryable: true,
},
},
// ...
}
```
Use `alias`'s value in the relationship definition to reference the other modules data model. To specify its fields, use dot notation.
Enabling the `isQueryable` property is required to use relationships in a module.
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.
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" />
---
@@ -164,76 +279,39 @@ So, in the example above, the referenced products title is retrieved along wi
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",
},
},
],
}
```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.
---
## Inverse Relationship
## Querying Module Relationships
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.
The next chapter explains how to query data across module relationships.