[Workflow] Database Migrations For MySQL - sparc-software-hust/fmecg-web-server GitHub Wiki

Mỗi khi có trường mới update, việc thêm file migration sẽ không ảnh hưởng đến data và các trường hiện có. Các công cụ sử dụng:

  • Library: Sequelize (yêu cầu có package sequelizesequelize-cli
  • Version: sequelize: ^6.37.1sequelize-cli: ^6.22.1
  • Reference: Sequelize Migrations

1. Giải thích flow

Flow migration chia làm 2 phần là schema migrations và data migrations (seed migrations). Sequelize có hỗ trợ chia làm 2 folder trong root directory:

  • Folder migrations: chứa các file migrations được tạo từ command line (sẽ được trình bày ở dưới).
  • Folder seeders: chứa các file dummy data được tạo từ command line.
    Khi chạy các câu lệnh liên quan đến migrations, Sequelize sẽ lấy data từ 2 folder và đọc config từ file .sequelizerc. Các câu lệnh để chạy migration đã được config trong package.json như dưới đây:
    "migrate": "npx sequelize-cli db:migrate --name",
    "migrate.all": "npx sequelize-cli db:migrate",
    "migration.create": "npx sequelize-cli migration:generate --name",
    "migration.rollback": "npx sequelize-cli db:migrate:undo",
    "migration.rollback.name": "npx sequelize-cli db:migrate:undo --name",
    "migration.rollback.all": "npx sequelize-cli db:migrate:undo:all",
    "seed": "npx sequelize-cli db:seed --seed",
    "seed.all": "npx sequelize-cli db:seed:all",
    "seed.create": "npx sequelize-cli seed:generate --name",
    "seed.rollback": "npx sequelize-cli db:seed:undo",
    "seed.rollback.name": "npx sequelize-cli db:seed:undo --seed",
    "seed.rollback.all": "npx sequelize-cli db:seed:undo:all"

Trong repo đã có các sẵn các file migrations. Nếu lần đầu chạy, chúng ta sẽ run 2 dòng sau:

npm run migrate.all
npm run seed.all

NOTE: Nếu run seed lỗi thì rollback và run lại:

npm run seed.rollback.all
npm run seed.all

Nếu thêm 1 trường mới vào bảng đã có sẵn, các bước sẽ được hướng dẫn trong 2.1.

2. Các thao tác với migrations file

2.1. Schema migrations

  • Tạo 1 file migration
npm run migrate.create name-of-file

Khi đó Sequelize sẽ tạo cho chúng ta 1 file với format timestamp-name-of-file.js trong folder migrations. Trong file sẽ có 2 hàm, updown:

'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up (queryInterface, Sequelize) {
    /**
     * Khi chạy migrate, Sequelize sẽ chạy hàm up
     *
     * Example:
     * await queryInterface.createTable('users', { id: Sequelize.INTEGER });
     */
  },

  async down (queryInterface, Sequelize) {
    /**
     * Khi muốn huỷ migrate đã chạy trước đó, Sequelize sẽ chạy hàm down
     *
     * Example:
     * await queryInterface.dropTable('users');
     */
  }
};

Việc thêm data vào migration giống như cách làm với sequelize.define trong các file models DTO.
Ví dụ khi thêm 1 trường hobby vào bảng users. Có 2 việc cần thực hiện:

  1. Tạo và chạy file migration
  2. Thêm trường hobby trong UserDTO.js

Hàm updown được sửa như sau:

module.exports = {
  async up(queryInterface, Sequelize) {
    const transaction = await queryInterface.sequelize.transaction();
    try {
      await queryInterface.addColumn(
        'users',
        'hobby',
        {
          type: Sequelize.DataTypes.STRING,
        },
        { transaction },
      );
      await transaction.commit();
    } catch (err) {
      await transaction.rollback();
      throw err;
    }
  },
  async down(queryInterface, Sequelize) {
    const transaction = await queryInterface.sequelize.transaction();
    try {
      await queryInterface.removeColumn('users', 'hobby', { transaction });
      await transaction.commit();
    } catch (err) {
      await transaction.rollback();
      throw err;
    }
  },
};
  • Chạy 1 file migration
npm run migrate name-of-file

hoặc (nếu đã chạy nhiều migration trước đó, Sequelize sẽ chỉ chạy những file migration mới được tạo), bạn chỉ cần:

npm run migrate
  • Chạy tất cả migration (cho trường hợp chạy migrations lần đầu)
npm run migrate.all
  • Undo lại 1 file migration bất kì
npm run migration.rollback.name name-of-file
  • Undo lại migration gần nhất
npm run migration.rollback
  • Undo tất cả các migrations
npm run migration.rollback.name

2.2. Seed migrations

  • Tạo 1 seed
npm run seed.create name-of file

Sequelize sẽ tạo 1 file timestamp-name-of-file.js trong folder seeders. Cũng với 2 hàm updown, flow giống như schema migrations

'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up (queryInterface, Sequelize) {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
  },

  async down (queryInterface, Sequelize) {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

NOTE: Đảm bảo phải await mỗi command. Nếu không sẽ không báo lỗi nhưng không insert được.

  • Chạy 1 file seed
npm run seed name-of-file
  • Chạy tất cả seed files (cho trường hợp chạy dummy lần đầu)
npm run seed.all
  • Undo lại 1 file seed bất kì
npm run seed.rollback.name name-of-file
  • Undo lại seed gần nhất
npm run seed.rollback
  • Undo tất cả các seeds
npm run seed.rollback.all