DEV Community

Lumin
Lumin

Posted on • Updated on

ทำ Database Change Management ด้วย Liquibase

Definitions

  • Changelog ไฟล์ที่รวบรวมการเปลี่ยนแปลงไว้ สำหรับบทความนี้เราใช้วิธีการเก็บไว้ในไฟล์ liquibase.changelog.xml และใส่ config ให้ใช้ทุกไฟล์ใน migrations ดังนั้นในบทความนี้ changelog หมายถึงไฟล์ sql ทุกไฟล์ในโฟรเดอร์ migrations
  • Changeset รายละเอียดของการเปลี่ยนแปลงที่เราสามารถเอา database migration script หลายๆตัวมารวมกันได้ภายใน changeset เดียว
  • Migrate การรัน migration script เพื่ออัพเดทโครงสร้าง database
  • Rollback การรัน rollback เพื่อ undo การ migrate

Project Structure

project-root/
- migrations/
    - YYYYMMDD-sprint-01.sql
    - YYYYMMDD-sprint-02.sql
    - ...
- liquibase.properties
- liquibase.changelog.xml
Enter fullscreen mode Exit fullscreen mode

อธิบาย

  • liquibase.changelog.xml -- ไฟล์ changelog หลัก ที่จะ config ให้ไปใช้ไฟล์ใน migrations ในการรัน database migration
  • liquibase.properties -- ไฟล์ที่เก็บ variable ของ Liquibase
  • migrations/ -- โฟลเดอร์ที่จะเก็บ migration script ทั้งหมด
  • migrations/YYYYMMDD-sprint-01.sql -- ไฟล์​ Liquibase changelog ในรูปแบบ SQL ซึ่งภายในไฟล์จะมี database migration script ที่สามารถ grouping เป็น change set ได้

คำแนะนำ
โดยแต่ละไฟล์ควรจะนำหน้าด้วย YYYYMMDD เพื่อเรียงลำดับของการ migration และควรใส่เลข sprint เพื่อที่จะสามารถ track กลับมาได้ว่าเป็น changelog ของ sprint ไหน

Migration Script

-- liquibase formatted sql

-- changeset lumin:1721661329831-1 labels:pbi-1234,sprint-10
-- comment: create products table
CREATE TABLE "products" ("id" INTEGER NOT NULL, "name" VARCHAR(50) NOT NULL, "description" TEXT NOT NULL, "price" numeric(5, 2) NOT NULL, "stock" INTEGER NOT NULL, "updated_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "products_pkey" PRIMARY KEY ("id"));
-- rollback DROP TABLE "products";

-- changeset lumin:1721661329831-2 labels:pbi-1235,sprint-10
-- comment: create customers table
CREATE TABLE "customers" ("id" INTEGER NOT NULL, "name" VARCHAR(100) NOT NULL, "registered_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "customers_pkey" PRIMARY KEY ("id"));
-- rollback DROP TABLE "customers";
Enter fullscreen mode Exit fullscreen mode

อธิบาย

  • บรรทัดแรก -- liquibase formatted sql เพื่อบอกว่านี่คือไฟล์ Liquibase changelog
  • -- changeset author:unique-number labels:label-1,label-2 เป็นการกำหนดว่าหลังจากบรรทัดนี้เป็นต้นไปจะเป็น migration script ภายใต้ changeset นี้ ซึ่งจะใช้เลข unique-number และใช้ label label-1 และ label-2 (สามารถเอาไปใช้ filter ได้)
  • -- comment: ... เป็น comment เพื่อใส่รายละเอียดอธิบาย ไม่มีผลในการรัน
  • -- rollback ... กำหนด roll back script

Step

0) Prepare Example Project

ด้วยการจำลอง database ด้วย Docker

# Use postgres/example user/password credentials
services:

  db:
    image: postgres:alpine
    restart: always
    shm_size: 128mb
    ports:
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: example

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
Enter fullscreen mode Exit fullscreen mode

และสร้าง container ด้วย

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

และเข้าไปสร้าง database จำลอง เพื่อจำลองว่าในโปรเจคของเรามี database ที่ยังไม่ได้ migrate อยู่ โดยใช้ script นี้

CREATE DATABASE "app-local";
CREATE TABLE products
(
    id INTEGER PRIMARY KEY NOT NULL,
    name VARCHAR(50) NOT NULL,
    description TEXT NOT NULL,
    price DECIMAL(5,2) NOT NULL,
    stock INTEGER NOT NULL,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE customers
(
    id INTEGER PRIMARY KEY NOT NULL,
    name VARCHAR(100) NOT NULL,
    registered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
Enter fullscreen mode Exit fullscreen mode

1) Init Liquibase Project

สร้าง liquibase.changelog.yml

databaseChangeLog:
  - includeAll:
      path: migrations/
Enter fullscreen mode Exit fullscreen mode

สร้าง liquibase.properties

# Liquibase setting
liquibase.hub.mode: off
liquibase.showBanner: false

changelogFile: liquibase.changelog.yml

# LOCAL ENVIRONMENT
url: jdbc:postgresql://localhost:5432/app-local
username: postgres
password: example
liquibase.command.defaultSchemaName: public
Enter fullscreen mode Exit fullscreen mode
  • variable ที่จำเป็นในการรัน Liquibase จะมี 4 ตัวดังนี้
    • changelogFile บอกว่าให้ไปหยิบ changelog จากไหน
    • url คือ database connection string แบบ jdbc
    • username คือ database username
    • password คือ database password
  • variable อื่นๆ ที่ไม่มีก็รันได้ แต่ถ้าใส่ก็จะดีกว่า
    • liquibase.hub.mode: off เพื่อไม่ส่งข้อมูลการใช้งานของเราให้ Liquibase
    • liquibase.showBanner: false เพื่อไม่แสดง Liquibase banner ตอนรัน CLI
    • liquibase.command.defaultSchemaName: public เพื่อบอกว่า default database schema คือ public ซึ่งเราอาจจะได้ใช้ในกรณีที่เรามีหลาย schema
  • ถ้าไม่มีไฟล์ liquibase.properties เราสามารถใส่ข้อมูลเหล่านี้ได้ 2 แบบ
    • ใส่เป็น option เช่น liquibase status --changelog-file ? --url ? --username ? --password ? (ไม่แนะนำให้ทำใน local environment จะลำบากทำไม)
    • ใส่เป็น environment variables โดยใช้ format LIQUIBASE_<option-name> เช่น
      • LIQUIBASE_URL
      • LIQUIBASE_USERNAME
      • LIQUIBASE_PASSWORD
    • ซึ่งท่านี้ เราจะใช้ในกรณีที่เอาไปรันใน CI เพราะเราจะไม่ใส่ liquibase.properties ตอน build package

ทดสอบว่าสามารถใช้งานได้ไหม

$ liquibase status
> ERROR: Exception Details
> ERROR: Exception Primary Class:  SetupException
> ERROR: Exception Primary Reason:  Could not find directory, directory was empty, or no changelogs matched the provided search criteria for includeAll 'migrations/'
> ERROR: Exception Primary Source:  4.28.0
Enter fullscreen mode Exit fullscreen mode

ซึ่งเป็น error ที่บอกว่าไม่มีไฟล์ใน migrations/ เลย แต่สามารถ connect database ได้เรียบร้อย

2) Capture Database Structure

เราสามารถดึงโครงสร้างของ database ณ ปัจจุบัน โดยใช้คำสั่ง generate-changelog

$ liquibase generate-changelog \
    --changelog-file ./migrations/00000000-init.sql
Generated changelog written to ./migrations/00000000-init.sql
Enter fullscreen mode Exit fullscreen mode

เกิดไฟล์ migrations/00000000-init.sql ซึ่งมีข้อมูล

-- liquibase formatted sql

-- changeset lumin:1721661329831-1
CREATE TABLE "products" ("id" INTEGER NOT NULL, "name" VARCHAR(50) NOT NULL, "description" TEXT NOT NULL, "price" numeric(5, 2) NOT NULL, "stock" INTEGER NOT NULL, "updated_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "products_pkey" PRIMARY KEY ("id"));

-- changeset lumin:1721661329831-2
CREATE TABLE "customers" ("id" INTEGER NOT NULL, "name" VARCHAR(100) NOT NULL, "registered_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "customers_pkey" PRIMARY KEY ("id"));
Enter fullscreen mode Exit fullscreen mode

เราควรเพิ่ม label ลงไปเพื่อให้เราสามารถทำ filter label ได้ โดยเพิ่ม labels:init

-- liquibase formatted sql

-- changeset lumin:1721661329831-1 labels:init
CREATE TABLE "products" ("id" INTEGER NOT NULL, "name" VARCHAR(50) NOT NULL, "description" TEXT NOT NULL, "price" numeric(5, 2) NOT NULL, "stock" INTEGER NOT NULL, "updated_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "products_pkey" PRIMARY KEY ("id"));

-- changeset lumin:1721661329831-2 labels:init
CREATE TABLE "customers" ("id" INTEGER NOT NULL, "name" VARCHAR(100) NOT NULL, "registered_at" TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL, CONSTRAINT "customers_pkey" PRIMARY KEY ("id"));
Enter fullscreen mode Exit fullscreen mode

ทดสอบ ด้วยคำสั่ง status

$ liquibase status
changesets have not been applied to postgres@jdbc:postgresql://localhost:5432/app-local
     migrations/000000-init-structure.sql::1721906361520-1::teerasak.vichadee
     migrations/000000-init-structure.sql::1721906361520-2::teerasak.vichadee
Enter fullscreen mode Exit fullscreen mode

ตอนนี้เรามี changeset 2 ตัวที่ยังไม่ได้รัน migrate (แน่ล่ะ ก็เราเพิ่ง generate มันใหม่จาก database structure เดิมที่มีอยู่แล้ว)

แต่อันที่จริง เราไม่จำเป็นต้อง migrate ก็เพราะว่ามันมี table ครบอยู่แล้ว ดังนั้นสิ่งที่เราควรทำคือ sync ข้อมูล changeset เหล่านี้ขึ้นไปเก็บและให้สถานะมันเป็น EXECUTED หรือ รัน migrate ไปแล้ว

# check sync SQL
$ liquibase changelog-sync-sql --label-filter init --output-file dump.sql
Output saved to dump.sql

# updated undeployed changelog with label=init to EXECUTED
$ liquibase changelog-sync --label-filter init
Enter fullscreen mode Exit fullscreen mode

เมื่อเข้าไปดูใน database จะพบว่าในตาราง databasechangelog (เป็นตารางที่ liquibase สร้างมาเก็บ changelog record) มี 2 record ที่มี

  • filename = migrations/000000-init-structure.sql
  • exectype = EXECUTED
  • labels = init

ทดสอบอีกครั้ง

# ตรวจสอบว่ามี changelog ที่ยังไม่ได้ execute ไหม (ไม่ควรมี เพราะเพิ่งเปลี่ยนสถานะเป็น EXECUTED ไป)
$ liquibase status
postgres@jdbc:postgresql://localhost:5432/app-local is up to date

# ตรวจสอบว่า changelog ตัวไหนที่ execute ไปแล้ว
$ liquibase history
Liquibase History for jdbc:postgresql://localhost:5432/app-local

- Database updated at 7/25/24, 6:40 PM. Applied 2 changeset(s) in 0.009s, DeploymentId: 1907624549
  migrations/000000-init-structure.sql::1721906361520-1::teerasak.vichadee
  migrations/000000-init-structure.sql::1721906361520-2::teerasak.vichadee
Enter fullscreen mode Exit fullscreen mode

ณ ตอนนี้ เรามี migration script ที่สามารถเอาไป execute ใน environment ใหม่ได้แล้ว

3) Test Migrate in New Environment

เราจะจำลองการเอาไปรันใน environment ใหม่โดยการ terminate docker container แล้วรัน migrate script

# terminate docker container ของโปรเจคปัจจุบัน
$ ​docker compose down

# start docker container อีกครั้ง (ซึ่ง database structure ทั้งหมดจะหายไปแล้ว)
$ docker compose up -d
Enter fullscreen mode Exit fullscreen mode

ก่อนอื่น เราต้องสร้าง database app-local ขึ้นมาก่อน

CREATE DATABASE "app-local";
Enter fullscreen mode Exit fullscreen mode

หลังจากนั้นรัน migration script ด้วยคำสั่ง

$ liquibase update
Running Changeset: migrations/000000-init-structure.sql::1721906361520-1::teerasak.vichadee
Running Changeset: migrations/000000-init-structure.sql::1721906361520-2::teerasak.vichadee

UPDATE SUMMARY
Run:                          2
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            2

Liquibase: Update has been successful. Rows affected: 2
Enter fullscreen mode Exit fullscreen mode

เมื่อไปเช็คใน database จะพบว่ามีตาราง products และ customers เกิดขึ้น ตามรายละเอียดของไฟล์​ migrations/000000-init-structure.sql

4) Create New Migration Script

สมมุติเราต้องเพิ่ม feature ใหม่ให้ระบบ ซึ่งจะต้องมีการเปลี่ยนแปลงโครงสร้างตารางด้วย

เราควรสร้างไฟล์​ changelog ใหม่ในโฟลเดอร์ migrations/ โดยกำหนดชื่อไฟล์ตาม pattern คือ migrations/20240725-sprint-11.sql

-- liquibase formatted sql

-- changeset teerasak.vichadee:pbi-111 labels:pbi-111,sprint-11
-- comment: pbi-111 implement orders aggregate
-- สร้างตาราง orders
CREATE TABLE "orders" (
  "id" serial NOT NULL, 
  PRIMARY KEY ("id"),
  "customer_id" integer NOT NULL,
  "updated_at" timestamp NOT NULL,
  "created_at" timestamp NOT NULL
);
-- สร้าง index สำหรับ orders.customer_id
CREATE INDEX "orders_customer_id" ON "orders" ("customer_id");
-- สร้างตาราง order_items
CREATE TABLE "order_items" (
  "id" serial NOT NULL,
  PRIMARY KEY ("id"),
  "order_id" integer NOT NULL,
  "product_id" integer NOT NULL,
  "quantity" integer NOT NULL DEFAULT '0',
  "updated_at" timestamp NOT NULL,
  "created_at" timestamp NOT NULL
);
-- สร้าง index สำหรับ order_items.order_id และ order_items.product_id
CREATE INDEX "order_items_order_id" ON "order_items" ("order_id");
CREATE INDEX "order_items_product_id" ON "order_items" ("product_id");
-- rollback DROP TABLE orders;
-- rollback DROP TABLE order_items;
Enter fullscreen mode Exit fullscreen mode

รายละเอียดภายในไฟล์ changelog ที่ควรสนใจและถกเถียงในทีมเวลาสร้าง

  • เราควรสร้าง changeset ให้มีหลายๆ SQL command โดยขึ้นอยู่กับว่า มันเป็น change ที่เกี่ยวข้องกันไหม
    • ซึ่งมันจะแลกมากับความยืดหยุ่นในการ migrate และ rollback เพราะถ้ามี change เยอะเกินไป หรือไม่เกี่ยวข้องการ การที่จะทำ rollback อาจจะส่งผลกระทบให้ต้อง rollback ทั้งหมด
    • ด้วยมาตรฐานที่เราวางไว้ว่า เราจะสร้าง PBI ที่มี value และสามารถ deploy ได้ด้วยตัวมันเอง และไม่ dependency กับ PBI อื่นๆ ดังนั้นโดยปกติ 1 PBI ควรมีแค่ 1 changeset
  • SQL command ในแต่ละ changset ควรใช้ command ที่ได้ performance เพื่อเสียเวลาในการรัน migrate น้อยที่สุด เช่น ถ้าจะ insert เพื่อทำ seeding ควรใช้ batch insert ไม่ควร insert 1 record per row
  • ทุก changeset ควรมี rollback
    • rollback script สามารถใส่หลายๆตัวภายใน changeset ดังนั้นเราสามารถใส่ควบคู่ไปกับ SQL command แต่ละตัวได้เลย

จากนั้นทดสอบ migration script ด้วย

# เช็คสถานะของ changeset ที่เราสร้าง
$ liquibase status
1 changeset has not been applied to postgres@jdbc:postgresql://localhost:5432/app-local
     migrations/20240725-sprint-11.sql::pbi-111::teerasak.vichadee

# สร้าง migration script เพื่อเอามารีวิว
$ liquibase update-sql --output-file migration-sprint-11.review.sql
Output saved to migration-sprint-11.review.sql

# สร้าง rollback script เพื่อเอามารีวิว
$ liquibase future-rollback-sql --output-file migration-sprint-11-rollback.review.sql
Output saved to migration-sprint-11-rollback.review.sql
Enter fullscreen mode Exit fullscreen mode

ในการทำงานเราควรเอาไฟล์​ migration-sprint-11.review.sql มีรีวิวว่ามีรายละเอียดตรงกับที่เราต้องการหรือไม่ (ข้อเสียของ Liquibase คือ ไม่แสดง SQL comment ที่เราใส่ไปใน changelog)

...

-- *********************************************************************
-- Update Database Script
-- *********************************************************************
-- Change Log: liquibase.changelog.yml
-- Ran at: 7/26/24, 9:32 AM
-- Against: postgres@jdbc:postgresql://localhost:5432/app-local
-- Liquibase version: 4.28.0
-- *********************************************************************

...

CREATE TABLE "orders" (
  "id" serial NOT NULL, 
  PRIMARY KEY ("id"),
  "customer_id" integer NOT NULL,
  "updated_at" timestamp NOT NULL,
  "created_at" timestamp NOT NULL
);

CREATE INDEX "orders_customer_id" ON "orders" ("customer_id");

CREATE TABLE "order_items" (
  "id" serial NOT NULL,
  PRIMARY KEY ("id"),
  "order_id" integer NOT NULL,
  "product_id" integer NOT NULL,
  "quantity" integer NOT NULL DEFAULT '0',
  "updated_at" timestamp NOT NULL,
  "created_at" timestamp NOT NULL
);

CREATE INDEX "order_items_order_id" ON "order_items" ("order_id");

CREATE INDEX "order_items_product_id" ON "order_items" ("product_id");

...
Enter fullscreen mode Exit fullscreen mode

และก็ควรรีวิว rollback script จากไฟล์ migration-sprint-11-rollback.review.sql

...

-- *********************************************************************
-- SQL to roll back currently unexecuted changes
-- *********************************************************************
-- Change Log: liquibase.changelog.yml
-- Ran at: 7/26/24, 9:43 AM
-- Against: postgres@jdbc:postgresql://localhost:5432/app-local
-- Liquibase version: 4.28.0
-- *********************************************************************

...

-- Rolling Back ChangeSet: migrations/20240725-sprint-11.sql::pbi-111::teerasak.vichadee
DROP TABLE orders;

DROP TABLE order_items;

...
Enter fullscreen mode Exit fullscreen mode

เมื่อรีวิวตรวจสอบความถูกต้องดีแล้ว จึงรัน migrate

# สั่งรัน migration script 
$ liquibase update
Running Changeset: migrations/20240725-sprint-11.sql::pbi-111::teerasak.vichadee

UPDATE SUMMARY
Run:                          1
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            3

Liquibase: Update has been successful. Rows affected: 1

# ตรวจสอบ history การรัน migration
$ liquibase history --format text
Liquibase History for jdbc:postgresql://localhost:5432/app-local

- Database updated at 7/25/24, 6:53 PM. Applied 2 changeset(s) in 0.013s, DeploymentId: 1908401506
  migrations/000000-init-structure.sql::1721906361520-1::teerasak.vichadee
  migrations/000000-init-structure.sql::1721906361520-2::teerasak.vichadee

- Database updated at 7/26/24, 9:20 AM. Applied 1 changeset(s), DeploymentId: 1960449791
  migrations/20240725-sprint-11.sql::pbi-111::teerasak.vichadee
Enter fullscreen mode Exit fullscreen mode

ซึ่งใน history จะเห็นว่า changelog ของเราเป็น update ล่าสุดที่เกิดขึ้น

5) Rollback!

เมื่อเกิดปัญหา เราสามารถสั่ง rollback ดังนี้

$ liquibase rollback-sql --label-filter sprint-11 --output-file migration-sprint-11-rollback.preview.sql
Output saved to migration-sprint-11-rollback.preview.sql

$ liquibase rollback --label-filter sprint-11
Rolling Back Changeset: migrations/20240725-sprint-11.sql::pbi-111::teerasak.vichadee

$ liquibase history --format text
Liquibase History for jdbc:postgresql://localhost:5432/app-local

- Database updated at 7/25/24, 6:53 PM. Applied 2 changeset(s) in 0.013s, DeploymentId: 1908401506
  migrations/000000-init-structure.sql::1721906361520-1::teerasak.vichadee
  migrations/000000-init-structure.sql::1721906361520-2::teerasak.vichadee
Enter fullscreen mode Exit fullscreen mode

การ rollback เราสามารถทำได้ 2 แบบ

  1. ใช้ rollback-count 1 เพื่อบอกว่าให้ rollback migration ล่าสุด แต่เราจะแน่ใจได้อย่างว่า นั่นคือ rollback ที่ถูกต้อง และถ้าไม่ถูกต้องจะต้องทำอย่างไร
  2. ใช้ rollback --label-filter sprint-11 เพื่อทำ rollback สำหรับ migrate ที่มี label = sprint-11 จะมีความ specific มากขึ้น โดยกำหนดว่าจะต้อง rollback migration ที่มี label ตามที่กำหนด

ดังนั้น ถ้าหากว่าเราใส่ label กำกับทุกครั้ง เราควรใช้ท่า rollback --label-filter

Summary

  • สร้าง pattern ของไฟล์ changelog ให้สามารถ filter ได้ เช่น 20240725-sprint-11.sql
  • สร้าง pattern ของ changeset
    • ใช้ unqiue-numer เป็นเลข pbi
    • ใส่ label เพื่อให้สามารถ filter เพื่อ migrate หรือ rollback ได้
  • migration workflow

    • สร้าง changelog ไปเก็บใน migrations/ และต้องใส่ rollback ในทุกๆ changeset ที่มีการเปลี่ยนแปลง และอย่าลืมกำหนด label ตาม pattern
    • run migrate
    # ตรวจสอบก่อนว่ามี pending changelog อยู่ไหม และใช่ของเราหรือปล่าว
    liquibase status
    
    # ตรวจสอบ migration script (ไม่ควรจะมีของเรา)
    liquibase update-sql --output-file migration-sprint-11.review.sql
    
    # ตรวจสอบ rollback script (ควรจะมี comment บอกว่ามาจากไฟล์ changelog ของเรา)
    liquibase future-rollback-sql --label-filter "sprint-11" --output-file migration-sprint-11.review.sql
    
    # สั่งรัน migration script 
    liquibase update
    
    # ตรวจสอบ pending อีกครั้งว่ารันไปแล้วหรือยัง (มันควรจะหายไป)
    liquibase status
    
    # ตรวจสอบ migration script ที่รันไปแล้ว (ควรมีของเราเป็นอันสุดท้าย)
    liquibase history
    
    • run rollback
    # ตรวจสอบ rollback script (ควรจะมี comment บอกว่ามาจากไฟล์ changelog ของเรา)
    liquibase rollback-sql --label-filter "sprint-11" --output-file rollback-sprint-11.review.sql
    
    # สั่ง rollback ด้วย label ของ changeset
    liquibase rollback --label-filter "sprint-11"
    
    # ตรวจสอบ pending (ควรจะแสดง changeset ที่ถูก rollback)
    liquibase status
    
    # ตรวจสอบ migration script ที่รันไปแล้ว (ไม่ควรมี changeset ที่ถูก rollback)
    liquibase history
    

Improvement

Makefile

เพื่อซ่อนความซับซ้อนและเพิ่มความเข้าใจในการรัน เราควรสร้าง Makefile ดังนี้

help: ## Shows the available commands.
    @printf "Available Commands:\n"
    @grep -E '^[a-zA-Z0-9_/\-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
    @printf "\nExample:\n"
    @printf "  - make migration/status\n"
    @printf "  - make migration/status OPTIONS=\"--label-filter init\"\n"
    @printf "\n"

migration/pending: ## ตรวจสอบ migration script ที่ยังไม่ได้รัน
    liquibase status $(OPTIONS)

migration/check-migrate: ## เตรียม SQL สำหรับรัน migration
    liquibase update-sql --output-file migration.review.sql $(OPTIONS)

migration/check-future-rollback: ## เตรียม SQL สำหรับรัน rollback
    liquibase future-rollback-sql --output-file rollback.review.sql $(OPTIONS)

migration/check-rollback: ## เตรียม SQL สำหรับรัน rollback
    ifndef labels
        $(error ระบุ labels โดยใช้คำสั่ง 'make migration/prepare-rollback labels=<label ที่เราต้องการ>')
    endif
    liquibase rollback-sql --output-file prepare-rollback.review.sql --label-filter=$(labels) $(OPTIONS)

migration/migrate: ## รัน migration script
    liquibase update $(OPTIONS)

migration/rollback: ## รัน rollback script
    ifndef labels
        $(error ระบุ labels โดยใช้คำสั่ง 'make migration/rollback labels=<label ที่เราต้องการ>')
    endif
    liquibase rollback --label-filter=$(labels) $(OPTIONS)

migration/history: ## ตรวจสอบ migration script ที่รันไปแล้ว
    liquibase history --format text $(OPTIONS)

Enter fullscreen mode Exit fullscreen mode
  • make migration/pending -- ตรวจสอบ migration script ที่ยังไม่ได้รัน
  • make migration/check-migrate -- เตรียม SQL สำหรับรัน migration เพื่อเอามารีวิว
  • make migration/check-future-rollback -- เตรียม SQL สำหรับรัน rollback ทุกอย่างที่อยู่ใน pending เพื่อเอามารีวิว
  • make migration/migrate -- รัน migration script
  • make migration/check-rollback labels=<label> -- เตรียม SQL สำหรับรัน rollback เฉพาะ changeset ที่มี labels=<label> เพื่อเอามารีวิว
  • make migration/rollback labels=<label> -- รัน rollback script เฉพาะ changeset ที่มี labels=<label>
  • make migration/history -- ตรวจสอบ migration script ที่รันไปแล้ว

Top comments (0)