Lewati ke konten

Rencana Merge

MergeResult adalah keluaran merge yang dapat dieksekusi. MergePlan adalah bentuk keluaran tersebut yang dapat diperiksa. Gunakan saat aplikasi perlu menampilkan, menyiapkan, menserialisasi, atau menerapkan perubahan database secara selektif sebelum menulisnya ke database target.

PHP
use Merql\Merql;

$plan = Merql::plan(
    id: 'plan-2026-06-06',
    base: 'base',
    ours: 'ours',
    theirs: 'theirs',
    metadata: ['sandbox_id' => 'ow_123'],
);

Merql::plan() memuat tiga snapshot bernama dan menggabungkannya pada tingkat kolom, seperti Merql::merge(). Untuk merencanakan merge yang menggunakan penggabungan tingkat sel pada kolom TEXT dan JSON, buat sendiri hasilnya dan berikan ke MergePlanBuilder:

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Plan\MergePlanBuilder;
use Merql\Snapshot\SnapshotStore;

$base = SnapshotStore::load('base');
$ours = SnapshotStore::load('ours');
$theirs = SnapshotStore::load('theirs');

$result = (new ThreeWayMerge(CellMergeConfig::auto()))->merge($base, $ours, $theirs);
$plan = (new MergePlanBuilder())->build('plan-2026-06-06', $base, $ours, $theirs, $result);

Rencana ini berisi:

  • nama snapshot yang digunakan untuk membuatnya,
  • ringkasan operasi, konflik, ketidakcocokan skema, tabel, dan grup,
  • ID operasi stabil,
  • ID grup perubahan stabil,
  • kolom identitas baris dan nilai identitas,
  • nilai baris base, ours, theirs, dan hasil untuk setiap operasi,
  • metadata aplikasi host opsional,
  • hash rencana,
  • versi skema.

ID Stabil

ID operasi bersifat deterministik untuk konten operasi yang sama. ID ini diturunkan dari nama tabel, kunci baris, jenis operasi, sumber operasi, kolom yang diubah, dan nilai hasil.

ID grup perubahan bersifat deterministik untuk konten grup yang sama. Builder default membuat satu grup operasi untuk setiap operasi. Aplikasi host dapat membuat grup khusus domain yang lebih besar dari daftar operasi dan tetap menserialisasikannya dengan bentuk DTO yang sama.

PHP
foreach ($plan->changeGroups as $group) {
    echo $group->id . ': ' . implode(', ', $group->operationIds);
}

Bentuk Operasi

Setiap MergePlanOperation menyimpan konteks yang cukup untuk ditinjau dan dikembalikan.

PHP
$operation = $plan->operations[0];

$operation->id;              // stable operation ID
$operation->type;            // insert, update, delete
$operation->table;           // canonical table name
$operation->rowKey;          // encoded identity key
$operation->identityColumns; // columns used for identity
$operation->identityValues;  // decoded identity values
$operation->source;          // ours, theirs, or merged
$operation->baseRow;         // row in base snapshot, or null
$operation->oursRow;         // row in ours snapshot, or null
$operation->theirsRow;       // row in theirs snapshot, or null
$operation->resultValues;    // values the merge would write
$operation->changedColumns;  // changed result columns

Selections

Gunakan ChangeGroupSelection saat UI menyiapkan grup. Ubah menjadi OperationSelection saat menerapkan atau membuat artefak rollback.

PHP
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;

$selection = ChangeGroupSelection::fromIds([
    $plan->changeGroups[0]->id,
]);

$operationSelection = $selection->toOperationSelection($plan);

$selectedResult = (new SelectedMergeResultFactory())->fromOperationSelection(
    $plan,
    $operationSelection,
    SnapshotStore::load($plan->baseSnapshot),
);

Hasil yang dipilih adalah MergeResult bersih yang hanya berisi operasi terpilih. Hasil ini dapat diberikan ke Merql::apply() atau Merql::applyGuarded().

Memilih yang Belum Dimiliki Target

Rencana berisi operasi dari kedua sisi karena hasil merge mengubah base menjadi keadaan gabungan. Jika target sudah memiliki salah satu sisi, pilih hanya operasi yang belum dimilikinya. Untuk target yang memiliki theirs, misalnya database aktif yang menerima perubahan dari salinan sandbox, pilih semua operasi dengan sumber ours, ditambah pembaruan merged yang menggabungkan perubahan kolom dari kedua sisi:

PHP
use Merql\Plan\OperationSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;

// Rows with an unresolved conflict stay out of the selection.
$conflicted = [];
foreach ($plan->conflicts as $conflict) {
    $conflicted[$conflict->table . "\0" . $conflict->rowKey] = true;
}

$ids = [];
foreach ($plan->operations as $operation) {
    $missing = $operation->source === 'ours'
        || ($operation->source === 'merged' && $operation->type === 'update');

    if ($missing && !isset($conflicted[$operation->table . "\0" . $operation->rowKey])) {
        $ids[] = $operation->id;
    }
}

$selected = (new SelectedMergeResultFactory())->fromOperationSelection(
    $plan,
    OperationSelection::fromIds($ids),
    SnapshotStore::load($plan->baseSnapshot),
);

Operasi dengan sumber theirs dan penghapusan merged (baris yang dihapus oleh kedua sisi) sudah ada di target tersebut.

Rencana yang dibuat dari merge dengan konflik tetap mencantumkan operasi untuk setiap baris berkonflik yang diperbarui oleh kedua sisi. Nilai hasilnya menyimpan nilai ours pada kolom yang berkonflik, dan SelectedMergeResultFactory menghasilkan hasil bersih untuk pilihan apa pun. Bahkan dalam kondisi itu, conflictState operasi dan grup perubahan saat ini bernilai clean (#9), jadi periksa sendiri $plan->conflicts seperti di atas, atau selesaikan konflik dengan ConflictResolver lalu buat rencana dari hasil yang telah diselesaikan menggunakan MergePlanBuilder. Lihat Penerapan Terjaga untuk menulis pilihan dengan prasyarat baris aktif.

Serialisasi

Rencana merge dan pilihan memiliki serialisasi JSON yang stabil. Simpan rencana yang telah diserialisasi jika langkah penerapan berikutnya harus menggunakan kumpulan operasi yang persis sama dengan yang ditinjau.

PHP
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\MergePlanSerializer;

$json = MergePlanSerializer::toJson($plan);
$restored = MergePlanSerializer::fromJson($json);

$selectionJson = json_encode($selection->toArray(), JSON_THROW_ON_ERROR);
$selection = ChangeGroupSelection::fromArray(
    json_decode($selectionJson, true, flags: JSON_THROW_ON_ERROR),
);

Snapshot dengan Alias

Rencana merge menggunakan nama tabel kanonis. Jika nama tabel fisik berbeda antarlingkungan, ambil snapshot dengan nama kanonis yang sama sebelum merencanakan merge.

PHP
use Merql\Snapshot\SnapshotStore;
use Merql\Snapshot\Snapshotter;

$snapshotter = new Snapshotter($connection);

SnapshotStore::save($snapshotter->captureAliased('live', [
    'wp_posts' => 'wp_posts',
]));

SnapshotStore::save($snapshotter->captureAliased('sandbox', [
    'wp_onumia_abc_posts' => 'wp_posts',
]));

Skema yang disimpan dalam snapshot menggunakan nama tabel kanonis sambil mempertahankan kolom, kunci, kolom identitas, kunci baris, dan filter tabel fisik.