docs: add routing page (#9550)

- Add a new homepage to `book` project for the routing page
- Move all main doc pages to be under `/v2/learn` (and added redirects + fixed links across docs)
- Other: add admin components to resources dropdown + fixes to search on mobile.

Closes DX-955

Preview: https://docs-v2-git-docs-router-page-medusajs.vercel.app/v2
This commit is contained in:
Shahed Nasser
2024-10-18 08:24:34 +00:00
committed by GitHub
parent 7a47f5211d
commit 0a37675f0e
223 changed files with 2549 additions and 696 deletions
@@ -0,0 +1,84 @@
export const metadata = {
title: `${pageNumber} Configure Data Model Properties`,
}
# {metadata.title}
In this chapter, youll learn how to configure data model properties.
## Propertys Default Value
Use the `default` method on a property's definition to specify the default value of a property.
For example:
export const defaultHighlights = [
["6", "default", "Set the default value to `black`."],
["9", "default", "Set the default value to `0`."]
]
```ts highlights={defaultHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
color: model
.enum(["black", "white"])
.default("black"),
age: model
.number()
.default(0),
// ...
})
export default MyCustom
```
In this example, you set the default value of the `color` enum property to `black`, and that of the `age` number property to `0`.
---
## Nullable Property
Use the `nullable` method to indicate that a propertys value can be `null`.
For example:
export const nullableHighlights = [
["4", "nullable", "Configure the `price` property to allow `null` values."]
]
```ts highlights={nullableHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
price: model.bigNumber().nullable(),
// ...
})
export default MyCustom
```
---
## Unique Property
The `unique` method indicates that a propertys value must be unique in the database through a unique index.
For example:
export const uniqueHighlights = [
["4", "unique", "Configure the `email` property to allow unique values only."]
]
```ts highlights={uniqueHighlights}
import { model } from "@medusajs/framework/utils"
const User = model.define("user", {
email: model.text().unique(),
// ...
})
export default User
```
In this example, multiple users cant have the same email.
@@ -0,0 +1,13 @@
export const metadata = {
title: `${pageNumber} Data Model Default Properties`,
}
# {metadata.title}
In this chapter, you'll learn about the properties available by default in your data model.
When you create a data model, the following properties are created for you by Medusa:
- `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 soft-delete a record, Medusa sets the `deleted_at` property to the current date.
@@ -0,0 +1,160 @@
export const metadata = {
title: `${pageNumber} Data Model Database Index`,
}
# {metadata.title}
In this chapter, youll learn how to define a database index on a data model.
## Define Database Index on Property
Use the `index` method on a property's definition to define a database index.
For example:
export const highlights = [
["5", "index", "Define an index on the `name` property."],
["6", '"IDX_MY_CUSTOM_NAME"', "Index name is optional."]
]
```ts highlights={highlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text().index(
"IDX_MY_CUSTOM_NAME"
),
})
export default MyCustom
```
The `index` method optionally accepts the name of the index as a parameter.
In this example, you define an index on the `name` property.
---
## Define Database Index on Data Model
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:
export const dataModelIndexHighlights = [
["7", "indexes", "Define indices on the data model's properties."],
["9", "on", "Specify the properties to define the index on."]
]
```ts highlights={dataModelIndexHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text(),
age: model.number(),
}).indexes([
{
on: ["name", "age"],
},
])
export default MyCustom
```
The `indexes` method receives an array of indices as a parameter. Each index is an object with a required `on` property indicating the properties to apply the index on.
In the above example, you define a composite index on the `name` and `age` properties.
### Index Conditions
An index can have conditions. For example:
export const conditionHighlights = [
["10", "where", "Specify conditions on properties."],
["11", "", "Create the index when `age` is `30`."]
]
```ts highlights={conditionHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text(),
age: model.number(),
}).indexes([
{
on: ["name", "age"],
where: {
age: 30,
},
},
])
export default MyCustom
```
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`.
A property's condition can be a negation. For example:
export const negationHighlights = [
["12", "", "Create the index when `age` is not `null`."]
]
```ts highlights={negationHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text(),
age: model.number().nullable(),
}).indexes([
{
on: ["name", "age"],
where: {
age: {
$ne: null,
},
},
},
])
export default MyCustom
```
A property's value in `where` can be an object having a `$ne` property. `$ne`'s value indicates what the specified property's value shouldn't be.
In the example above, the composite index is created on the `name` and `age` properties when `age`'s value is not `null`.
### Unique Database Index
The object passed to `indexes` accepts a `unique` property indicating that the created index must be a unique index.
For example:
export const uniqueHighlights = [
["10", "unique", "Specify if the index is a unique index."]
]
```ts highlights={uniqueHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text(),
age: model.number(),
}).indexes([
{
on: ["name", "age"],
unique: true,
},
])
export default MyCustom
```
This creates a unique composite index on the `name` and `age` properties.
@@ -0,0 +1,42 @@
export const metadata = {
title: `${pageNumber} Infer Type of Data Model`,
}
# {metadata.title}
In this chapter, you'll learn how to infer the type of a data model.
## How to Infer Type of Data Model?
Consider you have a `MyCustom` data model. You can't reference this data model in a type, such as a workflow input or service method output types, since it's a variable.
Instead, Medusa provides an `InferTypeOf` utility imported from `@medusajs/framework/types` that transforms your data model to a type.
For example:
```ts
import { InferTypeOf } from "@medusajs/framework/types"
import { MyCustom } from "../models/my-custom" // relative path to the model
export type MyCustom = InferTypeOf<typeof MyCustom>
```
The `InferTypeOf` utility accepts as a type argument the type of the data model.
Since the `MyCustom` data model is a variable, use the `typeof` operator to pass the data model as a type argument to `InferTypeOf`.
You can now use the `MyCustom` type to reference a data model in other types, such as in workflow inputs or service method outputs:
```ts title="Example Service"
// other imports...
import { InferTypeOf } from "@medusajs/framework/types"
import { MyCustom } from "../models/my-custom"
type MyCustom = InferTypeOf<typeof MyCustom>
class HelloModuleService extends MedusaService({ MyCustom }) {
async doSomething(): Promise<MyCustom> {
// ...
}
}
```
@@ -0,0 +1,202 @@
import { BetaBadge } from "docs-ui"
export const metadata = {
title: `${pageNumber} Manage Relationships`,
}
# {metadata.title} <BetaBadge tooltipText="Data model relationships are in active development and may change." text="Beta" />
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 Relationship
### BelongsTo Side of One-to-One
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", "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.createEmails({
// other properties...
user: "123",
})
// when updating an email
const email = await helloModuleService.updateEmails({
id: "321",
// other properties...
user: "123",
})
```
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
### Create Associations
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", "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.createProducts({
// other properties...
orders: ["123", "321"],
})
// when creating an order
const order = await helloModuleService.createOrders({
id: "321",
// other properties...
products: ["123", "321"],
})
```
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.
---
## Retrieve Records of Relation
The `list`, `listAndCount`, and `retrieve` methods of a module's main service accept as a second parameter an object of options.
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), 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.retrieveProducts(
"123",
{
relations: ["orders"],
}
)
```
In the example above, the retrieved product has an `orders` property, whose value is an array of orders associated with the product.
@@ -0,0 +1,15 @@
export const metadata = {
title: `${pageNumber} Data Models Advanced Guides`,
}
# {metadata.title}
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.
@@ -0,0 +1,30 @@
export const metadata = {
title: `${pageNumber} Data Models Primary Key`,
}
# {metadata.title}
In this chapter, youll learn how to configure the primary key of a data model.
## primaryKey Method
To set any `id`, `text`, or `number` property as a primary key, use the `primaryKey` method.
For example:
export const highlights = [
["4", "primaryKey", "Define the `id` property to be the data model's primary key."]
]
```ts highlights={highlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
// ...
})
export default MyCustom
```
In the example above, the `id` property is defined as the data model's primary key.
@@ -0,0 +1,204 @@
export const metadata = {
title: `${pageNumber} Data Model Property Types`,
}
# {metadata.title}
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/framework/utils`.
## id
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:
export const idHighlights = [["4", ".id()", "Define an `id` property."]]
```ts highlights={idHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id(),
// ...
})
export default MyCustom
```
---
## text
The `text` method defines a string property.
For example:
export const textHighlights = [["4", "text", "Define a `text` property."]]
```ts highlights={textHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
name: model.text(),
// ...
})
export default MyCustom
```
---
## number
The `number` method defines a number property.
For example:
export const numberHighlights = [["4", "number", "Define a `number` property."]]
```ts highlights={numberHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
age: model.number(),
// ...
})
export default MyCustom
```
---
## bigNumber
The `bigNumber` method defines a number property that expects large numbers, such as prices.
For example:
export const bigNumberHighlights = [["4", "bigNumber", "Define a `bigNumber` property."]]
```ts highlights={bigNumberHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
price: model.bigNumber(),
// ...
})
export default MyCustom
```
---
## boolean
The `boolean` method defines a boolean property.
For example:
export const booleanHighlights = [["4", "boolean", "Define a `boolean` property."]]
```ts highlights={booleanHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
hasAccount: model.boolean(),
// ...
})
export default MyCustom
```
---
### enum
The `enum` method defines a property whose value can only be one of the specified values.
For example:
export const enumHighlights = [["4", "enum", "Define a `enum` property."]]
```ts highlights={enumHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
color: model.enum(["black", "white"]),
// ...
})
export default MyCustom
```
The `enum` method accepts an array of possible string values.
---
## dateTime
The `dateTime` method defines a timestamp property.
For example:
export const dateTimeHighlights = [["4", "dateTime", "Define a `dateTime` property."]]
```ts highlights={dateTimeHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
date_of_birth: model.dateTime(),
// ...
})
export default MyCustom
```
---
## json
The `json` method defines a property whose value is a stringified JSON object.
For example:
export const jsonHighlights = [["4", "json", "Define a `json` property."]]
```ts highlights={jsonHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
metadata: model.json(),
// ...
})
export default MyCustom
```
---
## array
The `array` method defines an array of strings property.
For example:
export const arrHightlights = [["4", "array", "Define an `array` property."]]
```ts highlights={arrHightlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
names: model.array(),
// ...
})
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.
@@ -0,0 +1,252 @@
import { BetaBadge } from "docs-ui"
export const metadata = {
title: `${pageNumber} Data Model Relationships`,
}
# {metadata.title} <BetaBadge text="Beta" tooltipText="Data model relationships are in active development and may change." />
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.
</Note>
<Note title="Don't use data model relationships if" type="error">
You want to create a relationship between data models in different modules. Use module links instead.
</Note>
---
## 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.
2. `belongsTo`: indicates that the model belongs to one record of the specified model.
For example:
export const oneToOneHighlights = [
["5", "hasOne", "A user has one email."],
["10", "belongsTo", "An email belongs to a user."],
["11", `"email"`, "The relationship's name in the `User` data model."]
]
```ts highlights={oneToOneHighlights}
import { model } from "@medusajs/framework/utils"
const User = model.define("user", {
id: model.id().primaryKey(),
email: model.hasOne(() => Email),
})
const Email = model.define("email", {
id: model.id().primaryKey(),
user: model.belongsTo(() => User, {
mappedBy: "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.
### 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.
2. `belongsTo`: indicates that the model belongs to one record of the specified model.
For example:
export const oneToManyHighlights = [
["5", "hasMany", "A store has many products"],
["10", "belongsTo", "A product has one store."],
["11", `"products"`, "The relationship's name in the `Store` data model."]
]
```ts highlights={oneToManyHighlights}
import { model } from "@medusajs/framework/utils"
const Store = model.define("store", {
id: model.id().primaryKey(),
products: model.hasMany(() => Product),
})
const Product = model.define("product", {
id: model.id().primaryKey(),
store: model.belongsTo(() => Store, {
mappedBy: "products",
}),
})
```
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:
export const manyToManyHighlights = [
["5", "manyToMany", "An order is associated with many products."],
["12", "manyToMany", "A product is associated with many orders."]
]
```ts highlights={manyToManyHighlights}
import { model } from "@medusajs/framework/utils"
const Order = model.define("order", {
id: model.id().primaryKey(),
products: model.manyToMany(() => Product, {
mappedBy: "orders",
}),
})
const Product = model.define("product", {
id: model.id().primaryKey(),
orders: model.manyToMany(() => Order, {
mappedBy: "products",
}),
})
```
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)
---
## 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:
export const relationNameHighlights = [
["6", `"owner"`, "The relationship's name in the `Email` data model."],
["13", `"email"`, "The relationship's name in the `User` data model."]
]
```ts highlights={relationNameHighlights}
import { model } from "@medusajs/framework/utils"
const User = model.define("user", {
id: model.id().primaryKey(),
email: model.hasOne(() => Email, {
mappedBy: "owner",
}),
})
const Email = model.define("email", {
id: model.id().primaryKey(),
owner: model.belongsTo(() => User, {
mappedBy: "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`.
---
## Cascades
When an operation is performed on a data model, such as record deletion, the relationship cascade specifies what related data model records should be affected by it.
For example, if a store is deleted, its products should also be deleted.
The `cascades` method used on a data model configures which child records an operation is cascaded to.
For example:
export const highlights = [
["8", "", "When a store is deleted, delete its associated products."]
]
```ts highlights={highlights}
import { model } from "@medusajs/framework/utils"
const Store = model.define("store", {
id: model.id().primaryKey(),
products: model.hasMany(() => Product),
})
.cascades({
delete: ["products"],
})
const Product = model.define("product", {
id: model.id().primaryKey(),
store: model.belongsTo(() => Store, {
mappedBy: "products",
}),
})
```
The `cascades` method accepts an object. Its key is the operations name, such as `delete`. The value is an array of relationship property names that the operation is cascaded to.
In the example above, when a store is deleted, its associated products are also deleted.
@@ -0,0 +1,50 @@
export const metadata = {
title: `${pageNumber} Searchable Data Model Property`,
}
# {metadata.title}
In this chapter, you'll learn what a searchable property is and how to define it.
## What is a Searchable Property?
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 data model's searchable properties are queried to find matching records.
---
## Define a Searchable Property
Use the `searchable` method on a `text` property to indicate that it's searchable.
For example:
export const searchableHighlights = [
["4", "searchable", "Define the `name` property as searchable."]
]
```ts highlights={searchableHighlights}
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
name: model.text().searchable(),
// ...
})
export default MyCustom
```
In this example, the `name` property is searchable.
### Search Example
If you pass a `q` filter to the `listMyCustoms` method:
```ts
const myCustoms = await helloModuleService.listMyCustoms({
q: "John",
})
```
This retrieves records that include `John` in their `name` property.
@@ -0,0 +1,70 @@
export const metadata = {
title: `${pageNumber} Write Migration`,
}
# {metadata.title}
In this chapter, you'll learn how to create a migration and write it manually.
## What is a Migration?
A migration is a class created in a TypeScript or JavaScript file under a module's `migrations` directory. It has two methods:
- The `up` method reflects changes on the database.
- The `down` method reverts the changes made in the `up` method.
---
## How to Write a Migration?
The Medusa CLI tool provides a [db:generate](!resources!/medusa-cli/commands/db#dbgenerate) command to generate a migration for the specified modules' data models.
Alternatively, you can manually create a migration file under the `migrations` directory of your module.
For example:
```ts title="src/modules/hello/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\"));")
}
async down(): Promise<void> {
this.addSql("drop table if exists \"my_custom\" cascade;")
}
}
```
The migration's file name should be of the format `Migration{YEAR}{MONTH}{DAY}.ts`. The migration class in the file extends the `Migration` class imported from `@mikro-orm/migrations`.
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.
<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
To run your migration, run the following command:
<Note>
This command also syncs module links. If you don't want that, use the `--skip-links` option.
</Note>
```bash
npx medusa db:migrate
```
This reflects the changes in the database as implemented in the migration's `up` method.