Lite-версия мигратора Flyway для PostgreSQL на TypeScript

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Описание

В своих проектах для управления миграциями баз данных я всегда использую Flyway, включая некоторые важные компоненты его экосистемы:

  1. Versioned migrations — это стандартные миграции, которые применяются последовательно друг за другом.

  2. Repeatable migrations — это повторяемые миграции, например, скрипты для создания процедур. Они позволяют отслеживать историю изменений с помощью Git.

  3. Callbacks — это различные хуки, которые срабатывают в определённое время. Например, можно создать скрипт beforeMigrate__init_types.sql, в котором описаны все кастомные типы, используемые в базе данных. Мигратор сначала выполняет этот скрипт, а затем остальные операции.

Так как мои проекты преимущественно основаны на Node.js, я использую Node.js-обёртку для Flyway — node-flywaydb. Этот инструмент очень прост в использовании: при запуске он скачивает оригинальную Java-утилиту и запускает её, поэтому для работы требуется наличие JVM на машине.

Проблема

Когда мы создаем Docker-образы, предназначенные для запуска миграций базы данных, нам приходится включать в них JVM, что значительно увеличивает размер образа и замедляет весь CI/CD-процесс.

Возможные решения

  1. Использовать Node.js-миграторы (например: db-migrate, umzug, pg-migrate).

  2. Использовать миграторы, встроенные в ORM, применяемую в проекте (например: prisma, typeorm).

  3. Написать лёгкий клон Flyway на Node.js для одного типа базы данных (PostgreSQL).

Принятое решение

Так как я активно использую возможности Flyway, такие как repeatable migrations и callbacks, и не хочу от них отказываться, а аналогов этих функций в других системах миграции нет, я решил написать собственный лёгкий клон Flyway на Node.js для PostgreSQL, что и было сделано.

Этапы разработки

  1. Versioned migrations — выполнено.

  2. Repeatable migrations — выполнено.

  3. Callbacks — частично выполнено, только для versioned.

  4. Flyway schema history table — частично выполнена, только для versioned и repeatable.

  5. Migration Command Dry Runs — выполнено.

  6. Baseline migrations — не выполнено.

  7. Undo migrations — не выполнено.

  8. Script migrations — не выполнено.

  9. Migration transaction handling — не выполнено.

Там у них действительно много интересных возможностей, я перечислил только те, которые были наиболее полезными в моей практике.

Пример использования

Запуск базы данных

Для запуска базы данных выполните следующую команду:

curl -fsSL https://raw.githubusercontent.com/EndyKaufman/pg-tools/refs/heads/master/docker-compose.yml -o docker-compose.yml
docker compose up -d

Результатом будет успешный запуск контейнера PostgreSQL:

[+] Running 3/3
 ✔ Network pg-tools_default              Created                         0.1s
 ✔ Volume "pg-tools-postgre-sql-volume"  Created                         0.0s
 ✔ Container pg-tools-postgre-sql        Started                         0.2s

Создание миграции

Для создания первой миграции выполните следующую команду:

npx pg-flyway create --name=Init --version=1
echo "CREATE TABLE \"User\"(id uuid NOT NULL DEFAULT uuid_generate_v4() constraint PK_USER primary key,email varchar(20));" > migrations/V1__Init.sql

Результатом будет успешное создание пустой миграции:

[2025-01-15T23:23:53.903] [INFO] CreateEmptyMigrationService - Name: Init
[2025-01-15T23:23:53.904] [INFO] CreateEmptyMigrationService - Locations: migrations
[2025-01-15T23:23:53.914] [INFO] CreateEmptyMigrationService - Migration "migrations/V1__Init.sql" was created successfully!

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

Для применения созданной миграции выполните следующую команду:

npx pg-flyway migrate --database-url=postgres://pgtoolsusername:pgtoolspassword@localhost:5432/pgtoolsdatabase?schema=public

Результатом будет успешное выполнение миграции:

[2025-01-16T00:08:39.052] [INFO] MigrateService - Locations: migrations
[2025-01-16T00:08:39.053] [INFO] MigrateService - HistoryTable: __migrations
[2025-01-16T00:08:39.053] [INFO] MigrateService - DatabaseUrl: postgres://pgtoolsusername:pgtoolspassword@localhost:5432/pgtoolsdatabase?schema=public
[2025-01-16T00:08:39.074] [INFO] MigrateService - Migrations: 1

Просмотр списка выполненных миграций

Для просмотра списка выполненных миграций выполните следующую команду:

npx pg-flyway info --database-url=postgres://pgtoolsusername:pgtoolspassword@localhost:5432/pgtoolsdatabase?schema=public

Результатом будет таблица с информацией о выполненных миграциях:

[2025-01-16T09:15:34.007] [INFO] info - HistoryTable: __migrations
[2025-01-16T09:15:34.008] [INFO] info - DatabaseUrl: postgres://pgtoolsusername:pgtoolspassword@localhost:5432/pgtoolsdatabase?schema=public
[2025-01-16T09:15:34.057] [INFO] info - Migrations: 1
┌───────────┬─────────┬─────────────┬──────┬─────────────────────┬─────────┬──────────┐
│  Category │ Version │ Description │ Type │        Installed On │   State │ Undoable │
├───────────┼─────────┼─────────────┼──────┼─────────────────────┼─────────┼──────────┤
│ Versioned │       1 │        Init │  SQL │ 2025-01-15 20:08:39 │ Success │       No │
└───────────┴─────────┴─────────────┴──────┴─────────────────────┴─────────┴──────────┘

Остановка базы данных

Для остановки базы данных выполните следующую команду:

docker compose down

Планы

Основные функции Flyway уже перенесены в Typescript-код, что обеспечивает необходимый функционал для большинства сценариев при работе с миграциями.

Остальные не портированные функции я планирую переносить по мере наличия свободного времени.

Буду рад pull-реквестам с новыми функциями и исправлением багов.

Ссылки

  • https://github.com/EndyKaufman/pg-tools - Репозиторий проекта

  • https://www.npmjs.com/package/pg-flyway - Утилита на NPM

  • https://www.npmjs.com/package/node-flywaydb - Враппер для Flyway (Java) на NodeJS

  • https://documentation.red-gate.com/flyway-concepts-271583830.html - Документация Flyway

Источник: https://habr.com/ru/articles/874028/


Интересные статьи

Интересные статьи

В общем задача звучала так: установить Redmine на сервер, где веб-сервер на nginx.Так как Redmine написан на RoR, то необходимо иметь RoR среду, но пр...
Я давно знаком с Битрикс24, ещё дольше с 1С-Битрикс и, конечно же, неоднократно имел дела с интернет-магазинами которые работают на нём. Да, конечно это дорого, долго, местами неуклюже...
SWAP (своп) — это механизм виртуальной памяти, при котором часть данных из оперативной памяти (ОЗУ) перемещается на хранение на HDD (жёсткий диск), SSD (твёрдотельный накоп...
Устраивать конкурсы в инстаграме сейчас модно. И удобно. Инстаграм предоставляет достаточно обширный API, который позволяет делать практически всё, что может сделать обычный пользователь ручками.
CRM — это, прежде всего, система, которая хранит и управляет информацией обо всех ваших взаимодействиях с бизнес-клиентами. На основании этой информации и ее обработки можно принимать деловые и д...