Merql
純粋なPHPによる3ウェイデータベースマージと列レベルの競合解決。Git形式のマージセマンティクスをMySQLおよびSQLiteのテーブルに適用します。
composer require merql/merql最新リリース v0.4.1 MIT PHP 8.2+
use Merql\Merql;
Merql::init($connection);
// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');
// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);実践例
マージでは、保存済みの3つのスナップショットを読み込み、書き込み操作と解決すべき競合を返します。
3つのスナップショットをマージ
2つのコピーが分岐する前のベーススナップショットを取得し、ライブデータベースとサンドボックスのコピーなど、それぞれの側のスナップショットも取得します。ThreeWayMergeは両側をベースと比較し、2つの変更セットをマージします。
結果タブでは、oursが同じ行のcontentを編集し、theirsがtitleとstatusを編集しています。そのため、競合を起こさずに3つすべての編集が保持されます。
use Merql\Merge\ThreeWayMerge;
$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);
echo $result->operationCount(); // resolved operations
echo $result->conflictCount(); // unresolved conflictsBase: { title: "Hello", content: "Body", status: "draft" }
Ours: { title: "Hello", content: "Body v2", status: "draft" }
Theirs: { title: "New Title", content: "Body", status: "publish" }
Result: { title: "New Title", content: "Body v2", status: "publish" }3ウェイマージ
ベース、こちら側、相手側。行単位ではなく、キー付きの行と列を対象にしたgit形式の3方向マージです。2つのブランチ間の追加、更新、削除を検出します。
列レベルの解決
両側が同じ行を変更した場合、merqlは列ごとに比較します。同じ列が異なる値に変更された場合にのみ競合します。
オプトインのセルマージ
CellMergeConfigをThreeWayMergeに渡すと、TEXT列はMyers diffによる行単位のマージ、JSON列はキー単位のマージが行われます。MerqlファサードとCLIでは有効になりません。
複数のデータベース
接続アダプターと方言ドライバーをプラグインで追加でき、MySQLとSQLiteを標準で利用できます。
競合の検出
更新対更新、更新対削除、削除対更新、挿入対挿入をそれぞれテーブルと行とともに報告します。更新対更新の競合では列名も示します。
SQLの生成
外部キーを考慮した順序で、パラメーター化されたINSERT、UPDATE、DELETE文を生成します。ドライランでのプレビュー、またはトランザクション内での適用が可能です。
CLI
コマンドラインからスナップショット、差分、マージを実行できます。環境変数を使ってMySQLとSQLiteに対応します。
テスト済み
手書きの期待値を使った32の回帰シナリオ(composer test:oracle)。CIでは231件のユニットテストと統合テスト、およびPHPStanレベル10を実行します。
Merqlを選ぶ理由
スナップショットはファイル
各スナップショットは1つのJSONファイルで、マシン間でコピーしたり、バージョン管理にコミットしたりできます。差分比較とマージはこれらのファイルを読み込むため、データベース接続なしで実行できます。
書き込み前に確認
マージプランでは、各操作と変更グループに安定したIDを割り当て、ベース、ours、theirs、結果の各行を保持します。適用したいグループを選び、そのグループだけを反映できます。
古いプランは適用されない
保護付き適用では、確認したスナップショットと現在も一致する行だけを書き込みます。ステートメントが0行に作用した場合、トランザクションはロールバックされ、結果にエラーが含まれます。
差分確認付きロールバック
書き込み直前のライブ行からロールバックプランを作成し、JSONとして保存します。元に戻す前に差分確認で行のフィンガープリントを比較し、その後に変更された行に対する操作を返します。
との比較
Merqlは3つのスナップショットの行データをマージします。以下のツールはデータベースのバージョン管理、同期、移行を行うもので、隣接する用途です。
| ツール | 得意なこと | Merqlとの違い |
|---|---|---|
| Dolt | 得意なことDoltは、Gitリポジトリのようにフォーク、クローン、ブランチ作成、マージ、プッシュ、プルができるSQLデータベースです。MySQLデータベースと同じように接続でき、すべてのセルの系譜を追跡します。 | Merqlとの違いMerqlは、現在利用しているMySQLまたはSQLiteデータベースをそのまま使います。テーブルをJSONスナップショットファイルとして保存し、3つのファイルをマージします。ベーススナップショットは自分で選択します。 |
| pt-table-sync | 得意なことpt-table-syncはMySQLテーブル間の差分を検出して修正します。サーバー間で一方向または双方向に処理できます。レプリカを同期する場合、レプリケーション元に変更を加えます。 | Merqlとの違い双方向同期では、pt-table-syncは競合列に基づいて勝者となる行を選び、その値をコピーします。Merqlは共通のベースと両側を比較し、同じ行の異なる列への編集をマージします。互換性のない変更は解決すべき競合として報告します。 |
| sqldiff | 得意なことsqldiffは2つのSQLiteデータベースを比較し、1つ目を2つ目に変換するSQLスクリプトを出力します。SQLiteセッション拡張用のバイナリ変更セットを書き出したり、テーブルごとに変更された行を要約したりすることもできます。 | Merqlとの違い2方向の差分比較では、片側で行が追加されたのか、もう片側で削除されたのかを判断できません。Merqlはベーススナップショットを加えてこれを判別し、2組の変更をマージします。また、MySQLにも対応しています。 |
| Doctrine Migrations | 得意なことDoctrine Migrationsはデータベーススキーマのバージョンを管理するため、スキーマの変更を本番環境へのデプロイ前に確認してテストできます。 | Merqlとの違いMerqlはスキーマ移行ツールではありません。行データをマージし、スナップショット間で追加または削除された列を報告します。スキーマ変更は自分で行います。 |
質問と回答
Merqlのドキュメントから、簡潔に回答します。
PDOまたはmysqliアダプターを通じてMySQLとSQLiteに対応しています。別のエンジンを使う場合は、Driverインターフェースを実装するクラスを作成し、DriverFactory::register()に登録します。
いいえ。スキーマの移行、データベースのレプリケーション、リアルタイム同期は行いません。3つのデータベース状態を受け取り、競合を特定したうえで、マージ後の4つ目の状態を生成します。
両側が同じ行の同じ列を異なる値に変更した場合、一方が行を更新し、もう一方が削除した場合、または両側が同じキーの行を挿入した場合です。同じ行の異なる列への編集は問題なくマージされます。
いいえ。保存済みのスナップショットファイルを読み込むため、データベースに接続するのはスナップショットの取得時と結果の適用時だけです。
はい。マージプランを作成し、IDで変更グループを選択して、選択内容をMerql::apply()またはMerql::applyGuarded()向けのクリーンな結果に変換します。
CellMergeConfig(CellMergeConfig::auto()など)を指定してThreeWayMergeを構築した場合に限り、内部のマージを有効にできます。Merql::merge()、Merql::plan()、CLIは各列の値を全体として扱います。
最初のスナップショットから、マージプラン、保護付き適用、ロールバックまでガイドに沿って進めましょう。