Migration
Migration là lớp cơ sở cho migration dữ liệu của NocoBase, dùng để xử lý thay đổi cấu trúc cơ sở dữ liệu và migration dữ liệu khi nâng cấp Plugin. Import từ @nocobase/server.
import { Migration } from '@nocobase/server';
export default class extends Migration {
on = 'afterLoad';
appVersion = '<1.0.0';
async up() {
// Logic nâng cấp
}
}
Thuộc tính của lớp
on
on: 'beforeLoad' | 'afterSync' | 'afterLoad';
Kiểm soát thời điểm migration thực thi trong quy trình upgrade. Mặc định 'afterLoad'.
appVersion
Chuỗi semver range, quyết định migration được thực thi trên các phiên bản ứng dụng nào. Framework dùng semver.satisfies() để kiểm tra: chỉ khi phiên bản ứng dụng hiện tại thỏa mãn range này thì migration mới chạy.
// Chỉ chạy khi nâng cấp từ phiên bản thấp hơn 1.0.0
appVersion = '<1.0.0';
// Chỉ chạy khi nâng cấp từ phiên bản thấp hơn 0.21.0-alpha.13
appVersion = '<0.21.0-alpha.13';
// Để trống thì chạy mỗi lần upgrade
appVersion = '';
Thuộc tính của instance
app
Instance Application của NocoBase. Qua đây bạn có thể truy cập các module của ứng dụng:
async up() {
// Lấy phiên bản ứng dụng
const version = this.app.version;
// Lấy logger
this.app.log.info('Migration started');
}
db
Instance Database của NocoBase, có thể dùng để lấy Repository, thực thi truy vấn, v.v.:
async up() {
const repo = this.db.getRepository('users');
await repo.update({
filter: { status: 'inactive' },
values: { status: 'disabled' },
});
}
plugin
Instance Plugin hiện tại. Chỉ khả dụng trong migration cấp Plugin (trong core migration là undefined).
async up() {
const pluginName = this.plugin.name;
}
sequelize
get sequelize(): Sequelize
Instance Sequelize, có thể trực tiếp thực thi SQL thô:
async up() {
await this.sequelize.query(`UPDATE users SET status = 'active' WHERE status IS NULL`);
}
queryInterface
get queryInterface(): QueryInterface
Sequelize QueryInterface, dùng cho thao tác DDL (thêm/xóa cột, thêm ràng buộc, đổi kiểu cột, v.v.):
async up() {
const { DataTypes } = require('@nocobase/database');
// Thêm cột
await this.queryInterface.addColumn('users', 'nickname', {
type: DataTypes.STRING,
});
// Thêm ràng buộc unique
await this.queryInterface.addConstraint('users', {
type: 'unique',
fields: ['email'],
});
}
pm
Trình quản lý Plugin. Qua this.pm.repository bạn có thể truy vấn và sửa metadata Plugin:
async up() {
const plugins = await this.pm.repository.find();
for (const plugin of plugins) {
// Sửa hàng loạt bản ghi Plugin
}
}
Phương thức của instance
up()
async up(): Promise<void>
Thực thi khi nâng cấp. Lớp con phải override phương thức này, viết logic migration.
down()
async down(): Promise<void>
Thực thi khi rollback. Hầu hết migration để trống. Nếu cần hỗ trợ rollback, viết thao tác ngược ở đây.
Ví d ụ đầy đủ
Dùng Repository API để cập nhật dữ liệu (afterLoad)
Tình huống phổ biến nhất - sau khi tất cả Plugin được load xong, dùng Repository API để cập nhật hàng loạt dữ liệu:
import { Migration } from '@nocobase/server';
export default class extends Migration {
appVersion = '<1.0.0';
async up() {
const repo = this.db.getRepository('roles');
await repo.update({
filter: {
$or: [{ allowConfigure: true }, { name: 'root' }],
},
values: {
snippets: ['ui.*', 'pm', 'pm.*'],
allowConfigure: false,
},
});
}
async down() {}
}
Dùng QueryInterface để sửa cấu trúc bảng (beforeLoad)
Thực thi DDL ở tầng thấp trước khi Plugin được load - ví dụ thêm cột mới và ràng buộc unique cho bảng:
import { DataTypes } from '@nocobase/database';
import { Migration } from '@nocobase/server';
export default class extends Migration {
on = 'beforeLoad';
appVersion = '<0.14.0-alpha.2';
async up() {
const tableName = this.pm.collection.getTableNameWithSchema();
const field = this.pm.collection.getField('packageName');
// Kiểm tra trước xem field đã tồn tại chưa
const exists = await field.existsInDb();
if (exists) return;
await this.queryInterface.addColumn(tableName, field.columnName(), {
type: DataTypes.STRING,
});
await this.queryInterface.addConstraint(tableName, {
type: 'unique',
fields: [field.columnName()],
});
}
}
Dùng SQL thô (afterSync)
Sau khi cấu trúc bảng được sync xong, dùng SQL thô để migrate dữ liệu:
import { Migration } from '@nocobase/server';
export default class extends Migration {
on = 'afterSync';
appVersion = '<1.0.0-alpha.3';
async up() {
const items = await this.pm.repository.find();
for (const item of items) {
if (item.name.startsWith('@nocobase/plugin-')) {
item.set('name', item.name.substring('@nocobase/plugin-'.length));
await item.save();
}
}
}
}
Tạo file Migration
Tạo qua lệnh CLI:
yarn nocobase create-migration my-migration --pkg @my-project/plugin-hello
Lệnh sẽ tạo file có timestamp trong thư mục src/server/migrations/ của Plugin, theo template:
import { Migration } from '@nocobase/server';
export default class extends Migration {
on = 'afterLoad';
appVersion = '<phiên bản hiện tại>';
async up() {
// coding
}
}
Tham số lệnh:
Liên kết liên quan