ပန်းတိုင်နှင့် မည်သည့်အခါ အသုံးပြုမည်နည်း
Entity registration က runtime အတွက် table များကို ဆက်လက် ကြေညာနေသော်လည်း၊ အမှန်တကယ် schema ပြောင်းလဲမှုသည် migration မှတဆင့် ဖြစ်ရပါမည်။ Additive သို့မဟုတ် destructive DDL၊ rename၊ index၊ constraint နှင့် plugin upgrade အတွင်း တစ်ကြိမ်သာ run ရမည့် data backfill အတွက် အသုံးပြုပါ။
- Staging / production — synchronize ကို မမှီခိုရပါ
- ပြန်လှန်နိုင်သော ပြောင်းလဲမှု — up() နှင့် down() ကို တွဲထားပါ
- Ship ပြီးသား ဖိုင်များ — မပြင်ရပါ; နံပါတ်အသစ်ဖြင့် migration အသစ် ထည့်ပါ
1. လိုအပ်ချက်များ
backend/src/index.ts တွင် default-export IPlugin ရှိရပါမည်။ ရည်ရွယ် datasource (များသောအားဖြင့် shared default) ကိုလည်း ရှင်းလင်းစွာ သိရှိရပါမည်။
- backend/src/index.ts က IPlugin ကို implement လုပ်သော plugin class ကို export လုပ်ရပါသည်
- ပြောင်းလဲမှု ပိုင်ဆိုင်သော connection ကို သိပါ — များသောအားဖြင့် { plugin: "default", name: "default" }
- Entity definition များကို နောက်ဆုံး migrated schema နှင့် ကိုက်ညီအောင် ပြင်ဆင်မည် ဖြစ်ပါသည်
- Numbering စည်းမျဉ်း — backend/src/migrations/ အောက်တွင် 001, 002, …
2. Folder အပြင်အဆင်
Migration class များကို backend/src/migrations/ အောက်တွင် ထားရှိပြီး၊ getMigrations() က ပြန်ပေးနိုင်အောင် export လုပ်ရပါသည်။
- ဖိုင်တစ်ခုလျှင် class တစ်ခု; အမည် / နံပါတ်များကို စဉ်အတိုင်း ထားပါ
- Plugin က ESM သုံးပါက index မှ .js extension ဖြင့် import လုပ်ပါ
1backend/
2 src/
3 index.ts # IPlugin — getMigrations()
4 migrations/
5 001-initial.migration.ts
6 002-add-status.migration.ts
7 feature/
8 my.module.ts3. IDatabaseMigration implement လုပ်ခြင်း
getName()၊ getSource()၊ up(QueryRunner) နှင့် down(QueryRunner) ကို implement လုပ်ရပါသည်။ getName() ကို metadata.name ဖြင့် prefix လုပ်၍ plugin အချင်းချင်း ထူးခြားအောင် ထားပါ။ getSource() သည် များသောအားဖြင့် { plugin: "default", name: "default" } ကို ပြန်ပေးပါသည်။
- getName() — ထူးခြားသော id; metadata.name ဖြင့် prefix လုပ်ပါ (ဥပမာ `${metadata.name}_002_add_status`)
- getSource() — SQL run မည့် DataSource (အများအားဖြင့် shared default DB)
- up() — ပြောင်းလဲမှုကို သက်ရောက်စေပါ; local ပြန် run အတွက် IF EXISTS / IF NOT EXISTS ကို ဦးစားပေးပါ
- down() — တူညီသော ပြောင်းလဲမှုကို ပြန်ဖျက်ပါ
1import type { IDatabaseMigration } from "@quan-erp/shared-types";
2import type { QueryRunner } from "typeorm";
3import metadata from "../../module.metadata.json" with { type: "json" };
4
5export class AddStatusMigration implements IDatabaseMigration {
6 getName() {
7 return `${metadata.name}_002_add_status`;
8 }
9
10 getSource() {
11 return { plugin: "default", name: "default" };
12 }
13
14 async up(queryRunner: QueryRunner): Promise<void> {
15 await queryRunner.query(
16 `ALTER TABLE ${metadata.name}_order ADD COLUMN IF NOT EXISTS status varchar(32)`,
17 );
18 }
19
20 async down(queryRunner: QueryRunner): Promise<void> {
21 await queryRunner.query(
22 `ALTER TABLE ${metadata.name}_order DROP COLUMN IF EXISTS status`,
23 );
24 }
25}4. getMigrations() ဖြင့် မှတ်ပုံတင်ခြင်း
backend/src/index.ts ၏ default-exported plugin class မှ getMigrations() ဖြင့် migration class များကို ပြန်ပေးရပါသည်။ Post-migration seed သို့မဟုတ် repair အတွက် optional onMigrate() ကို အသုံးပြုနိုင်ပါသည်။
- Array အစဉ်သည် ရည်ရွယ် apply အစဉ်နှင့် ကိုက်ညီရပါမည်
- onMigrate() သည် pending migration batch ပြီးဆုံးပြီးနောက် run ပါသည်
- Custom datasource — getSource() သည် ထို connection ၏ plugin + name နှင့် ကိုက်ညီရပါမည်
1import type { GetMigrationsType, IPlugin } from "@quan-erp/shared-types";
2import { InitialMigration } from "./migrations/001-initial.migration.js";
3import { AddStatusMigration } from "./migrations/002-add-status.migration.js";
4
5export default class MyPlugin implements IPlugin {
6 getMigrations(): GetMigrationsType {
7 return [InitialMigration, AddStatusMigration];
8 }
9
10 async onMigrate(): Promise<void> {
11 // optional: seed / repair after migrations apply
12 }
13
14 // … getRootModule, getName, getVersion, getMetadata, …
15}5. စစ်ဆေးခြင်းနှင့် စည်းမျဉ်းများ
Plugin ကို Install သို့မဟုတ် upgrade လုပ်သောအခါ core က getMigrations() ကို ဖတ်ပြီး၊ pending name များကို apply လုပ်ကာ၊ module init မတိုင်မီ onMigrate() ကို ခေါ်ပါသည်။
- Pending getName() များသည် getSource() ပေါ်တွင် up() run ပါသည်
- Entity column / index များသည် နောက်ဆုံး migrated schema နှင့် ကိုက်ညီရပါသည်
- Rollback အရေးကြီးပါက down() ကို local / staging တွင် စမ်းသပ်ပါ
- Ship ပြီးသား migration ကို မပြင်ရပါ — 003-… အသစ် ထည့်ပါ
- အမှန်တကယ် upgrade အတွက် synchronize ထက် migration ကို ဦးစားပေးပါ
- 01
Plugin install / upgrade
Core က module.js ကို load လုပ်ပြီး getMigrations() ကို ဖတ်ပါသည်။
- 02
Pending migration များ သက်ရောက်ခြင်း
မသုံးရသေးသော getName() တိုင်းအတွက် getSource() ပေါ်တွင် up(queryRunner) run ပါသည်။
- 03
onMigrate()
Migration batch ပြီးဆုံးပြီးနောက် optional plugin hook ဖြစ်ပါသည်။
- 04
Module init
Entities၊ DI နှင့် @OnInit သည် ပုံမှန်အတိုင်း ဆက်လက် လုပ်ဆောင်ပါသည်။
အဖြစ်များသော အမှားများ
- IDatabaseMigration ပေါ်တွင် getName() / getSource() အစား plain name property သုံးခြင်း
- getName() ကို metadata.name ဖြင့် prefix မလုပ်ခြင်း (plugin အချင်းချင်း collision)
- getSource() မှားခြင်း — entity နှင့် မတူသော DataSource ပေါ်တွင် run ခြင်း
- Ship ပြီးသား migration ကို ပြင်ခြင်း — နံပါတ်အသစ်ဖြင့် ဖိုင်အသစ် ထည့်ရပါသည်
- Entity ကိုသာ ပြင်ပြီး migration မပါခြင်း (သို့မဟုတ် ပြန်လှန်)
- Production upgrade တွင် synchronize: true ကို မှီခိုခြင်း