docs: improvements and fixes to API route docs (#9197)

General improvements and fixes to docs around API routes
This commit is contained in:
Shahed Nasser
2024-09-19 17:08:23 +03:00
committed by GitHub
parent 270a9a1770
commit bf4335f2a6
11 changed files with 240 additions and 66 deletions

View File

@@ -10,4 +10,4 @@ When you create a data model, the following properties are created for you by Me
- `created_at`: A `dateTime` property that stores when a record of the data model was created.
- `updated_at`: A `dateTime` property that stores when a record of the data model was updated.
- `deleted_at`: A `dateTime` property that stores when a record of the data model was deleted. When you delete a record, Medusa soft-deletes it by setting the `deleted_at` property to the current date.
- `deleted_at`: A `dateTime` property that stores when a record of the data model was deleted. When you soft-delete a record, Medusa sets the `deleted_at` property to the current date.

View File

@@ -1,14 +1,14 @@
export const metadata = {
title: `${pageNumber} Data Model Index`,
title: `${pageNumber} Data Model Database Index`,
}
# {metadata.title}
In this chapter, youll learn how to define indices on a data model.
In this chapter, youll learn how to define a database index on a data model.
## Define Index on Property
## Define Database Index on Property
Use the `index` method on a property's definition to define an index.
Use the `index` method on a property's definition to define a database index.
For example:
@@ -36,9 +36,9 @@ In this example, you define an index on the `name` property.
---
## Define Index on Data Model
## Define Database Index on Data Model
A data model has an `indexes` method that defines indices on its properties.
A data model has an `indexes` method that defines database indices on its properties.
The index can be on multiple columns (composite index). For example:
@@ -95,7 +95,7 @@ const MyCustom = model.define("my_custom", {
export default MyCustom
```
The index object passed to `indexes` accepts a `where` property that is an object of conditions. The object's key is a property's name, and its value is the condition on that property.
The index object passed to `indexes` accepts a `where` property whose value is an object of conditions. The object's key is a property's name, and its value is the condition on that property.
In the example above, the composite index is created on the `name` and `age` properties when the `age`'s value is `30`.
@@ -130,7 +130,7 @@ A property's value in `where` can be an object having a `$ne` property. `$ne`'s
In the example above, the composite index is created on the `name` and `age` properties when `age`'s value is not `null`.
### Unique Data Model Index
### Unique Database Index
The object passed to `indexes` accepts a `unique` property indicating that the created index must be a unique index.

View File

@@ -8,63 +8,173 @@ export const metadata = {
In this chapter, you'll learn how to manage relationships between data models when creating, updating, or retrieving records using the module's main service.
## Manage One-to-One and One-to-Many Relationship
## Manage One-to-One Relationship
When you create a record of a data model that belongs to another, pass the ID of the other data model's record in the `{relation_name}_id` property.
### BelongsTo Side of One-to-One
For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship):
When you create a record of a data model that belongs to another through a one-to-one relation, pass the ID of the other data model's record in the relation property.
For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship), set an email's user ID as follows:
export const belongsHighlights = [
["4", "user_id", "The ID of the user the email belongs to."],
["11", "user_id", "The ID of the user the email belongs to."]
["4", "user", "The ID of the user the email belongs to."],
["11", "user", "The ID of the user the email belongs to."]
]
```ts highlights={belongsHighlights}
// when creating an email
const email = await helloModuleService.createEmail({
const email = await helloModuleService.createEmails({
// other properties...
user_id: "123",
user: "123",
})
// when updating an email
const email = await helloModuleService.updateEmail({
const email = await helloModuleService.updateEmails({
id: "321",
// other properties...
user_id: "123",
user: "123",
})
```
In the example above, you pass the `user_id` property when creating or updating an email to specify the user it belongs to.
In the example above, you pass the `user` property when creating or updating an email to specify the user it belongs to.
### HasOne Side
When you create a record of a data model that has one of another, pass the ID of the other data model's record in the relation property.
For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship), set an user's email ID as follows:
export const hasOneHighlights = [
["4", "email", "The ID of the email that the user has."],
["11", "email", "The ID of the email that the user has."]
]
```ts highlights={hasOneHighlights}
// when creating a user
const user = await helloModuleService.createUsers({
// other properties...
email: "123",
})
// when updating a user
const user = await helloModuleService.updateUsers({
id: "321",
// other properties...
email: "123",
})
```
In the example above, you pass the `email` property when creating or updating a user to specify the email it has.
---
## Manage One-to-Many Relationship
In a one-to-many relationship, you can only manage the associations from the `belongsTo` side.
When you create a record of the data model on the `belongsTo` side, pass the ID of the other data model's record in the `{relation}_id` property, where `{relation}` is the name of the relation property.
For example, assuming you have the [Product and Store data models from the previous chapter](../relationships/page.mdx#one-to-many-relationship), set a product's store ID as follows:
export const manyBelongsHighlights = [
["4", "store_id", "The ID of the store the product belongs to."],
["11", "store_id", "The ID of the store the product belongs to."]
]
```ts highlights={manyBelongsHighlights}
// when creating a product
const product = await helloModuleService.createProducts({
// other properties...
store_id: "123",
})
// when updating a product
const product = await helloModuleService.updateProducts({
id: "321",
// other properties...
store_id: "123",
})
```
In the example above, you pass the `store_id` property when creating or updating a product to specify the store it belongs to.
---
## Manage Many-to-Many Relationship
When you create or update a record of a data model that has a many-to-many relationship to another data model, pass an array of IDs of the other data model's records in the `{relation_name}_ids` property.
### Create Associations
For example, assuming you have the [Order and Product data models from the previous chapter](../relationships/page.mdx#many-to-many-relationship):
When you create a record of a data model that has a many-to-many relationship to another data model, pass an array of IDs of the other data model's records in the relation property.
For example, assuming you have the [Order and Product data models from the previous chapter](../relationships/page.mdx#many-to-many-relationship), set the association between products and orders as follows:
export const manyHighlights = [
["4", "order_ids", "The IDs of the orders associated with the product."],
["11", "product_ids", "The IDs of the products associated with the order."]
["4", "orders", "The IDs of the orders associated with the product."],
["11", "products", "The IDs of the products associated with the order."]
]
```ts highlights={manyHighlights}
// when creating a product
const product = await helloModuleService.createProduct({
const product = await helloModuleService.createProducts({
// other properties...
order_ids: ["123", "321"],
orders: ["123", "321"],
})
// when updating an order
const order = await helloModuleService.updateOrder({
// when creating an order
const order = await helloModuleService.createOrders({
id: "321",
// other properties...
product_ids: ["123", "321"],
products: ["123", "321"],
})
```
In the example above, you pass the `order_ids` property when you create (or update) a product, and you pass the `product_ids` property when you update (or create) an order.
In the example above, you pass the `orders` property when you create a product, and you pass the `products` property when you create an order.
### Update Associations
When you use the `update` methods generated by the service factory, you also pass an array of IDs as the relation property's value to add new associated records.
However, this removes any existing associations to records whose IDs aren't included in the array.
For example, assuming you have the [Order and Product data models from the previous chapter](../relationships/page.mdx#many-to-many-relationship), you update the product's related orders as so:
```ts
const product = await helloModuleService.updateProducts({
id: "123",
// other properties...
orders: ["321"],
})
```
If the product was associated with an order, and you don't include that order's ID in the `orders` array, the association between the product and order is removed.
So, to add a new association without removing existing ones, retrieve the product first to pass its associated orders when updating the product:
export const updateAssociationHighlights = [
["1", "retrieveProduct", "Retrieve the product with its orders."],
["12", "", "Pass the IDs of the orders previously associated with the product."],
["13", "", "Associate the product with a new order."]
]
```ts highlights={updateAssociationHighlights}
const product = await helloModuleService.retrieveProduct(
"123",
{
relations: ["orders"]
}
)
const updatedProduct = await helloModuleService.updateProducts({
id: product.id,
// other properties...
orders: [
...product.orders.map((order) => order.id),
"321"
],
})
```
This keeps existing associations between the product and orders, and adds a new one.
---
@@ -74,14 +184,14 @@ The `list`, `listAndCount`, and `retrieve` methods of a module's main service ac
To retrieve the records associated with a data model's records through a relationship, pass in the second parameter object a `relations` property whose value is an array of relationship names.
For example, assuming you have the [Order and Product data models from the previous chapter](../relationships/page.mdx#many-to-many-relationship):
For example, assuming you have the [Order and Product data models from the previous chapter](../relationships/page.mdx#many-to-many-relationship), you retrieve a product's orders as follows:
export const retrieveHighlights = [
["4", `"orders"`, "Retrieve the records associated with the product\nthrough the `orders` relationship."]
]
```ts highlights={retrieveHighlights}
const product = await helloModuleService.retrieveProduct(
const product = await helloModuleService.retrieveProducts(
"123",
{
relations: ["orders"],

View File

@@ -1,7 +1,15 @@
export const metadata = {
title: `${pageNumber} Data Models`,
title: `${pageNumber} Data Models Advanced Guides`,
}
# {metadata.title}
In the next chapters, you'll learn more about creating data models, including property types, relationships, and more.
In the next chapters, you'll learn more about defining data models.
You'll learn about:
- The different property types available.
- How to set a property as a primary key.
- How to create and manage relationships.
- How to configure properties, such as making them nullable or searchable.
- How to manually write migrations.

View File

@@ -6,9 +6,11 @@ export const metadata = {
In this chapter, youll learn about the types of properties in a data models schema.
These types are available as methods on the `model` utility imported from `@medusajs/utils`.
## id
The `id` method defines an automatically generated string ID property.
The `id` method defines an automatically generated string ID property. The generated ID is a unique string that has a mix of letters and numbers.
For example:
@@ -194,3 +196,9 @@ const MyCustom = model.define("my_custom", {
export default MyCustom
```
---
## Properties Reference
Refer to the [Data Model API reference](https://docs.medusajs.com/v2/resources/references/data-model) for a full reference of the properties.

View File

@@ -8,6 +8,12 @@ export const metadata = {
In this chapter, youll learn how to define relationships between data models in your module.
## What is a Relationship Property?
A relationship property defines an association in the database between two models. It's created using methods on the `models` utility, such as `hasOne` or `belongsTo`.
When you generate a migration for these data models, the migrations include foreign key columns or pivot tables, based on the relationship's type.
<Note title="Use data model relationships when" type="success">
You want to create a relation between data models in the same module.
@@ -20,14 +26,12 @@ You want to create a relationship between data models in different modules. Use
</Note>
## What is a Relationship Property?
A relationship property is defined using relation methods, such as `hasOne` or `belongsTo`. It represents a relationship between two data models in a module.
---
## One-to-One Relationship
A one-to-one relationship indicates that one record of a data model belongs to or is associated with another.
To define a one-to-one relationship, create relationship properties in the data models using the following methods:
1. `hasOne`: indicates that the model has one record of the specified model.
@@ -57,16 +61,31 @@ const Email = model.define("email", {
})
```
In the example above, a user has one email, and an email belongs to one user.
The `hasOne` and `belongsTo` methods accept a function as a first parameter. The function returns the associated data model.
The `belongsTo` method also requires passing as a second parameter an object with the property `mappedBy`. Its value is the name of the relationship property in the other data model.
In the example above, a user has one email, and an email belongs to one user.
### Optional Relationship
To make the relationship optional on the `hasOne` or `belongsTo` side, use the `nullable` method on either properties as explained in [this chapter](../configure-properties/page.mdx#nullable-property).
### One-to-One Relationship in the Database
When you generate the migrations of data models that have a one-to-one relationship, the migration adds to the table of the data model that has the `belongsTo` property:
1. A column of the format `{relation_name}_id` to store the ID of the record of the related data model. For example, the `email` table will have a `user_id` column.
2. A foreign key on the `{relation_name}_id` column to the table of the related data model.
![Diagram illustrating the relation between user and email records in the database](https://res.cloudinary.com/dza7lstvk/image/upload/v1726733492/Medusa%20Book/one-to-one_cj5np3.jpg)
---
## One-to-Many Relationship
A one-to-many relationship indicates that one record of a data model has many records of another data model.
To define a one-to-many relationship, create relationship properties in the data models using the following methods:
1. `hasMany`: indicates that the model has more than one records of the specified model.
@@ -98,10 +117,25 @@ const Product = model.define("product", {
In this example, a store has many products, but a product belongs to one store.
### Optional Relationship
To make the relationship optional on the `belongsTo` side, use the `nullable` method on the property as explained in [this chapter](../configure-properties/page.mdx#nullable-property).
### One-to-Many Relationship in the Database
When you generate the migrations of data models that have a one-to-many relationship, the migration adds to the table of the data model that has the `belongsTo` property:
1. A column of the format `{relation_name}_id` to store the ID of the record of the related data model. For example, the `product` table will have a `store_id` column.
2. A foreign key on the `{relation_name}_id` column to the table of the related data model.
![Diagram illustrating the relation between a store and product records in the database](https://res.cloudinary.com/dza7lstvk/image/upload/v1726733937/Medusa%20Book/one-to-many_d6wtcw.jpg)
---
## Many-to-Many Relationship
A many-to-many relationship indicates that many records of a data model can be associated to many records of another data model.
To define a many-to-many relationship, create relationship properties in the data models using the `manyToMany` method.
For example:
@@ -124,21 +158,31 @@ const Order = model.define("order", {
const Product = model.define("product", {
id: model.id().primaryKey(),
orders: model.manyToMany(() => Order, {
mappedBy: "orders"
mappedBy: "products"
}),
})
```
At least one side of the many-to-many relationship should have the `mappedBy` property set in the second object parameter of the `manyToMany` object. Its value is the name of the relationship property in the other data model.
At least one side of the many-to-many relationship must have the `mappedBy` property set in the second object parameter of the `manyToMany` object. Its value is the name of the relationship property in the other data model.
In this example, an order is associated with many products, and a product is associated with many orders.
### Many-to-Many Relationship in the Database
When you generate the migrations of data models that have a many-to-many relationship, the migration adds a new pivot table.
The pivot table has a column with the name `{data_model}_id` for each of the data model's tables. It also has foreign keys on each of these columns to their respective tables.
![Diagram illustrating the relation between order and product records in the database](https://res.cloudinary.com/dza7lstvk/image/upload/v1726734269/Medusa%20Book/many-to-many_fzy5pq.jpg)
---
## Configure Relationship Property Name
## Set Relationship Name in the Other Model
The relationship property methods accept as a second parameter an object of options. The `mappedBy` property defines the name of the relationship in the other data model.
This is useful if the relationship propertys name is different than that of the associated data model.
As seen in previous examples, the `mappedBy` option is required for the `belongsTo` method.
For example:
@@ -168,8 +212,6 @@ const Email = model.define("email", {
In this example, you specify in the `User` data models relationship property that the name of the relationship in the `Email` data model is `owner`.
This is useful if the relationship propertys name is different than that of the associated data model.
---
## Cascades

View File

@@ -10,7 +10,7 @@ In this chapter, you'll learn what a searchable property is and how to define it
Methods generated by the [service factory](../../modules/service-factory/page.mdx) that accept filters, such as `list{ModelName}s`, accept a `q` property as part of the filters.
When the `q` filter is passed, the query is applied on searchable properties in a data model.
When the `q` filter is passed, the data model's searchable properties are queried to find matching records.
---
@@ -47,4 +47,4 @@ const myCustoms = await helloModuleService.listMyCustoms({
})
```
The `q` filter is applied on the `name` property of the `MyCustom` records.
This retrieves records that include `John` in their `name` property.

View File

@@ -45,6 +45,12 @@ In the `up` and `down` method of the migration class, you use the `addSql` metho
In the example above, the `up` method creates the table `my_custom`, and the `down` method drops the table if the migration is reverted.
<Note title="Tip">
Refer to [MikroORM's documentation](https://mikro-orm.io/docs/migrations#migration-class) for more details on writing migrations.
</Note>
---
## Run the Migration

View File

@@ -16,14 +16,6 @@ A data model is created in a module, and its record are managed in the database
## How to Create a Data Model?
<Note title="Steps Summary">
1. Create a data model in a module.
2. Generate migration for the data model.
4. Run migration to add the data model's table in the database.
</Note>
A data model is created in a TypeScript or JavaScript file under a module's `models` directory. It's defined using the `model` utility imported from `@medusajs/utils`.
For example, create the file `src/modules/hello/models/my-custom.ts` with the following content:
@@ -48,7 +40,7 @@ The example above defines the data model `MyCustom` with the properties `id` and
### Generate a Migration
A migration is a TypeScript or JavaScript file that defines changes to be made in the database, such as create or update tables.
A migration is a TypeScript or JavaScript file that defines changes to be made in the database, such as creating a new table or updating it.
To generate a migration for the data models in your module, run the following command:
@@ -56,7 +48,9 @@ To generate a migration for the data models in your module, run the following co
npx medusa db:generate helloModuleService
```
The `db:generate` command of the Medusa CLI accepts one or more module names (for example, `helloModuleService`) to generate the migration for.
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for.
The module name (for example, `helloModuleService`) is the key used when registering the module in the `modules` configuration in `medusa-config.js`.
The above command creates a migration file at the directory `src/modules/hello/migrations` similar to the following:
@@ -78,6 +72,12 @@ export class Migration20240702105919 extends Migration {
In the migration class, the `up` method creates the table `my_custom` and defines its columns. The `down` method drops the table.
<Note>
Data models automatically have the date properties `created_at`, `updated_at`, and `deleted_at`.
</Note>
### Run Migration
To reflect the changes in the generated migration file, run the `migration` command:

View File

@@ -27,16 +27,16 @@ export const generatedEditDates = {
"app/advanced-development/workflows/access-workflow-errors/page.mdx": "2024-09-11T10:46:54.913Z",
"app/basics/events-and-subscribers/page.mdx": "2024-09-03T08:01:30.986Z",
"app/advanced-development/modules/container/page.mdx": "2024-08-05T07:23:49+00:00",
"app/basics/data-models/page.mdx": "2024-09-03T07:58:42.761Z",
"app/basics/data-models/page.mdx": "2024-09-19T07:24:38.584Z",
"app/advanced-development/workflows/execute-another-workflow/page.mdx": "2024-07-21T21:19:23+02:00",
"app/basics/loaders/page.mdx": "2024-09-03T08:00:45.993Z",
"app/advanced-development/admin/widgets/page.mdx": "2024-08-06T09:44:22+02:00",
"app/advanced-development/data-models/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/page.mdx": "2024-09-19T07:26:43.535Z",
"app/advanced-development/modules/remote-link/page.mdx": "2024-07-24T09:16:01+02:00",
"app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-11T10:45:44.293Z",
"app/advanced-development/workflows/add-workflow-hook/page.mdx": "2024-08-13T09:55:37+03:00",
"app/advanced-development/events-and-subscribers/data-payload/page.mdx": "2024-07-16T17:12:05+01:00",
"app/advanced-development/data-models/default-properties/page.mdx": "2024-07-02T12:34:44+03:00",
"app/advanced-development/data-models/default-properties/page.mdx": "2024-09-19T07:32:06.118Z",
"app/advanced-development/workflows/advanced-example/page.mdx": "2024-09-11T10:46:59.975Z",
"app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-09-10T11:39:51.168Z",
"app/advanced-development/workflows/conditions/page.mdx": "2024-07-31T17:01:33+03:00",
@@ -44,16 +44,16 @@ export const generatedEditDates = {
"app/advanced-development/admin/page.mdx": "2024-05-29T13:50:19+03:00",
"app/advanced-development/workflows/long-running-workflow/page.mdx": "2024-09-11T11:29:58.203Z",
"app/advanced-development/workflows/constructor-constraints/page.mdx": "2024-07-17T13:19:51+01:00",
"app/advanced-development/data-models/write-migration/page.mdx": "2024-07-15T17:46:10+02:00",
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-09-10T11:39:51.167Z",
"app/advanced-development/data-models/write-migration/page.mdx": "2024-09-19T08:50:51.503Z",
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-09-19T12:13:08.980Z",
"app/advanced-development/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
"app/advanced-development/modules/options/page.mdx": "2024-08-05T07:23:49+00:00",
"app/advanced-development/data-models/relationships/page.mdx": "2024-09-11T11:28:55.494Z",
"app/advanced-development/data-models/relationships/page.mdx": "2024-09-19T11:26:16.387Z",
"app/advanced-development/workflows/compensation-function/page.mdx": "2024-07-31T17:01:33+03:00",
"app/advanced-development/modules/service-factory/page.mdx": "2024-07-26T14:40:56+00:00",
"app/advanced-development/data-models/primary-key/page.mdx": "2024-07-02T12:34:44+03:00",
"app/advanced-development/modules/module-links/page.mdx": "2024-07-24T09:16:01+02:00",
"app/advanced-development/data-models/searchable-property/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/searchable-property/page.mdx": "2024-09-19T08:48:53.599Z",
"app/advanced-development/scheduled-jobs/execution-number/page.mdx": "2024-07-02T09:41:15+00:00",
"app/advanced-development/api-routes/parameters/page.mdx": "2024-09-11T10:44:13.491Z",
"app/advanced-development/api-routes/http-methods/page.mdx": "2024-09-11T10:43:33.169Z",
@@ -63,9 +63,9 @@ export const generatedEditDates = {
"app/advanced-development/api-routes/middlewares/page.mdx": "2024-09-11T10:45:31.861Z",
"app/advanced-development/modules/isolation/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/configure-properties/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/index/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/index/page.mdx": "2024-09-19T08:47:12.961Z",
"app/advanced-development/custom-cli-scripts/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/property-types/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/property-types/page.mdx": "2024-09-19T07:31:20.696Z",
"app/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-09-11T10:48:09.593Z",
"app/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-09-10T11:39:51.170Z",
"app/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2024-09-10T11:39:51.171Z",

View File

@@ -326,7 +326,7 @@ export const sidebar = numberSidebarItems(
{
type: "link",
path: "/advanced-development/data-models/index",
title: "Index",
title: "Define Index",
},
{
type: "link",