Должен ли я написать обратную операцию для отката миграции? - PullRequest
1 голос
/ 14 мая 2019

Я использую knex.js, и это хороший построитель запросов для PostgreSQL. Я не нашел никаких документов, объясняющих, как правильно выполнить откат миграции.

Сейчас я просто пишу операцию обратного переноса в функции down, чтобы выполнить откат переноса. Это правильный путь?

import * as Knex from 'knex';

exports.up = async (knex: Knex): Promise<any> => {
  await knex.schema.raw(`
    ALTER TABLE IF EXISTS "GOOGLE_CHANNEL" 
    ADD COLUMN IF NOT EXISTS google_channel_ad_group_cpc_bid INTEGER NOT NULL DEFAULT 0;
  `);

  await knex.schema.raw(`
    UPDATE "GOOGLE_CHANNEL" as gc
    SET
      google_channel_ad_group_cpc_bid = 7
    FROM "CAMPAIGN_TEMPLATE" as ct
    WHERE ct.campaign_channel_id = gc.campaign_channel_id;
  `);
};

exports.down = async (knex: Knex): Promise<any> => {
  // TODO: migration rollback
  await knex.schema.raw(``);
};

У меня есть две проблемы:

  1. Если в функции up много операторов SQL, мне нужно написать множество операторов SQL в функции down, чтобы откатить миграцию.

  2. Почему knex.js не выполняет откат миграции без написания обратной операции для нас? Я имею в виду, что knex.js может сделать снимок или записать точку сохранения базы данных.

1 Ответ

1 голос
/ 14 мая 2019

Да, для отката вы используете функцию down скрипта миграции. При запуске knex migrate:rollback будет работать функция down. В базе данных Knex есть мета-таблицы, которые используются для определения, какие миграции выполнялись или нет.

Например:

exports.up = function (knex, Promise) {
  return knex.schema
    .createTable('role', function (table) {
      table.increments('role_id').primary();
      table.string('title').notNullable().unique();
      table.string('description');
      table.integer('level').notNullable(),
    })
    .createTable('user_account', function (table) {
      table.increments('user_id').primary();
      table.integer('role_id').references('role_id').inTable('role').notNullable();
      table.string('username').notNullable().unique();
      table.string('passwordHashed').notNullable();
      table.string('email', 50).notNullable().unique();
    });
};

exports.down = function (knex, Promise) {
  return knex.schema
    .dropTable('user_account')
    .dropTable('role');
};

Здесь я создаю две таблицы в функции up. user_account имеет ограничение внешнего ключа и связывается с таблицей role, что означает, что мне нужно удалить таблицу user_account перед таблицей role в функции down.

В вашем случае вы используете оператор обновления. В функции down вы должны либо сделать новое обновление с жестко запрограммированным значением (старое до миграции), либо убедиться, что вы сохранили старое значение в таблице истории.

Что касается ваших проблем:

  1. Да, если вы добавляете много вещей, вы также должны добавить много кода, чтобы полностью изменить то, что вы делаете. Тем не менее, вы можете пропустить создание сценариев down, но тогда вы не сможете выполнить откат. Некоторые (многие?) Предпочитают только идти вперед и никогда не отступать. Если им нужно что-то исправить, они не откатываются, а создают новый сценарий миграции с исправлением.

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

  2. Я не могу ответить за создателей Knex здесь. Однако то, что вы описываете как потенциальное решение, - это, в основном, резервное копирование базы данных перед выполнением миграции. В конце концов, миграция делает больше, чем просто меняет расположение таблиц и т. Д. Сценарий миграции обычно добавляет или удаляет новые строки. Вы можете использовать подход резервного копирования, но вы должны сделать резервные копии самостоятельно.

    Knex - довольно простой построитель запросов. Если вы хотите, чтобы скрипты миграции были написаны для вас, вы, возможно, захотите использовать полноценный OR mapper.

...