EY-Office ブログ

PostgreSQL+Node.jsでDBマイグレーションをするならnode-pg-migrateが良いぞ!

ここ10年くらいバックエンドはRuby on Railsで開発していました。Ruby on Railsの良いところはいろいろありますが、一定スタイルの開発を支援するツールが組み込まれていることです。その1つがマイグレーションです。
マイグレーション機能の良いところは、

  1. RDB実装に依存しないDSLでテーブル作成・変更が書ける
  2. テーブル作成・変更の履歴が直ぐにわかる
  3. 本番サーバーやCIサーバーにデプロイした際、テーブル作成・変更が自動的に実行される
  4. テーブル作成・変更に問題があった場合、前の状態に戻せる

などです。Ruby on Rails以降に作られたWebフレームワークや、各プログラム言語に単体のマイグレーションツールが作られています。 参考→2021年度最新版スタンドアロンDBマイグレーションツールの比較

migrations

db-migrateにモヤモヤ

先ほど上げた2021年度最新版スタンドアロンDBマイグレーションツールの比較にもあるように、Node.jsではdb-migrate一強のようです。検索しても他のツールはほとんど出てきません。

テスト用のプロジェクトを作り、db-migrateを試してみました。今回はテーブル作成・変更記述にはDSLではなくSQLを使う事にするので一般的な評価とは異なるかもしれませんので。

マイグレーションファイルの作成には npx db-migrate create create_users --sql-file のようなコマンドラインで行います。実行後以下の3つのファイルが作成されます

migrations/sqls/20210830020655-create-users-down.sql
migrations/sqls/20210830020655-create-users-up.sql
migrations/20210830020655-create-users.js

20210830020655-create-users-down.sql、 20210830020655-create-users-up.sql ファイルは空でここにマイグレーション実行、取り消しのSQLを書きます。

  • 20210830020655-create-users-up.sql
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name VARCHAR NOT NULL,
  email VARCHAR NOT NULL,
  created_at TIMESTAMP DEFAULT current_timestamp
);
  • 20210830020655-create-users-down.sql
DROP TABLE users;

さて、20210830020655-create-users.jsファイルは何なんでしょうか?

'use strict';

var dbm;
var type;
var seed;
var fs = require('fs');
var path = require('path');
var Promise;

/**
  * We receive the dbmigrate dependency from dbmigrate initially.
  * This enables us to not have to rely on NODE_PATH.
  */
exports.setup = function(options, seedLink) {
  dbm = options.dbmigrate;
  type = dbm.dataType;
  seed = seedLink;
  Promise = options.Promise;
};

exports.up = function(db) {
  var filePath = path.join(__dirname, 'sqls', '20210830020655-create-users-up.sql');
  return new Promise( function( resolve, reject ) {
    fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
      if (err) return reject(err);
      console.log('received data: ' + data);

      resolve(data);
    });
  })
  .then(function(data) {
    return db.runSql(data);
  });
};

exports.down = function(db) {
  var filePath = path.join(__dirname, 'sqls', '20210830020655-create-users-down.sql');
  return new Promise( function( resolve, reject ) {
    fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
      if (err) return reject(err);
      console.log('received data: ' + data);

      resolve(data);
    });
  })
  .then(function(data) {
    return db.runSql(data);
  });
};

exports._meta = {
  "version": 1
};

20210830020655-create-users-up.sqlなどの、マイグレーションSQLファイルを読み込んでdb.runSql()関数でSQLを実行しています。何これ !?

ちなみにDSL(JavaScript)でマイグレーションファイルを作ると以下のようなファイルが作られます。そして exports.up = function(db) {return null;の間にテーブル作成・変更のDSL(JavaScriptのコード)を書きます。

'use strict';

var dbm;
var type;
var seed;

/**
  * We receive the dbmigrate dependency from dbmigrate initially.
  * This enables us to not have to rely on NODE_PATH.
  */
exports.setup = function(options, seedLink) {
  dbm = options.dbmigrate;
  type = dbm.dataType;
  seed = seedLink;
};

exports.up = function(db) {
  return null;
};

exports.down = function(db) {
  return null;
};

exports._meta = {
  "version": 1
};

なんとdb-migrateは、DSLベースのマイグレーション・ツールで、JavaScriptマイグレーション用ファイルでSQLファイルを読み込むという、SQLはおまけ的な扱いです。
さらに、upとdownのSQLファイルが分かれているのも気に入りません、downはupをもとに作るので同じファイルに書けた方が楽ですし、ファイルが増えるのは今ひとつです😅

他のツールは?

db-migrateをフォークして改造したらどうだろう?と思いましたがコードは昔のコールバック地獄コードでした。またマイグレーションファイルのテンプレートもコード内にハードコードされていて、やる気が無くなりました😅

他に良いツールはないのか?と調べだしました。試しにGoで書かれたsql-migrateを試してみましたが、これは良いツールです。SQLは1つのマイグレーションファイルに書けます。ただしマイグレーションツールのためだけにGo言語を開発環境や本番サーバーにインストルするのはなんだかな? と思います。

simple-db-migrateというツールも発見しましたがメンテされておらず、フォークし一部変更しないと動きませんでした、コマンドの使い勝手も良くありませんでした😅

node-pg-migrate

そんな時、検索結果に出てきたブログで紹介されていたnode-pg-migrateを発見しました。db-migrateを参考に作られたPostgreSQL専用ツールですがコードはTypeScriptで0から書かれたasync/awaitを使った今風のコードです。

試してみましたが、私の求めていたツールでした!

npx node-pg-migrate create create-users --migration-file-language=sql でマイグレーションファイルが作成されます。(--migration-file-language=sql指定は最初のマイグレーションファイル作成時のみ指定すればOKです😁)

1つのマイグレーションファイルにup/down両方のSQLが書けます。

-- Up Migration
CREATE TABLE a_users (
  id SERIAL PRIMARY KEY,
  name VARCHAR NOT NULL,
  email VARCHAR NOT NULL,
  created_at TIMESTAMP DEFAULT current_timestamp
);

-- Down Migration
DROP TABLE a_users;

ということで、PostgreSQL+Node.js環境でSQLを使ってDBマイグレーションを行うならnode-pg-migrateがお薦めです。

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ