Миграция

Во время разработки и обновления плагинов NocoBase структура или конфигурация базы данных плагина может претерпевать несовместимые изменения. Чтобы обеспечить плавное обновление, NocoBase предоставляет механизм миграций, который обрабатывает такие изменения с помощью файлов миграции. Это руководство поможет системно понять процесс использования и разработки миграций.

Концепция миграции

Миграция — это скрипт, который автоматически запускается во время обновлений плагина и используется для решения следующих проблем:

  • Корректировка структуры таблицы данных (добавление полей, изменение типов полей и т. д.)
  • Миграция данных (например, пакетное обновление значений полей)
  • Обновление конфигурации плагина или внутренней логики

Сроки выполнения миграции делятся на три типа:

ТипВремя триггераСценарий выполнения
beforeLoadПеред загрузкой всех конфигураций плагинов
afterSyncПосле синхронизации конфигураций коллекции с базой данных (структура коллекции уже изменена)
afterLoadПосле загрузки всех конфигураций плагина

Создание файлов миграции

Файлы миграции должны быть помещены в src/server/migrations/*.ts в каталоге плагина. NocoBase предоставляет команду create-migration для быстрого создания файлов миграции.

yarn nocobase create-migration [options] <name>

Необязательные параметры

ПараметрОписание
--pkg <pkg>Укажите имя пакета плагина
--on [on]Укажите время выполнения, параметры: beforeLoad, afterSync, afterLoad

Пример

$ yarn nocobase create-migration update-ui --pkg=@nocobase/plugin-client

Путь к сгенерированному файлу миграции:

/nocobase/packages/plugins/@nocobase/plugin-client/src/server/migrations/20240107173313-update-ui.ts

Начальное содержимое файла:

import { Migration } from '@nocobase/server';

export default class extends Migration {
  on = 'afterLoad'; // возможные значения: 'beforeLoad' | 'afterSync' | 'afterLoad'
  appVersion = '<0.19.0-alpha.3';

  async up() {
    // Напишите здесь логику обновления
  }
}

⚠️ appVersion используется для идентификации версии, на которую предназначено обновление. Среды с версиями меньше указанной будут выполнять эту миграцию.

Написание миграции

В файлах миграции через this доступны общие свойства и API для удобной работы с базой данных, плагинами и экземпляром приложения:

Общие свойства

  • this.app Текущий экземпляр приложения NocoBase. Используется для доступа к глобальным сервисам, плагинам и конфигурации.

    const config = this.app.config.get('database');
  • this.db Экземпляр сервиса базы данных предоставляет интерфейсы для работы с моделями (коллекциями).

    const users = await this.db.getRepository('users').findAll();
  • this.plugin Текущий экземпляр плагина можно использовать для доступа к пользовательским методам плагина.

    const settings = this.plugin.customMethod();
  • this.sequelize Экземпляр Sequelize позволяет напрямую выполнять SQL-запросы и транзакции.

    await this.sequelize.transaction(async (transaction) => {
      await this.sequelize.query('UPDATE users SET active = 1', { transaction });
    });
  • this.queryInterface QueryInterface Sequelize обычно используется для изменения структуры таблиц, например для добавления полей или удаления таблиц.

    await this.queryInterface.addColumn('users', 'age', {
      type: this.sequelize.Sequelize.INTEGER,
      allowNull: true,
    });

Пример миграции

import { Migration } from '@nocobase/server';

export default class extends Migration {
  on = 'afterSync';
  appVersion = '<0.19.0-alpha.3';

  async up() {
    // Используйте queryInterface для добавления поля
    await this.queryInterface.addColumn('users', 'nickname', {
      type: this.sequelize.Sequelize.STRING,
      allowNull: true,
    });

    // Используйте db для доступа к моделям данных
    const users = await this.db.getRepository('users').findAll();
    for (const user of users) {
      user.nickname = user.username;
      await user.save();
    }

    // Выполните пользовательский метод плагина
    await this.plugin.customMethod();
  }
}

Помимо перечисленных выше общих свойств, Migration предоставляет и другие API. Подробности см. в API Migration.

Запуск миграции

Выполнение миграций запускается командой nocobase upgrade:

$ yarn nocobase upgrade

Во время обновления система определяет порядок выполнения на основе типа миграции и appVersion.

Тестирование миграции

При разработке плагинов рекомендуется использовать тестовый сервер (Mock Server), чтобы проверить корректность выполнения миграций и избежать повреждения реальных данных.

import { createMockServer, MockServer } from '@nocobase/test';

describe('Тест миграции', () => {
  let app: MockServer;

  beforeEach(async () => {
    app = await createMockServer({
      plugins: ['my-plugin'], // Имя плагина
      version: '0.18.0-alpha.5', // Версия до обновления
    });
  });

  afterEach(async () => {
    await app.destroy();
  });

  test('запуск миграции при обновлении', async () => {
    await app.runCommand('upgrade');
    // Напишите логику проверки, например проверьте, что поле существует и миграция данных выполнена успешно
  });
});

Использование тестового сервера (Mock Server) позволяет быстро смоделировать сценарии обновления и проверить порядок выполнения миграций и изменения данных.

Рекомендации по практике разработки

  1. Раздельная миграция Старайтесь создавать один файл миграции для каждого обновления, чтобы сохранить атомарность и упростить отладку.
  2. Укажите время выполнения Выбирайте beforeLoad, afterSync или afterLoad в зависимости от объектов операции, избегая зависимости от еще не загруженных модулей.
  3. Управление версиями Используйте appVersion, чтобы явно указать версию, для которой применяется миграция, и предотвратить повторное выполнение.
  4. Тестовое покрытие Проверяйте миграции на тестовом сервере (Mock Server) перед запуском обновления в реальной среде.