docs: improved data model docs (#11884)
* docs: improved data model docs * fix build errors
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Configure Data Model Properties`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn how to configure data model properties.
|
||||
|
||||
## Property’s 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 property’s 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 property’s 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 can’t have the same email.
|
||||
@@ -1,13 +0,0 @@
|
||||
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.
|
||||
@@ -6,35 +6,11 @@ export const metadata = {
|
||||
|
||||
In this chapter, you’ll learn how to define a database index on a data model.
|
||||
|
||||
## Define Database Index on Property
|
||||
<Note>
|
||||
|
||||
Use the `index` method on a property's definition to define a database index.
|
||||
You can also define an index on a property as explained in the [Properties chapter](../properties/page.mdx#define-database-index-on-property).
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
</Note>
|
||||
|
||||
## Define Database Index on Data Model
|
||||
|
||||
@@ -73,7 +49,7 @@ An index can have conditions. For example:
|
||||
|
||||
export const conditionHighlights = [
|
||||
["10", "where", "Specify conditions on properties."],
|
||||
["11", "", "Create the index when `age` is `30`."]
|
||||
["11", "age", "Create the index when `age` is `30`."]
|
||||
]
|
||||
|
||||
```ts highlights={conditionHighlights}
|
||||
@@ -102,7 +78,7 @@ In the example above, the composite index is created on the `name` and `age` pro
|
||||
A property's condition can be a negation. For example:
|
||||
|
||||
export const negationHighlights = [
|
||||
["12", "", "Create the index when `age` is not `null`."]
|
||||
["12", "$ne", "Create the index when `age` is not `null`."]
|
||||
]
|
||||
|
||||
```ts highlights={negationHighlights}
|
||||
|
||||
@@ -8,7 +8,7 @@ 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.
|
||||
Consider you have a `Post` 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 `InferTypeOf` that transforms your data model to a type.
|
||||
|
||||
@@ -16,26 +16,26 @@ For example:
|
||||
|
||||
```ts
|
||||
import { InferTypeOf } from "@medusajs/framework/types"
|
||||
import { MyCustom } from "../models/my-custom" // relative path to the model
|
||||
import { Post } from "../modules/blog/models/post" // relative path to the model
|
||||
|
||||
export type MyCustom = InferTypeOf<typeof MyCustom>
|
||||
export type Post = InferTypeOf<typeof Post>
|
||||
```
|
||||
|
||||
`InferTypeOf` 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`.
|
||||
Since the `Post` 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:
|
||||
You can now use the `Post` 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"
|
||||
import { Post } from "../models/post"
|
||||
|
||||
type MyCustom = InferTypeOf<typeof MyCustom>
|
||||
type Post = InferTypeOf<typeof Post>
|
||||
|
||||
class HelloModuleService extends MedusaService({ MyCustom }) {
|
||||
async doSomething(): Promise<MyCustom> {
|
||||
class BlogModuleService extends MedusaService({ Post }) {
|
||||
async doSomething(): Promise<Post> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,114 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Data Models Advanced Guides`,
|
||||
title: `${pageNumber} Data Models`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
Data models are created and managed in a module. To learn how to create a data model in a custom module, refer to the [Modules chapter](../modules/page.mdx).
|
||||
In this chapter, you'll learn what a data model is and how to create a data model.
|
||||
|
||||
In the next chapters, you'll learn about defining data models in more details. You'll learn about:
|
||||
## What is a Data Model?
|
||||
|
||||
- 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.
|
||||
A data model represents a table in the database. You create data models using Medusa's data modeling language (DML). It simplifies defining a table's columns, relations, and indexes with straightforward methods and configurations.
|
||||
|
||||
You create a data model in a [module](../modules/page.mdx). The module's service provides the methods to store and manage those data models. Then, you can resolve the module's service in other customizations, such as a [workflow](../workflows/page.mdx), to manage the data models' records.
|
||||
|
||||
---
|
||||
|
||||
## How to Create a Data Model
|
||||
|
||||
In a module, you can create a data model in a TypeScript or JavaScript file under the module's `models` directory.
|
||||
|
||||
So, for example, assuming you have a Blog Module at `src/modules/blog`, you can create a `Post` data model by creating the `src/modules/blog/models/post.ts` file with the following content:
|
||||
|
||||

|
||||
|
||||
```ts title="src/modules/blog/models/post.ts"
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Post = model.define("post", {
|
||||
id: model.id().primaryKey(),
|
||||
title: model.text(),
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
You define the data model using the `define` method of the DML. It accepts two parameters:
|
||||
|
||||
1. The first one is the name of the data model's table in the database. Use snake-case names.
|
||||
2. The second is an object, which is the data model's schema. The schema's properties are defined using the `model`'s methods, such as `text` and `id`.
|
||||
- Data models automatically have the date properties `created_at`, `updated_at`, and `deleted_at`, so you don't need to add them manually.
|
||||
|
||||
The code snippet above defines a `Post` data model with `id` and `title` properties.
|
||||
|
||||
---
|
||||
|
||||
## Generate Migrations
|
||||
|
||||
After you create a data model in a module, then [register that module in your Medusa configurations](../modules/page.mdx#4-add-module-to-medusas-configurations), you must generate a migration to create the data model's table in the database.
|
||||
|
||||
A migration is a TypeScript or JavaScript file that defines database changes made by a module. Migrations are useful when you re-use a module or you're working in a team, so that when one member of a team makes a database change, everyone else can reflect it on their side by running the migrations.
|
||||
|
||||
For example, to generate a migration for the Blog Module, run the following command in your Medusa application's directory:
|
||||
|
||||
<Note>
|
||||
|
||||
If you're creating the module in a plugin, use the [plugin\:db\:generate command](!resources!/medusa-cli/commands/plugin#plugindbgenerate) instead.
|
||||
|
||||
</Note>
|
||||
|
||||
```bash
|
||||
npx medusa db:generate blog
|
||||
```
|
||||
|
||||
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
|
||||
|
||||
```ts
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20241121103722 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql("create table if not exists \"post\" (\"id\" text not null, \"title\" text not null, \"created_at\" timestamptz not null default now(), \"updated_at\" timestamptz not null default now(), \"deleted_at\" timestamptz null, constraint \"post_pkey\" primary key (\"id\"));")
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql("drop table if exists \"post\" cascade;")
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
In the migration class, the `up` method creates the table `post` and defines its columns using PostgreSQL syntax. The `down` method drops the table.
|
||||
|
||||
### Run Migrations
|
||||
|
||||
To reflect the changes in the generated migration file on the database, run the `db:migrate` command:
|
||||
|
||||
<Note>
|
||||
|
||||
If you're creating the module in a plugin, run this command on the Medusa application that the plugin is installed in.
|
||||
|
||||
</Note>
|
||||
|
||||
```bash
|
||||
npx medusa db:migrate
|
||||
```
|
||||
|
||||
This creates the `post` table in the database.
|
||||
|
||||
### Migrations on Data Model Changes
|
||||
|
||||
Whenever you make a change to a data model, you must generate and run the migrations.
|
||||
|
||||
For example, if you add a new column to the `Post` data model, you must generate a new migration and run it.
|
||||
|
||||
---
|
||||
|
||||
## Manage Data Models
|
||||
|
||||
Your module's service should extend the [service factory](../modules/service-factory/page.mdx), which generates data-management methods for your module's data models.
|
||||
|
||||
For example, the Blog Module's service would have methods like `retrievePost` and `createPosts`.
|
||||
|
||||
Refer to the [Service Factory](../modules/service-factory/page.mdx) chapter to learn more about how to extend the service factory and manage data models, and refer to the [Service Factory Reference](!resources!/service-factory-reference) for the full list of generated methods and how to use them.
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Data Model’s Primary Key`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll 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,412 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Data Model Properties`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn about the different property types you can use in a data model and how to configure a data model's properties.
|
||||
|
||||
## Data Model's Default Properties
|
||||
|
||||
By default, Medusa creates the following properties for every data model:
|
||||
|
||||
- `created_at`: A [dateTime](#dateTime) property that stores when a record of the data model was created.
|
||||
- `updated_at`: A [dateTime](#dateTime) property that stores when a record of the data model was updated.
|
||||
- `deleted_at`: A [dateTime](#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.
|
||||
|
||||
---
|
||||
|
||||
## Property Types
|
||||
|
||||
This section covers the different property types you can define in a data model's schema using the `model` methods.
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
id: model.id(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
name: model.text(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
age: model.number(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### float
|
||||
|
||||
<Note>
|
||||
|
||||
This property is only available after [Medusa v2.1.2](https://github.com/medusajs/medusa/releases/tag/v2.1.2).
|
||||
|
||||
</Note>
|
||||
|
||||
The `float` method defines a number property that allows for values with decimal places.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Use this property type when it's less important to have high precision for numbers with large decimal places. Alternatively, for higher percision, use the [bigNumber property](#bignumber).
|
||||
|
||||
</Note>
|
||||
|
||||
For example:
|
||||
|
||||
export const floatHighlights = [["4", "float", "Define a `float` property."]]
|
||||
|
||||
```ts highlights={floatHighlights}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Post = model.define("post", {
|
||||
rating: model.float(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### bigNumber
|
||||
|
||||
The `bigNumber` method defines a number property that expects large numbers, such as prices.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Use this property type when it's important to have high precision for numbers with large decimal places. Alternatively, for less percision, use the [float property](#float).
|
||||
|
||||
</Note>
|
||||
|
||||
For example:
|
||||
|
||||
export const bigNumberHighlights = [["4", "bigNumber", "Define a `bigNumber` property."]]
|
||||
|
||||
```ts highlights={bigNumberHighlights}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Post = model.define("post", {
|
||||
price: model.bigNumber(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
hasAccount: model.boolean(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
color: model.enum(["black", "white"]),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
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 Post = model.define("post", {
|
||||
date_of_birth: model.dateTime(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
metadata: model.json(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### 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 Post = model.define("post", {
|
||||
names: model.array(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### Properties Reference
|
||||
|
||||
Refer to the [Data Model Language (DML) reference](!resources!/references/data-model) for a full reference of the properties.
|
||||
|
||||
---
|
||||
|
||||
## Set Primary Key Property
|
||||
|
||||
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 Post = model.define("post", {
|
||||
id: model.id().primaryKey(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
In the example above, the `id` property is defined as the data model's primary key.
|
||||
|
||||
---
|
||||
|
||||
## Property 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 Post = model.define("post", {
|
||||
color: model
|
||||
.enum(["black", "white"])
|
||||
.default("black"),
|
||||
age: model
|
||||
.number()
|
||||
.default(0),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
In this example, you set the default value of the `color` enum property to `black`, and that of the `age` number property to `0`.
|
||||
|
||||
---
|
||||
|
||||
## Make Property Optional
|
||||
|
||||
Use the `nullable` method to indicate that a property’s value can be `null`. This is useful when you want a property to be optional.
|
||||
|
||||
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 Post = model.define("post", {
|
||||
price: model.bigNumber().nullable(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
In the example above, the `price` property is configured to allow `null` values, making it optional.
|
||||
|
||||
---
|
||||
|
||||
## Unique Property
|
||||
|
||||
The `unique` method indicates that a property’s 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 can’t have the same email.
|
||||
|
||||
---
|
||||
|
||||
## Define Database Index on Property
|
||||
|
||||
Use the `index` method on a property's definition to define a database index.
|
||||
|
||||
For example:
|
||||
|
||||
export const dbIndexHighlights = [
|
||||
["5", "index", "Define an index on the `name` property."],
|
||||
["6", '"IDX_MY_CUSTOM_NAME"', "Index name is optional."]
|
||||
]
|
||||
|
||||
```ts highlights={dbIndexHighlights}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Post = model.define("post", {
|
||||
id: model.id().primaryKey(),
|
||||
name: model.text().index(
|
||||
"IDX_MY_CUSTOM_NAME"
|
||||
),
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
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 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.
|
||||
|
||||
Use the `searchable` method on a `text` property to indicate that it's searchable.
|
||||
|
||||
For example:
|
||||
|
||||
export const searchableHighlights = [
|
||||
["4", "searchable", "Define the `title` property as searchable."]
|
||||
]
|
||||
|
||||
```ts highlights={searchableHighlights}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Post = model.define("post", {
|
||||
title: model.text().searchable(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
In this example, the `title` property is searchable.
|
||||
|
||||
### Search Example
|
||||
|
||||
If you pass a `q` filter to the `listPosts` method:
|
||||
|
||||
```ts
|
||||
const posts = await blogModuleService.listPosts({
|
||||
q: "New Products",
|
||||
})
|
||||
```
|
||||
|
||||
This retrieves records that include `New Products` in their `title` property.
|
||||
@@ -1,241 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Data Model Property Types`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn about the types of properties in a data model’s schema.
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## float
|
||||
|
||||
<Note>
|
||||
|
||||
This property is only available after [Medusa v2.1.2](https://github.com/medusajs/medusa/releases/tag/v2.1.2).
|
||||
|
||||
</Note>
|
||||
|
||||
The `float` method defines a number property that allows for values with decimal places.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Use this property type when it's less important to have high precision for numbers with large decimal places. Alternatively, for higher percision, use the [bigNumber property](#bignumber).
|
||||
|
||||
</Note>
|
||||
|
||||
For example:
|
||||
|
||||
export const floatHighlights = [["4", "float", "Define a `float` property."]]
|
||||
|
||||
```ts highlights={floatHighlights}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const MyCustom = model.define("my_custom", {
|
||||
rating: model.float(),
|
||||
// ...
|
||||
})
|
||||
|
||||
export default MyCustom
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## bigNumber
|
||||
|
||||
The `bigNumber` method defines a number property that expects large numbers, such as prices.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Use this property type when it's important to have high precision for numbers with large decimal places. Alternatively, for less percision, use the [float property](#float).
|
||||
|
||||
</Note>
|
||||
|
||||
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](!resources!/references/data-model) for a full reference of the properties.
|
||||
@@ -67,7 +67,7 @@ The `belongsTo` method also requires passing as a second parameter an object wit
|
||||
|
||||
### Optional Relationship
|
||||
|
||||
To make the relationship optional on the `hasOne` or `belongsTo` side, use the `nullable` method on either property as explained in [this chapter](../configure-properties/page.mdx#nullable-property).
|
||||
To make the relationship optional on the `hasOne` or `belongsTo` side, use the `nullable` method on either property as explained in [this chapter](../properties/page.mdx#make-property-optional).
|
||||
|
||||
### One-sided One-to-One Relationship
|
||||
|
||||
@@ -142,7 +142,7 @@ 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).
|
||||
To make the relationship optional on the `belongsTo` side, use the `nullable` method on the property as explained in [this chapter](../properties/page.mdx#make-property-optional).
|
||||
|
||||
### One-to-Many Relationship in the Database
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
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.
|
||||
@@ -1,32 +1,46 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Write Migration`,
|
||||
title: `${pageNumber} Migrations`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn how to create a migration and write it manually.
|
||||
In this chapter, you'll learn what a migration is and how to generate a migration or 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:
|
||||
A migration is a TypeScript or JavaScript file that defines database changes made by a module. Migrations are useful when you re-use a module or you're working in a team, so that when one member of a team makes a database change, everyone else can reflect it on their side by running the migrations.
|
||||
|
||||
The migration's file has a class with 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?
|
||||
## Generate 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.
|
||||
Instead of you writing the migration manually, the Medusa CLI tool provides a [db:generate](!resources!/medusa-cli/commands/db#dbgenerate) command to generate a migration for a modules' data models.
|
||||
|
||||
Alternatively, you can manually create a migration file under the `migrations` directory of your module.
|
||||
For example, assuming you have a `blog` Module, you can generate a migration for it by running the following command:
|
||||
|
||||
```bash
|
||||
npx medusa db:generate blog
|
||||
```
|
||||
|
||||
This generates a migration file under the `migrations` directory of the Blog Module. You can then run it to reflect the changes in the database as mentioned in [this section](#run-the-migration).
|
||||
|
||||
---
|
||||
|
||||
## Write a Migration Manually
|
||||
|
||||
You can also write migrations manually. To do that, create a file in the `migrations` directory of the module and in it, a class that has an `up` and `down` method. The class's name should be of the format `Migration{YEAR}{MONTH}{DAY}{HOUR}{MINUTE}.ts` to ensure migrations are ran in the correct order.
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/modules/blog/migrations/Migration20240429.ts"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20240702105919 extends Migration {
|
||||
export class Migration202507021059 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
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\"));")
|
||||
@@ -39,9 +53,7 @@ export class Migration20240702105919 extends Migration {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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 `author`, and the `down` method drops the table if the migration is reverted.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user