docs: add missing details related to links and migrations (#11809)
* docs: add missing details related to links and migrations * reorder content * small changes * last changes * improve examples * fix lint error
This commit is contained in:
@@ -13,9 +13,9 @@ In this chapter, you'll learn available configurations in the Medusa application
|
||||
All configurations of the Medusa application are stored in the `medusa.config.ts` file. The file exports an object created using the `defineConfig` utility. For example:
|
||||
|
||||
```ts title="medusa.config.ts"
|
||||
import { loadEnv, defineConfig } from '@medusajs/framework/utils'
|
||||
import { loadEnv, defineConfig } from "@medusajs/framework/utils"
|
||||
|
||||
loadEnv(process.env.NODE_ENV || 'development', process.cwd())
|
||||
loadEnv(process.env.NODE_ENV || "development", process.cwd())
|
||||
|
||||
module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
@@ -26,7 +26,7 @@ module.exports = defineConfig({
|
||||
authCors: process.env.AUTH_CORS!,
|
||||
jwtSecret: process.env.JWT_SECRET || "supersecret",
|
||||
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -82,7 +82,7 @@ This configuration is useful for production databases, which can be supported by
|
||||
module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
databaseDriverOptions: process.env.NODE_ENV !== "development" ?
|
||||
{ connection: { ssl: { rejectUnauthorized: false } } } : {}
|
||||
{ connection: { ssl: { rejectUnauthorized: false } } } : {},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -177,7 +177,7 @@ The `projectConfig.databaseLogging` configuration specifies whether database mes
|
||||
```ts title="medusa-config.ts"
|
||||
module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
databaseLogging: true
|
||||
databaseLogging: true,
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -285,7 +285,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
jwtSecret: process.env.JWT_SECRET || "supersecret",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -305,7 +305,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
jwtExpiresIn: process.env.JWT_EXPIRES_IN || "2d",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -325,7 +325,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -362,8 +362,8 @@ Then, set the configuration in `medusa-config.ts`:
|
||||
module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
authCors: process.env.AUTH_CORS
|
||||
}
|
||||
authCors: process.env.AUTH_CORS,
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -377,7 +377,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
authCors: "/http:\\/\\/localhost:700\\d+$/",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -413,7 +413,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
storeCors: process.env.STORE_CORS,
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -427,7 +427,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
storeCors: "/vercel\\.app$/",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -463,7 +463,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
adminCors: process.env.ADMIN_CORS,
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -477,7 +477,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
adminCors: "/vercel\\.app$/",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -500,9 +500,9 @@ module.exports = defineConfig({
|
||||
enabled: true,
|
||||
level: 6,
|
||||
memLevel: 8,
|
||||
threshold: 1024
|
||||
}
|
||||
}
|
||||
threshold: 1024,
|
||||
},
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -563,9 +563,9 @@ module.exports = defineConfig({
|
||||
http: {
|
||||
authMethodsPerActor: {
|
||||
user: ["emailpass"],
|
||||
customer: ["emailpass", "google"]
|
||||
}
|
||||
}
|
||||
customer: ["emailpass", "google"],
|
||||
},
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -585,9 +585,9 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
http: {
|
||||
restrictedFields: {
|
||||
store: ["customer", "customers"]
|
||||
}
|
||||
}
|
||||
store: ["customer", "customers"],
|
||||
},
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -621,7 +621,7 @@ module.exports = defineConfig({
|
||||
redisOptions: {
|
||||
connectionName: process.env.REDIS_CONNECTION_NAME ||
|
||||
"medusa",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -710,7 +710,7 @@ module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
sessionOptions: {
|
||||
name: process.env.SESSION_NAME || "custom",
|
||||
}
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -786,7 +786,7 @@ In production, it's recommended to deploy two instances of your Medusa applicati
|
||||
```ts title="medusa-config.ts"
|
||||
module.exports = defineConfig({
|
||||
projectConfig: {
|
||||
workerMode: process.env.WORKER_MODE || "shared"
|
||||
workerMode: process.env.WORKER_MODE || "shared",
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
@@ -809,7 +809,7 @@ The `admin.backendUrl` configuration specifies the URL of the Medusa application
|
||||
module.exports = defineConfig({
|
||||
admin: {
|
||||
backendUrl: process.env.MEDUSA_BACKEND_URL ||
|
||||
"http://localhost:9000"
|
||||
"http://localhost:9000",
|
||||
},
|
||||
// ...
|
||||
})
|
||||
@@ -825,7 +825,7 @@ The `admin.disable` configuration specifies whether to disable the Medusa Admin.
|
||||
module.exports = defineConfig({
|
||||
admin: {
|
||||
disable: process.env.ADMIN_DISABLED === "true" ||
|
||||
false
|
||||
false,
|
||||
},
|
||||
// ...
|
||||
})
|
||||
@@ -871,7 +871,7 @@ For example, this URL is used as a prefix to shareable payment links for orders
|
||||
module.exports = defineConfig({
|
||||
admin: {
|
||||
storefrontUrl: process.env.MEDUSA_STOREFRONT_URL ||
|
||||
"http://localhost:8000"
|
||||
"http://localhost:8000",
|
||||
},
|
||||
// ...
|
||||
})
|
||||
@@ -895,7 +895,7 @@ module.exports = defineConfig({
|
||||
optimizeDeps: {
|
||||
include: ["qs"],
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
// ...
|
||||
@@ -929,9 +929,9 @@ module.exports = defineConfig({
|
||||
{
|
||||
resolve: "./src/modules/cms",
|
||||
options: {
|
||||
apiKey: process.env.CMS_API_KEY
|
||||
}
|
||||
}
|
||||
apiKey: process.env.CMS_API_KEY,
|
||||
},
|
||||
},
|
||||
],
|
||||
// ...
|
||||
})
|
||||
@@ -1068,7 +1068,7 @@ module.exports = defineConfig({
|
||||
featureFlags: {
|
||||
index_engine: true,
|
||||
// ...
|
||||
}
|
||||
},
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
@@ -23,17 +23,17 @@ Alternatively, you can manually create a migration file under the `migrations` d
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/modules/hello/migrations/Migration20240429.ts"
|
||||
```ts title="src/modules/blog/migrations/Migration20240429.ts"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20240702105919 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql("create table if not exists \"my_custom\" (\"id\" text not null, \"name\" text not null, \"created_at\" timestamptz not null default now(), \"updated_at\" timestamptz not null default now(), \"deleted_at\" timestamptz null, constraint \"my_custom_pkey\" primary key (\"id\"));")
|
||||
this.addSql("create table if not exists \"author\" (\"id\" text not null, \"name\" text not null, \"created_at\" timestamptz not null default now(), \"updated_at\" timestamptz not null default now(), \"deleted_at\" timestamptz null, constraint \"author_pkey\" primary key (\"id\"));")
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql("drop table if exists \"my_custom\" cascade;")
|
||||
this.addSql("drop table if exists \"author\" cascade;")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,7 +43,7 @@ The migration's file name should be of the format `Migration{YEAR}{MONTH}{DAY}.t
|
||||
|
||||
In the `up` and `down` method of the migration class, you use the `addSql` method provided by MikroORM's `Migration` class to run PostgreSQL syntax.
|
||||
|
||||
In the example above, the `up` method creates the table `my_custom`, and the `down` method drops the table if the migration is reverted.
|
||||
In the example above, the `up` method creates the table `author`, and the `down` method drops the table if the migration is reverted.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
@@ -76,10 +76,18 @@ This reflects the changes in the database as implemented in the migration's `up`
|
||||
To rollback or revert the last migration you ran for a module, run the following command:
|
||||
|
||||
```bash
|
||||
npx medusa db:rollback helloModuleService
|
||||
npx medusa db:rollback blog
|
||||
```
|
||||
|
||||
This rolls back the last ran migration on the Hello Module.
|
||||
This rolls back the last ran migration on the Blog Module.
|
||||
|
||||
### Caution: Rollback Migration before Deleting
|
||||
|
||||
If you need to delete a migration file, make sure to rollback the migration first. Otherwise, you might encounter issues when generating and running new migrations.
|
||||
|
||||
For example, if you delete the migration of the Blog Module, then try to create a new one, Medusa will create a brand new migration that re-creates the tables or indices. If those are still in the database, you might encounter errors.
|
||||
|
||||
So, always rollback the migration before deleting it.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Add Columns to a Link`,
|
||||
title: `${pageNumber} Add Columns to a Link Table`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn how to add custom columns to a link definition and manage them.
|
||||
In this chapter, you'll learn how to add custom columns to a link definition's table and manage them.
|
||||
|
||||
## Link Table's Default Columns
|
||||
|
||||
When you define a link between two data models, Medusa creates a link table in the database to store the IDs of the linked records. You can learn more about the created table in the [Module Links chapter](../page.mdx).
|
||||
|
||||
In various cases, you might need to store additional data in the link table. For example, if you define a link between a `product` and a `post`, you might want to store the publish date of the product's post in the link table.
|
||||
|
||||
In those cases, you can add a custom column to a link's table in the link definition. You can later set that column whenever you create or update a link between the linked records.
|
||||
|
||||
---
|
||||
|
||||
## How to Add Custom Columns to a Link's Table?
|
||||
|
||||
@@ -19,13 +29,13 @@ export const linkHighlights = [
|
||||
]
|
||||
|
||||
```ts highlights={linkHighlights}
|
||||
import HelloModule from "../modules/hello"
|
||||
import BlogModule from "../modules/blog"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
ProductModule.linkable.product,
|
||||
HelloModule.linkable.myCustom,
|
||||
BlogModule.linkable.blog,
|
||||
{
|
||||
database: {
|
||||
extraColumns: {
|
||||
@@ -38,7 +48,7 @@ export default defineLink(
|
||||
)
|
||||
```
|
||||
|
||||
This adds to the table created for the link between `product` and `myCustom` a `metadata` column of type `json`.
|
||||
This adds to the table created for the link between `product` and `blog` a `metadata` column of type `json`.
|
||||
|
||||
### Database Options
|
||||
|
||||
@@ -96,8 +106,8 @@ await link.create({
|
||||
[Modules.PRODUCT]: {
|
||||
product_id: "123",
|
||||
},
|
||||
HELLO_MODULE: {
|
||||
my_custom_id: "321",
|
||||
[BLOG_MODULE]: {
|
||||
post_id: "321",
|
||||
},
|
||||
data: {
|
||||
metadata: {
|
||||
@@ -116,28 +126,28 @@ To retrieve linked records with their custom columns, use [Query](../query/page.
|
||||
For example:
|
||||
|
||||
export const retrieveHighlights = [
|
||||
["1", "productHelloLink", "Import the exported link definition."],
|
||||
["1", "productPostLink", "Import the exported link definition."],
|
||||
["6", "entity", "Pass the link definition to retrieve its data."],
|
||||
["7", `"metadata"`, "Retrieve the `metadata` column."],
|
||||
["7", `"product.*"`, "Retrieve the linked product's details."],
|
||||
["7", `"my_custom.*"`, "Retrieve the linked `myCustom` record's details."],
|
||||
["7", `"post.*"`, "Retrieve the linked `post` record's details."],
|
||||
]
|
||||
|
||||
```ts highlights={retrieveHighlights}
|
||||
import productHelloLink from "../links/product-hello"
|
||||
import productPostLink from "../links/product-post"
|
||||
|
||||
// ...
|
||||
|
||||
const { data } = await query.graph({
|
||||
entity: productHelloLink.entryPoint,
|
||||
fields: ["metadata", "product.*", "my_custom.*"],
|
||||
entity: productPostLink.entryPoint,
|
||||
fields: ["metadata", "product.*", "post.*"],
|
||||
filters: {
|
||||
product_id: "prod_123",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
This retrieves the product of id `prod_123` and its linked `my_custom` records.
|
||||
This retrieves the product of id `prod_123` and its linked `post` records.
|
||||
|
||||
In the `fields` array you pass `metadata`, which is the custom column to retrieve of the link.
|
||||
|
||||
@@ -156,8 +166,8 @@ await link.create({
|
||||
[Modules.PRODUCT]: {
|
||||
product_id: "123",
|
||||
},
|
||||
HELLO_MODULE: {
|
||||
my_custom_id: "321",
|
||||
[BLOG_MODULE]: {
|
||||
post_id: "321",
|
||||
},
|
||||
data: {
|
||||
metadata: {
|
||||
|
||||
@@ -4,13 +4,15 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn what a module link is.
|
||||
In this chapter, you’ll learn what a module link is and how to define one.
|
||||
|
||||
## What is a Module Link?
|
||||
|
||||
Since modules are isolated, you can't access another module's data models to add a relation to it or extend it.
|
||||
Medusa's modular architecture isolates modules from one another to ensure they can be integrated into your application without side effects. Module isolation has other benefits, which you can learn about in the [Module Isolation chapter](../modules/isolation/page.mdx). Since modules are isolated, you can't access another module's data models to add a relation to it or extend it. Instead, you use a module link.
|
||||
|
||||
Instead, you use a module link. A module link forms an association between two data models of different modules, while maintaining module isolation.
|
||||
A module link forms an association between two data models of different modules while maintaining module isolation. Using module links, you can build virtual relations between your custom data models and data models in the commerce modules, which is useful as you extend the features provided by the commerce modules. Then, Medusa creates a link table in the database to store the IDs of the linked records. You'll learn more about link tables later in this chapter.
|
||||
|
||||
For example, the [Brand Customizations Tutorial](../../customization/extend-features/page.mdx) shows how to create a Brand Module that adds the concept of brands to your application, then link those brands to a product.
|
||||
|
||||
---
|
||||
|
||||
@@ -18,29 +20,29 @@ Instead, you use a module link. A module link forms an association between two d
|
||||
|
||||
### 1. Create Link File
|
||||
|
||||
Links are defined in a TypeScript or JavaScript file under the `src/links` directory. The file defines the link using `defineLink` from the Modules SDK and exports it.
|
||||
Module links are defined in a TypeScript or JavaScript file under the `src/links` directory. The file defines the link using `defineLink` from the Modules SDK and exports it.
|
||||
|
||||
For example:
|
||||
|
||||
export const highlights = [
|
||||
["6", "linkable", "Special `linkable` property that holds the linkable data models of `HelloModule`."],
|
||||
["6", "linkable", "Special `linkable` property that holds the linkable data models of `BlogModule`."],
|
||||
["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"
|
||||
```ts title="src/links/blog-product.ts" highlights={highlights}
|
||||
import BlogModule from "../modules/blog"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
ProductModule.linkable.product,
|
||||
HelloModule.linkable.myCustom
|
||||
BlogModule.linkable.post
|
||||
)
|
||||
```
|
||||
|
||||
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.
|
||||
In this example, you define a module link between the `blog` module's `post` data model and the Product Module's `Product` data model.
|
||||
|
||||
### 2. Sync Links
|
||||
|
||||
@@ -50,25 +52,34 @@ After defining the link, run the `db:sync-links` command:
|
||||
npx medusa db:sync-links
|
||||
```
|
||||
|
||||
The Medusa application creates a new table for your link to store the IDs of linked records.
|
||||
The Medusa application creates a new table for your module link to store the IDs of linked records.
|
||||
|
||||
Use this command whenever you make changes to your links. For example, run this command if you remove your link definition file.
|
||||
You can also use the `db:migrate` command, which runs both the migrations and syncs the links.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
You can also use the `db:migrate` command, which both runs the migrations and syncs the links.
|
||||
|
||||
</Note>
|
||||
Use either of these commands whenever you make changes to your link definitions. For example, run this command if you remove your link definition file.
|
||||
|
||||
---
|
||||
|
||||
## How Module Links Work?
|
||||
### Module Link's Database Table
|
||||
|
||||
When you define a module link, the Medusa application creates a table in the database for that link.
|
||||
When you define a module link, the Medusa application creates a table in the database for that module link. The table's name is a combination of the names of the two data models linked in the format `module1_table1_module2_table2`, where:
|
||||
|
||||
- `module1` and `module2` are the names of the modules.
|
||||
- `table1` and `table2` are the table names of the data models.
|
||||
|
||||
For example, if you define a link between the `Product` data model from the [Product Module](!resources!/commerce-modules/product) and a `Post` data model from a Blog Module, the table name would be `product_product_blog_post`.
|
||||
|
||||
The table has two columns, each storing the ID of a record from the linked data models. For example, the `product_product_blog_post` table would have columns `product_id` and `post_id`. These columns store only the IDs of the linked records and do not hold a foreign key constraint.
|
||||
|
||||
Then, when you create links between records of the data models, the IDs of these data models are stored as a new record in the link's table.
|
||||
|
||||

|
||||
<Note title="Tip">
|
||||
|
||||
You can also add custom columns in the link table as explained in the [Add Columns to Link Table chapter](./custom-columns/page.mdx).
|
||||
|
||||
</Note>
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -89,23 +100,23 @@ You want to create a relationship between data models in the same module. Use da
|
||||
|
||||
---
|
||||
|
||||
## Define a List Link
|
||||
## Define a List Module 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.
|
||||
By default, a module 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 BlogModule from "../modules/blog"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
ProductModule.linkable.product,
|
||||
{
|
||||
linkable: HelloModule.linkable.myCustom,
|
||||
linkable: BlogModule.linkable.post,
|
||||
isList: true,
|
||||
}
|
||||
)
|
||||
@@ -116,7 +127,30 @@ In this case, you pass an object of configuration as a parameter instead. The ob
|
||||
- `linkable`: The data model's link configuration.
|
||||
- `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`.
|
||||
In this example, a record of `product` can be linked to more than one record of `post`.
|
||||
|
||||
### Many-to-Many Module Link
|
||||
|
||||
Your module link can also establish a many-to-many relation between the linked data models. To do this, enable `isList` on both sides of the link.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import BlogModule from "../modules/blog"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
{
|
||||
linkable: ProductModule.linkable.product,
|
||||
isList: true,
|
||||
},
|
||||
{
|
||||
linkable: BlogModule.linkable.post,
|
||||
isList: true,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -127,17 +161,82 @@ To enable delete cascade on a link so that when a record is deleted, its linked
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import HelloModule from "../modules/hello"
|
||||
import BlogModule from "../modules/blog"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
ProductModule.linkable.product,
|
||||
{
|
||||
linkable: HelloModule.linkable.myCustom,
|
||||
linkable: BlogModule.linkable.post,
|
||||
deleteCascade: true,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
In this example, when a product is deleted, its linked `myCustom` record is also deleted.
|
||||
In this example, when a product is deleted, its linked `post` record is also deleted.
|
||||
|
||||
---
|
||||
|
||||
## Renaming Participants in a Module Link
|
||||
|
||||
As mentioned in the [Module Link's Database Table](#module-links-database-table) section, the name of a link's table consists of the names of the modules and the data models' table names.
|
||||
|
||||
So, if you rename a module or a data model's table, then run the `db:sync-links` or `db:migrate` commands, you'll be asked to delete the old link table and create a new one.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
A data model's table name is passed in the first parameter of `model.define`, and a module's name is passed in the first parameter of `Module` in the module's `index.ts` file.
|
||||
|
||||
</Note>
|
||||
|
||||
For example, if you have the link table `product_product_blog_post` and you rename the Blog Module from `blog` to `article`, Medusa considers the old link definition deleted. Then, when you run the `db:sync-links` or `db:migrate` command, Medusa will ask if you want to delete the old link table, and will create a new one with the new name `product_product_article_post`.
|
||||
|
||||
To resolve this, you can rename the link table in the link definition.
|
||||
|
||||
### Rename Link Table
|
||||
|
||||
If you need to rename a module or its data model's table, you can persist the old name by passing a third parameter to `defineLink`. This parameter is an object of additional configurations. It accepts a `database` property that allows you to configure the link's table name.
|
||||
|
||||
For example, after renaming the Blog Module to `article`, you can persist the old name `blog` in the link table name:
|
||||
|
||||
export const renameHighlights = [
|
||||
["13", `"product_product_blog_post"`, "Specify the old link table name to persist when renaming a module or data model's table."]
|
||||
]
|
||||
|
||||
```ts highlights={renameHighlights}
|
||||
import ArticleModule from "../modules/article"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
|
||||
export default defineLink(
|
||||
ProductModule.linkable.product,
|
||||
{
|
||||
linkable: ArticleModule.linkable.post,
|
||||
isList: true,
|
||||
},
|
||||
{
|
||||
database: {
|
||||
table: "product_product_blog_post",
|
||||
},
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
In this example, you set the `table` property in the `database` object to the old link table name `product_product_blog_post`, ensuring that the old link table is not deleted.
|
||||
|
||||
This is enough to rename the link table when you rename a module. If you renamed a data model's table, you need to also run the `db:sync-links` or `db:migrate` commands, which will update the column names in the link table automatically:
|
||||
|
||||
```bash
|
||||
npx medusa db:migrate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Delete Module Link Definition
|
||||
|
||||
To delete a module link definition, remove the link file from the `src/links` directory. Then, run the `db:sync-links` or `db:migrate` command to delete the link table from the database:
|
||||
|
||||
```bash
|
||||
npx medusa db:migrate
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ A module is a reusable package of functionalities related to a single domain or
|
||||
|
||||
When building a commerce application, you often need to introduce custom behavior specific to your products, tech stack, or your general ways of working. In other commerce platforms, introducing custom business logic and data models requires setting up separate applications to manage these customizations.
|
||||
|
||||
Medusa removes this overhead by allowing you to easily write custom modules that integrate into the Medusa application without implications on the existing setup. You can also re-use your modules across Medusa projects.
|
||||
Medusa removes this overhead by allowing you to easily write custom modules that integrate into the Medusa application without affecting the existing setup. You can also re-use your modules across Medusa projects.
|
||||
|
||||
As you learn more about Medusa, you will see that modules are central to customizations and integrations. With modules, your Medusa application can turn into a middleware solution for your commerce ecosystem.
|
||||
|
||||
@@ -34,7 +34,7 @@ As you learn more about Medusa, you will see that modules are central to customi
|
||||
|
||||
In a module, you define data models that represent new tables in the database, and you manage these models in a class called a service. Then, the Medusa application registers the module's service in the [Medusa container](../../fundamentals/medusa-container/page.mdx) so that you can build commerce flows and features around the functionalities provided by the module.
|
||||
|
||||
In this section, you'll build a Blog Module that has a `Post` data model and a service to manage that data model, you'll expose an API endpoint to create a blog post.
|
||||
In this section, you'll build a Blog Module that has a `Post` data model and a service to manage that data model. You'll also expose an API endpoint to create a blog post.
|
||||
|
||||
Modules are created in a sub-directory of `src/modules`. So, start by creating the directory `src/modules/blog`.
|
||||
|
||||
@@ -96,7 +96,7 @@ class BlogModuleService extends MedusaService({
|
||||
export default BlogModuleService
|
||||
```
|
||||
|
||||
Your module's service extends a class generated by `MedusaService` from the Modules SDK. This class comes with generated methods for data-management Create, Read, Update, and Delete (CRUD) operations on each of your modules, saving your time that can be spent on building custom business logic.
|
||||
Your module's service extends a class generated by `MedusaService` from the Modules SDK. This class comes with generated methods for data-management Create, Read, Update, and Delete (CRUD) operations on each of your modules, saving you time that can be spent on building custom business logic.
|
||||
|
||||
The `MedusaService` function accepts an object of data models to generate methods for. You can pass all data models in your module in this object.
|
||||
|
||||
@@ -137,7 +137,7 @@ export default Module(BLOG_MODULE, {
|
||||
|
||||
You use `Module` from the Modules SDK to create the module's definition. It accepts two parameters:
|
||||
|
||||
1. The name that the module's main service is registered under (`blog`).
|
||||
1. The name that the module's main service is registered under (`blog`). The module name can contain only alphanumeric characters and underscores.
|
||||
2. An object with a required property `service` indicating the module's main service.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
@@ -35,7 +35,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/admin/page.mdx": "2024-10-23T07:08:55.898Z",
|
||||
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2025-01-27T08:45:19.028Z",
|
||||
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2025-02-12T13:55:33.437Z",
|
||||
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2024-11-11T15:27:59.794Z",
|
||||
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2025-03-11T12:58:05.655Z",
|
||||
"app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2025-02-11T15:53:12.541Z",
|
||||
"app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
|
||||
"app/learn/fundamentals/modules/options/page.mdx": "2025-02-12T16:00:28.484Z",
|
||||
@@ -70,13 +70,13 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/admin/constraints/page.mdx": "2024-10-21T13:30:21.366Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx": "2025-01-31T13:19:02.586Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2025-01-31T13:19:02.587Z",
|
||||
"app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-01-06T11:19:13.178Z",
|
||||
"app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-03-11T13:29:54.752Z",
|
||||
"app/learn/fundamentals/module-links/directions/page.mdx": "2024-12-12T15:31:31.555Z",
|
||||
"app/learn/fundamentals/module-links/page.mdx": "2024-12-09T14:39:26.668Z",
|
||||
"app/learn/fundamentals/module-links/page.mdx": "2025-03-11T13:39:14.345Z",
|
||||
"app/learn/fundamentals/module-links/query/page.mdx": "2025-02-04T07:35:31.633Z",
|
||||
"app/learn/fundamentals/modules/db-operations/page.mdx": "2024-12-09T14:40:50.581Z",
|
||||
"app/learn/fundamentals/modules/multiple-services/page.mdx": "2024-10-21T13:30:21.370Z",
|
||||
"app/learn/fundamentals/modules/page.mdx": "2025-01-16T08:34:28.947Z",
|
||||
"app/learn/fundamentals/modules/page.mdx": "2025-03-11T13:00:37.391Z",
|
||||
"app/learn/debugging-and-testing/instrumentation/page.mdx": "2025-02-24T08:12:53.132Z",
|
||||
"app/learn/fundamentals/api-routes/additional-data/page.mdx": "2025-01-27T08:45:19.025Z",
|
||||
"app/learn/fundamentals/workflows/variable-manipulation/page.mdx": "2025-01-27T08:45:19.029Z",
|
||||
|
||||
@@ -7,7 +7,7 @@ export const generatedSidebars = [
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "category",
|
||||
"title": "1. Get Started",
|
||||
"title": "1. Getting Started",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -40,7 +40,7 @@ export const generatedSidebars = [
|
||||
"number": "1.3."
|
||||
}
|
||||
],
|
||||
"chapterTitle": "1. Get Started",
|
||||
"chapterTitle": "1. Getting Started",
|
||||
"number": "1."
|
||||
},
|
||||
{
|
||||
@@ -406,9 +406,9 @@ export const generatedSidebars = [
|
||||
"isPathHref": true,
|
||||
"type": "link",
|
||||
"path": "/learn/fundamentals/module-links/custom-columns",
|
||||
"title": "Custom Columns",
|
||||
"title": "Add Custom Columns",
|
||||
"children": [],
|
||||
"chapterTitle": "3.3.4. Custom Columns",
|
||||
"chapterTitle": "3.3.4. Add Custom Columns",
|
||||
"number": "3.3.4."
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ export const sidebars = [
|
||||
items: [
|
||||
{
|
||||
type: "category",
|
||||
title: "Get Started",
|
||||
title: "Getting Started",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
@@ -218,7 +218,7 @@ export const sidebars = [
|
||||
{
|
||||
type: "link",
|
||||
path: "/learn/fundamentals/module-links/custom-columns",
|
||||
title: "Custom Columns",
|
||||
title: "Add Custom Columns",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
|
||||
Reference in New Issue
Block a user