docs: general fixes and improvements (#7918)

* docs improvements and changes

* updated module definition

* modules + dml changes

* fix build

* fix vale error

* fix lint errors

* fixes to stripe docs

* fix condition

* fix condition

* fix module defintion

* fix checkout

* disable UI action

* change oas preview action

* flatten provider module options

* fix lint errors

* add module link docs

* pr comments fixes

* fix vale error

* change node engine version

* links -> linkable

* add note about database name

* small fixes

* link fixes

* fix response code in api reference

* added migrations step
This commit is contained in:
Shahed Nasser
2024-07-04 17:26:03 +03:00
committed by GitHub
parent 32982e708a
commit 964927b597
149 changed files with 1676 additions and 3008 deletions
@@ -42,12 +42,11 @@ export default class HelloModuleService {
// ...
}
```
### Loader
A loader function in a module accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources.
A loader function accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources.
For example:
@@ -64,5 +63,4 @@ export default function helloWorldLoader({
logger.info("[helloWorldLoader]: Hello, World!")
}
```
@@ -4,12 +4,12 @@ export const metadata = {
# {metadata.title}
In this chapter, you'll learn about how modules are isolated, and what that means for your custom development.
In this chapter, you'll learn how modules are isolated, and what that means for your custom development.
<Note title="Summary">
- Modules can't access resources, such as services, from other modules.
- You can use Medusa's tools, explained in the next chapters, to extend modules or implement features across modules.
- You can use Medusa's tools, as explained in the next chapters, to extend a modules' features or implement features across modules.
</Note>
@@ -17,13 +17,13 @@ In this chapter, you'll learn about how modules are isolated, and what that mean
A module is unaware of any resources other than its own, such as services or data models. This means it can't access these resources if they're implemented in another module.
For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to another module's data model.
For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to the Product Module's data models.
---
## Customize and Implement Features Across Modules
## How to Implement Custom Features Across Modules?
In your Medusa application, you want to implement features that span across modules, or you want to extend existing modules to add new features.
In your Medusa application, you want to implement features that span across modules, or you want to extend an existing module's features and customize them for your own use case.
For example, you want to extend the Product Module to add new properties to the `Product` data model.
@@ -1,23 +0,0 @@
export const metadata = {
title: `${pageNumber} Link Modules`,
}
# {metadata.title}
In this chapter, youll learn what a link module is and how to use the remote link in your customizations.
## What is a Link Module?
A link module is a module whose only purpose is to define a relationship between two modules data models. The relationship is represented as a pivot or link table in the database, pointing at the primary keys of each data model.
For example, Medusa has a link module that defines a relationship between the Product and Pricing modules. It links the `ProductVariant` and `PriceSet` data models.
![Diagram showcasing the link module between the Product and Pricing modules](https://res.cloudinary.com/dza7lstvk/image/upload/v1709651569/Medusa%20Resources/product-pricing_vlxsiq.jpg)
Link modules create the relationship between modules while maintaining module isolation. The Medusa application only creates the link tables when both modules are available.
<Note type="soon">
Link modules are currently only available for Medusas commerce modules.
</Note>
@@ -0,0 +1,128 @@
export const metadata = {
title: `${pageNumber} Module Link`,
}
# {metadata.title}
In this chapter, youll learn what a module link is.
<Note type="soon" title="In Development">
Module links are in active development.
</Note>
## What is a Module Link?
A module link forms an association between two data models of different modules, while maintaining module isolation.
You can then retrieve data across the linked modules, and manage their linked records.
---
## Prerequisite: isQueryable Configuration
Before you define a module link, you must enable the `isQueryable` configuration of the module.
For example:
```js
module.exports = defineConfig({
// ...
modules: {
helloModuleService: {
resolve: "./modules/hello",
definition: {
isQueryable: true,
},
},
},
})
```
---
## How to Define a Module Link?
### 1. Create Link File
Links are defined in a TypeScript or JavaScript file under the `src/links` directory. The file defines the link using the `defineLink` function imported from `@medusajs/utils` and exports it.
For example:
export const highlights = [
["6", "linkable", "Special `linkable` property that holds the linkable data models of `HelloModule`."],
["7", "linkable", "Special `linkable` property that holds the linkable data models of `ProductModule`."],
]
```ts title="src/links/hello-product.ts" highlights={highlights}
import HelloModule from "../modules/hello"
import ProductModule from "@medusajs/product"
import { defineLink } from "@medusajs/utils"
export default defineLink(
HelloModule.linkable.myCustom,
ProductModule.linkable.product
)
```
The `defineLink` function accepts as parameters the link configurations of each module's data model. A module has a special `linkable` property that holds these configurations for its data models.
In this example, you define a module link between the `hello` module's `MyCustom` data model and the Product Module's `Product` data model.
### 2. Run Migrations
Medusa stores links as pivot tables in the database, so you must run migrations after defining a link:
```bash
npx medusa migrations run
```
---
## Define a List Link
By default, the defined link establishes a one-to-one relation: a record of a data model is linked to one record of the other data model.
To specify that a data model can have multiple of its records linked to the other data model's record, use the `isList` option.
For example:
```ts
import HelloModule from "../modules/hello"
import ProductModule from "@medusajs/product"
import { defineLink } from "@medusajs/utils"
export default defineLink(
{
model: HelloModule.linkable.myCustom,
isList: true
},
ProductModule.linkable.product
)
```
In this case, you pass an object of configuration as a parameter rather than the linked model. The object accepts the following properties:
- `model`: The data model to link.
- `isList`: Whether multiple records can be linked to one record of the other data model.
In this example, a record of `product` can be linked to more than one record of `myCustom`.
---
## Extend Data Models with Module Links
Module links are most useful when you want to add properties to a data model of another module.
For example, to add custom properties to the `Product` data model of the Product Module, you:
1. Create a module.
2. Create in the module a data model that holds the custom properties you want to add to the `Product` data model.
2. Define a module link that links your module to the Product Module.
Then, in the next chapters, you'll learn how to:
- Link each product to a record of your data model.
- Retrieve your data model's properties when you retrieve products.
@@ -80,7 +80,7 @@ The object that a modules loaders receive as a parameter has an `options` pro
For example:
```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["16"]]}
```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["12", "ModuleOptions", "The type of expected module options."], ["16"]]}
import {
LoaderOptions,
} from "@medusajs/modules-sdk"
@@ -6,9 +6,15 @@ export const metadata = {
In this chapter, youll learn what the remote link is and how to use it to manage links.
<Note type="soon" title="In Development">
Remote Links are in active development.
</Note>
## What is the Remote Link?
The remote link is a class with utility methods to manage links defined by the link module. Its registered in the Medusa container under the `remoteLink` registration name.
The remote link is a class with utility methods to manage links between data models. Its registered in the Medusa container under the `remoteLink` registration name.
For example:
@@ -38,7 +44,9 @@ export async function POST(
You can use its methods to manage links, such as create or delete links.
### Create Link
---
## Create Link
To create a link between records of two data models, use the `create` method of the remote link.
@@ -51,23 +59,25 @@ import { Modules } from "@medusajs/utils"
await remoteLink.create({
[Modules.PRODUCT]: {
variant_id: product.variants[0].id,
product_id: "prod_123",
},
[Modules.PRICING]: {
price_set_id: price.id,
"hello": {
my_custom_id: "mc_123",
},
})
```
The `create` method accepts as a parameter an object. The objects keys are the names of the linked modules.
The value of each modules property is an object. It defines the values of the linked fields.
The value of each modules property is an object, whose keys are of the format `{data_model_snake_name}_id`, and values are the IDs of the linked record.
So, in the example above, you specify for the Product Module the value of the `variant_id`, and for the Pricing Module the value of `price_set_id`. These are the fields linked between the models of the two modules.
So, in the example above, you link a record of the `MyCustom` data model in a `hello` module to a `Product` record in the Product Module.
### Dismiss Link
---
To remove a link between records of two data models, use the `dismiss` method of the remote link. This doesnt remove the records, only the relation between them.
## Dismiss Link
To remove a link between records of two data models, use the `dismiss` method of the remote link.
For example:
@@ -78,19 +88,21 @@ import { Modules } from "@medusajs/utils"
await remoteLink.dismiss({
[Modules.PRODUCT]: {
variant_id: product.variants[0].id,
product_id: "prod_123",
},
[Modules.PRICING]: {
price_set_id: price.id,
"hello": {
my_custom_id: "mc_123",
},
})
```
The `dismiss` method accepts the same parameter type as the [create method](#create-link).
### Cascade Delete Linked Records
---
If a record, such as a variant, is deleted, use the `delete` method of the remote link to delete all associated links with cascade delete enabled.
## Cascade Delete Linked Records
If a record is deleted, use the `delete` method of the remote link to delete all linked records.
For example:
@@ -103,16 +115,18 @@ await productModuleService.deleteVariants([variant.id])
await remoteLink.delete({
[Modules.PRODUCT]: {
variant_id: variant.id,
product_id: "prod_123",
},
})
```
This deletes all records linked to the deleted variant with cascade delete enabled in their relationship.
This deletes all records linked to the deleted product.
### Restore Linked Records
---
If a record, such as a variant, that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all associated links that were cascade deleted.
## Restore Linked Records
If a record that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all linked records.
For example:
@@ -121,77 +135,11 @@ import { Modules } from "@medusajs/utils"
// ...
await productModuleService.restoreVariants([variant.id])
await productModuleService.restoreProducts(["prod_123"])
await remoteLink.restore({
[Modules.PRODUCT]: {
variant_id: variant.id,
product_id: "prod_123",
},
})
```
---
## Link Module's Service
The remote link has a `getLinkModule` method to retrieve the service of the link module. This service has `list` and `retrieve` methods to retrieve the linked items.
For example, to retrieve the link module of the Product and Pricing modules:
export const linkModuleServiceHighlights = [
["6", "Modules.PRODUCT", "The name of the first module in the link module's definition."],
["7", '"variant_id"', "The foreign key that links to the record in the first module."],
["8", "Modules.PRICING", "The name of the second module in the link module's definition."],
["9", '"price_set_id"', "The foreign key that links to the record in the second module."],
["12", "", "The link module's service is undefined if either of the modules isn't installed or there's no link module with the specified definition."]
]
```ts highlights={linkModuleServiceHighlights}
import { Modules } from "@medusajs/utils"
// ...
const linkModuleService = remoteLink.getLinkModule(
Modules.PRODUCT,
"variant_id",
Modules.PRICING,
"price_set_id"
)
if (!linkModuleService) {
return
}
```
The `getLinkModule` method accepts four parameter:
1. A string indicating the name of the first module in the link module's definition.
2. A string indicating the foreign key that links to the record in the first module.
3. A string indicating the name of the second module in the link module's definition.
4. A string indicating the foreign key that links to the record in the second module.
Notice that the returned link module service might be undefined if either of the modules isn't installed, or if there's no link module with the specified definition.
### List Linked Items
The link module's service has a `list` method that retrieves a list of linked records. It also accepts filters to retrieve specific linked items.
For example, to retrieve the price sets linked to a variant:
```ts
import { Modules } from "@medusajs/utils"
// ...
const linkModuleService = remoteLink.getLinkModule(
Modules.PRODUCT,
"variant_id",
Modules.PRICING,
"price_set_id"
)
const items = await linkModuleService.list(
{ variant_id: [variant.id] },
{ select: ["variant_id", "price_set_id"] }
)
```
@@ -14,27 +14,11 @@ The remote query fetches data across modules. Its a function registered in th
In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusas commerce modules.
---
<Note type="check">
## isQueryable Configuration
- [Enable the isQueryable configuration of the module](../module-links/page.mdx#prerequisite-isqueryable-configuration)
Before you use remote query on your module, you must enable the `isQueryable` configuration of the module.
For example:
```js
module.exports = defineConfig({
// ...
modules: {
helloModuleService: {
resolve: "./modules/hello",
definition: {
isQueryable: true,
},
},
},
})
```
</Note>
---
@@ -93,6 +77,48 @@ You then pass the query to the `remoteQuery` function to retrieve the results.
---
## Retrieve Linked Records
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: [
"id",
"name",
"product.*"
],
})
```
<Note title="Tip">
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
</Note>
### Retrieve List Link Records
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: [
"id",
"name",
"products.*"
],
})
```
---
## Apply Filters
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
@@ -259,6 +285,8 @@ The remote query function alternatively accepts a string with GraphQL syntax as
}
`
const result = await remoteQuery(query)
res.json({
my_customs: result,
})
@@ -12,9 +12,9 @@ In this chapter, youll learn about what the service factory is and how to use
Medusa provides a service factory that your modules main service can extend.
The service factory generates data management methods for your data models, so you don't have to implement them manually.
The service factory generates data management methods for your data models, so you don't have to implement these methods manually.
<Note title="Use the service factory when" type="success">
<Note title="Extend the service factory when" type="success">
- Your service provides data-management functionalities of your data models.
@@ -50,7 +50,7 @@ export default HelloModuleService
The `MedusaService` function accepts one parameter, which is an object of data models to generate data-management methods for.
In the example above, the `HelloModuleService` now has methods to manage the `MyCustom` data model, such as `createMyCustoms`.
In the example above, since the `HelloModuleService` extends `MedusaService`, it has methods to manage the `MyCustom` data model, such as `createMyCustoms`.
### Generated Methods