Hoppa till innehåll

Sammanslagningsplaner

En MergeResult är det körbara resultatet av en sammanslagning. En MergePlan är en granskningsbar version av resultatet. Använd den när en applikation behöver visa, förbereda, serialisera eller selektivt tillämpa databasändringar innan de skrivs till måldatabasen.

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() läser in de tre namngivna ögonblicksbilderna och slår samman dem på kolumnnivå, precis som Merql::merge(). Om du vill planera en sammanslagning som använder sammanslagning på cellnivå för kolumner av typen TEXT och JSON skapar du resultatet själv och skickar det till 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);

Planen innehåller:

  • namnen på ögonblicksbilderna som användes för att skapa den,
  • en sammanfattning av åtgärder, konflikter, schemamissmatchningar, tabeller och grupper,
  • stabila åtgärds-ID:n,
  • stabila ID:n för ändringsgrupper,
  • radens identitetskolumner och identitetsvärden,
  • basvärden, värden från vår sida och deras sida samt resultatvärden för varje åtgärd,
  • valfria metadata från värdapplikationen,
  • en planhash,
  • en schemaversion.

Stabila ID:n

Åtgärds-ID:n är deterministiska för samma åtgärdsinnehåll. De härleds från tabellnamn, radnyckel, åtgärdstyp, åtgärdskälla, ändrade kolumner och resultatvärden.

ID:n för ändringsgrupper är deterministiska för samma gruppinnehåll. Standardbyggaren skapar en åtgärdsgrupp per åtgärd. Värdapplikationer kan skapa större domänspecifika grupper från åtgärdslistan och ändå serialisera dem med samma DTO-form.

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

Åtgärdens struktur

Varje MergePlanOperation innehåller tillräckligt med sammanhang för granskning och återställning.

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

Urval

Använd ChangeGroupSelection när UI förbereder grupper. Omvandla den till en OperationSelection när ändringarna tillämpas eller återställningsartefakter skapas.

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),
);

Det valda resultatet är ett rent MergeResult som endast innehåller valda åtgärder. Det kan skickas till Merql::apply() eller Merql::applyGuarded().

Välja vad ett mål saknar

En plan innehåller båda sidornas operationer, eftersom sammanslagningsresultatet omvandlar basen till det sammanslagna tillståndet. När målet redan innehåller den ena sidan väljer du bara de operationer som det ännu saknar. För ett mål som innehåller deras ändringar, till exempel en aktiv databas som tar emot ändringar från en sandlåsekopia, är det varje operation med källa ours, plus merged-uppdateringar, som kombinerar båda sidornas kolumnändringar:

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),
);

Operationer med källa theirs och merged-borttagningar (rader som båda sidor har tagit bort) finns redan i det målet.

En plan som byggts från en sammanslagning med konflikter listar fortfarande en operation för varje konfliktrad som båda sidor har uppdaterat. Resultatvärdena innehåller vårt värde i den konfliktande kolumnen, och SelectedMergeResultFactory ger ett rent resultat för alla val. Operationens och ändringsgruppens conflictState visar för närvarande clean även då (#9), så kontrollera $plan->conflicts själv enligt ovan, eller lös konflikterna med ConflictResolver och bygg planen från det lösta resultatet med MergePlanBuilder. Se Skyddad tillämpning för att skriva urvalet med förvillkor för aktuella rader.

Serialisering

Sammanslagningsplaner och urval har en stabil serialisering med JSON. Spara den serialiserade planen när ett senare tillämpningssteg måste använda exakt den granskade operationsuppsättningen.

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),
);

Alias-ögonblicksbilder

Sammanslagningsplaner använder kanoniska tabellnamn. Om de fysiska tabellnamnen skiljer sig åt mellan miljöer ska du samla in dem under samma kanoniska namn innan du skapar en plan.

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',
]));

Schemat som lagras i ögonblicksbilden använder det kanoniska tabellnamnet, samtidigt som kolumner, nycklar, identitetskolumner, radnycklar och filter från den fysiska tabellen bevaras.