Přejít k obsahu

Plány sloučení

MergeResult je spustitelným výstupem sloučení. MergePlan je jeho prohlížitelná podoba. Použijte jej, když aplikace potřebuje zobrazit, připravit, serializovat nebo selektivně použít změny databáze před zápisem do cílové databáze.

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() načte tři pojmenované snímky a sloučí je na úrovni sloupců, podobně jako Merql::merge(). Chcete-li naplánovat sloučení využívající sloučení na úrovni buněk pro sloupce TEXT a JSON, sestavte výsledek sami a předejte jej do 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);

Plán obsahuje:

  • názvy snímků použité k jeho vytvoření,
  • souhrn operací, konfliktů, nesouladů schématu, tabulek a skupin,
  • stabilní ID operací,
  • stabilní ID skupin změn,
  • sloupce identity řádků a hodnoty identity,
  • hodnoty řádků před sloučením, naše, jejich a výsledné,
  • volitelná metadata hostitelské aplikace,
  • hash plánu,
  • verzi schématu.

Stabilní ID

ID operací jsou deterministická pro stejný obsah operace. Odvozují se z názvu tabulky, klíče řádku, typu operace, zdroje operace, změněných sloupců a výsledných hodnot.

ID skupin změn jsou deterministická pro stejný obsah skupiny. Výchozí nástroj pro sestavení vytváří jednu skupinu operací na každou operaci. Hostitelské aplikace mohou ze seznamu operací sestavit větší skupiny specifické pro danou doménu a přesto je serializovat se stejným tvarem DTO.

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

Struktura operace

Každé MergePlanOperation uchovává dostatek kontextu pro kontrolu a vrácení změn.

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

Výběry

Použijte ChangeGroupSelection, když UI připravuje skupiny. Při použití změn nebo generování artefaktů pro vrácení změn jej převeďte na OperationSelection.

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

Vybraný výsledek je čisté MergeResult obsahující pouze vybrané operace. Lze jej předat do Merql::apply() nebo Merql::applyGuarded().

Výběr chybějících změn v cíli

Plán obsahuje operace obou stran, protože výsledek sloučení převede základ do sloučeného stavu. Pokud cíl již obsahuje stav jedné strany, vyberte pouze operace, které v něm ještě nejsou. U cíle se stavem jejich strany, například živé databáze přijímající úpravy ze sandboxové kopie, jde o každou operaci se zdrojem ours a také aktualizace merged, které kombinují změny sloupců obou stran:

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

Operace se zdrojem theirs a odstranění merged (řádky odstraněné oběma stranami) jsou v tomto cíli již obsaženy.

Plán vytvořený ze sloučení s konflikty stále uvádí operaci pro každý konfliktní řádek, který aktualizovaly obě strany. Jeho výsledné hodnoty obsahují hodnotu naší strany v konfliktním sloupci a SelectedMergeResultFactory vrací čistý výsledek pro jakýkoli výběr. Atributy conflictState operace i skupiny změn však i v takovém případě aktuálně mají hodnotu clean (#9). Proto si sami ověřte $plan->conflicts podle výše uvedeného postupu, nebo vyřešte konflikty pomocí ConflictResolver a sestavte plán z vyřešeného výsledku pomocí MergePlanBuilder. Pokyny k zápisu výběru s předběžnými podmínkami pro živé řádky najdete v části Guarded Apply.

Serializace

Plány sloučení a výběry mají stabilní serializaci JSON. Uložte serializovaný plán, pokud má pozdější krok použití změn využít přesně tu sadu operací, která byla zkontrolována.

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

Aliasy snímků

Plány sloučení používají kanonické názvy tabulek. Pokud se fyzické názvy tabulek v různých prostředích liší, před plánováním je zaznamenejte pod stejným kanonickým názvem.

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

Schéma uložené ve snímku používá kanonický název tabulky a zároveň zachovává sloupce, klíče, sloupce identity, klíče řádků a filtry fyzické tabulky.