ここ10年くらいバックエンドはRuby on Railsで開発していました。Ruby on Railsの良いところはいろいろありますが、一定スタイルの開発を支援するツールが組み込まれていることです。その1つがマイグレーションです。
マイグレーション機能の良いところは、
- RDB実装に依存しないDSLでテーブル作成・変更が書ける
- テーブル作成・変更の履歴が直ぐにわかる
- 本番サーバーやCIサーバーにデプロイした際、テーブル作成・変更が自動的に実行される
- テーブル作成・変更に問題があった場合、前の状態に戻せる
などです。Ruby on Rails以降に作られたWebフレームワークや、各プログラム言語に単体のマイグレーションツールが作られています。 参考→2021年度最新版スタンドアロンDBマイグレーションツールの比較
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がお薦めです。