From 5a01ef89ead59d425b2079d28b9bdcd2d2daea22 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 25 Jul 2025 17:22:37 +0300 Subject: [PATCH] docs: document checks examples + migrations naming convention (#13052) --- .../data-models/check-constraints/page.mdx | 62 +++++++++++++ .../data-models/properties/page.mdx | 26 ++++++ .../data-models/write-migration/page.mdx | 8 +- www/apps/book/generated/edit-dates.mjs | 6 +- www/apps/book/public/llms-full.txt | 92 ++++++++++++++++++- 5 files changed, 189 insertions(+), 5 deletions(-) diff --git a/www/apps/book/app/learn/fundamentals/data-models/check-constraints/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/check-constraints/page.mdx index fc6b1dd15d..798664a4de 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/check-constraints/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/check-constraints/page.mdx @@ -84,3 +84,65 @@ npx medusa db:migrate ``` The first command generates the migration under the `migrations` directory of your module's directory, and the second reflects it on the database. + +--- + +## Examples + +This section covers common use cases where check constraints are particularly useful. + +### 1. Enforce Text Length + +Ensure that text properties meet minimum or maximum length requirements: + +```ts +const User = model.define("user", { + username: model.text(), + password: model.text(), +}) +.checks([ + { + name: "password_length_check", + expression: (columns) => `LENGTH(${columns.password}) >= 8`, + }, +]) +``` + +In the above example, the check constraint fails if the `password` property is less than 8 characters long. + +### 2. Validate Email Format + +Ensure email addresses contain the `@` symbol: + +```ts +const Customer = model.define("customer", { + email: model.text(), +}) +.checks([ + { + name: "email_format_check", + expression: (columns) => `${columns.email} LIKE '%@%'`, + }, +]) +``` + +In the above example, the check constraint fails if the `email` property does not contain the `@` symbol. + +### 3. Enforce Date Ranges + +Ensure dates fall within valid ranges: + +```ts +const Event = model.define("event", { + start_date: model.dateTime(), + end_date: model.dateTime(), +}) +.checks([ + { + name: "date_order_check", + expression: (columns) => `${columns.end_date} >= ${columns.start_date}`, + }, +]) +``` + +In the above example, the check constraint fails if the `end_date` is earlier than the `start_date`. \ No newline at end of file diff --git a/www/apps/book/app/learn/fundamentals/data-models/properties/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/properties/page.mdx index d2ab8e51c2..fd0bfec50a 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/properties/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/properties/page.mdx @@ -58,6 +58,32 @@ const Post = model.define("post", { export default Post ``` +#### Limit Text Length + +To limit the allowed length of a `text` property, use the [checks method](../check-constraints/page.mdx). + +For example, to limit the `name` property to a maximum of 50 characters: + +export const textLengthHighlights = [ + ["7", "checks", "Add check constraints to the data model."], +] + +```ts highlights={textLengthHighlights} +import { model } from "@medusajs/framework/utils" + +const Post = model.define("post", { + name: model.text(), + // ... +}) +.checks([ + (columns) => `${columns.name.length} <= 50`, +]) + +export default Post +``` + +This will add a database check constraint that ensures the `name` property of a record does not exceed 50 characters. If a record with a longer `name` is attempted to be inserted, an error will be thrown. + ### number The `number` method defines a number property. diff --git a/www/apps/book/app/learn/fundamentals/data-models/write-migration/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/write-migration/page.mdx index bfab5f82b7..5c1c5ca0de 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/write-migration/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/write-migration/page.mdx @@ -37,7 +37,7 @@ You can also write migrations manually. To do that, create a file in the `migrat For example: -```ts title="src/modules/blog/migrations/Migration202507021059.ts" +```ts title="src/modules/blog/migrations/Migration202507021059_create_author.ts" import { Migration } from "@mikro-orm/migrations" export class Migration202507021059 extends Migration { @@ -63,6 +63,12 @@ Refer to [MikroORM's documentation](https://mikro-orm.io/docs/migrations#migrati +### Migration File Naming + +Migrations are executed in the ascending order of their file names. So, it's recommended to prefix the migration file name with the timestamp of when the migration was created. This ensures that migrations are executed in the order they were created. + +For example, if you create a migration on July 2, 2025, at 10:59 AM, the file name should be `Migration202507021059_create_brand.ts`. This way, the migration will be executed after any previous migrations that were created before this date and time. + --- ## Run the Migration diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index bab5534b84..0bc9ba6a51 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -32,7 +32,7 @@ export const generatedEditDates = { "app/learn/fundamentals/admin/page.mdx": "2025-07-25T12:46:15.466Z", "app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2025-07-14T10:32:21.640Z", "app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2025-04-24T13:18:24.184Z", - "app/learn/fundamentals/data-models/write-migration/page.mdx": "2025-07-23T15:32:18.008Z", + "app/learn/fundamentals/data-models/write-migration/page.mdx": "2025-07-25T13:53:00.692Z", "app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2025-04-25T14:16:41.124Z", "app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00", "app/learn/fundamentals/modules/options/page.mdx": "2025-03-18T15:12:34.510Z", @@ -97,7 +97,7 @@ export const generatedEditDates = { "app/learn/deployment/general/page.mdx": "2025-06-20T08:36:05.063Z", "app/learn/fundamentals/workflows/multiple-step-usage/page.mdx": "2024-11-25T16:19:32.169Z", "app/learn/installation/page.mdx": "2025-07-23T14:28:50.404Z", - "app/learn/fundamentals/data-models/check-constraints/page.mdx": "2024-12-06T14:34:50.384Z", + "app/learn/fundamentals/data-models/check-constraints/page.mdx": "2025-07-25T13:50:21.065Z", "app/learn/fundamentals/module-links/link/page.mdx": "2025-04-07T08:03:14.513Z", "app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-04-17T08:29:10.166Z", "app/learn/fundamentals/plugins/create/page.mdx": "2025-04-17T08:29:09.910Z", @@ -115,7 +115,7 @@ export const generatedEditDates = { "app/learn/configurations/ts-aliases/page.mdx": "2025-07-23T15:32:18.008Z", "app/learn/production/worker-mode/page.mdx": "2025-07-18T15:19:45.352Z", "app/learn/fundamentals/module-links/read-only/page.mdx": "2025-07-25T07:58:54.327Z", - "app/learn/fundamentals/data-models/properties/page.mdx": "2025-03-18T07:57:17.826Z", + "app/learn/fundamentals/data-models/properties/page.mdx": "2025-07-25T13:40:28.866Z", "app/learn/fundamentals/framework/page.mdx": "2025-06-26T14:26:22.120Z", "app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx": "2025-07-14T10:24:32.582Z", "app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z", diff --git a/www/apps/book/public/llms-full.txt b/www/apps/book/public/llms-full.txt index c2ea04a94f..ee6afd2178 100644 --- a/www/apps/book/public/llms-full.txt +++ b/www/apps/book/public/llms-full.txt @@ -8561,6 +8561,68 @@ npx medusa db:migrate The first command generates the migration under the `migrations` directory of your module's directory, and the second reflects it on the database. +*** + +## Examples + +This section covers common use cases where check constraints are particularly useful. + +### 1. Enforce Text Length + +Ensure that text properties meet minimum or maximum length requirements: + +```ts +const User = model.define("user", { + username: model.text(), + password: model.text(), +}) +.checks([ + { + name: "password_length_check", + expression: (columns) => `LENGTH(${columns.password}) >= 8`, + }, +]) +``` + +In the above example, the check constraint fails if the `password` property is less than 8 characters long. + +### 2. Validate Email Format + +Ensure email addresses contain the `@` symbol: + +```ts +const Customer = model.define("customer", { + email: model.text(), +}) +.checks([ + { + name: "email_format_check", + expression: (columns) => `${columns.email} LIKE '%@%'`, + }, +]) +``` + +In the above example, the check constraint fails if the `email` property does not contain the `@` symbol. + +### 3. Enforce Date Ranges + +Ensure dates fall within valid ranges: + +```ts +const Event = model.define("event", { + start_date: model.dateTime(), + end_date: model.dateTime(), +}) +.checks([ + { + name: "date_order_check", + expression: (columns) => `${columns.end_date} >= ${columns.start_date}`, + }, +]) +``` + +In the above example, the check constraint fails if the `end_date` is earlier than the `start_date`. + # Data Model Database Index @@ -9090,6 +9152,28 @@ const Post = model.define("post", { export default Post ``` +#### Limit Text Length + +To limit the allowed length of a `text` property, use the [checks method](https://docs.medusajs.com/learn/fundamentals/data-models/check-constraints/index.html.md). + +For example, to limit the `name` property to a maximum of 50 characters: + +```ts highlights={textLengthHighlights} +import { model } from "@medusajs/framework/utils" + +const Post = model.define("post", { + name: model.text(), + // ... +}) +.checks([ + (columns) => `${columns.name.length} <= 50`, +]) + +export default Post +``` + +This will add a database check constraint that ensures the `name` property of a record does not exceed 50 characters. If a record with a longer `name` is attempted to be inserted, an error will be thrown. + ### number The `number` method defines a number property. @@ -9733,7 +9817,7 @@ You can also write migrations manually. To do that, create a file in the `migrat For example: -```ts title="src/modules/blog/migrations/Migration202507021059.ts" +```ts title="src/modules/blog/migrations/Migration202507021059_create_author.ts" import { Migration } from "@mikro-orm/migrations" export class Migration202507021059 extends Migration { @@ -9755,6 +9839,12 @@ In the example above, the `up` method creates the table `author`, and the `down` Refer to [MikroORM's documentation](https://mikro-orm.io/docs/migrations#migration-class) for more details on writing migrations. +### Migration File Naming + +Migrations are executed in the ascending order of their file names. So, it's recommended to prefix the migration file name with the timestamp of when the migration was created. This ensures that migrations are executed in the order they were created. + +For example, if you create a migration on July 2, 2025, at 10:59 AM, the file name should be `Migration202507021059_create_brand.ts`. This way, the migration will be executed after any previous migrations that were created before this date and time. + *** ## Run the Migration