
# Vrátenie zmien

Plány na vrátenie zmien opisujú, ako zrušiť vybrané operácie zlúčenia po ich použití. Vytvárajú sa pred použitím, na základe presných aktuálnych riadkov, ktoré existujú bezprostredne pred zápisom.

Plán na vrátenie zmien nevytvárajte iba zo základnej snímky. Základný stav je spoločný predok, nie nevyhnutne aktuálny stav, ktorý sa prepisuje.

## Vytvorenie plánu na vrátenie zmien

```php
use Merql\Plan\ChangeGroupSelection;
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Snapshot\SnapshotStore;

$selection = ChangeGroupSelection::fromIds([$plan->changeGroups[0]->id]);
$operationSelection = $selection->toOperationSelection($plan);
$expectedLive = SnapshotStore::load($plan->theirsSnapshot);

$liveBeforeRows = [];
foreach ($plan->operations as $operation) {
    if (!$operationSelection->contains($operation->id)) {
        continue;
    }

    $liveBeforeRows[$operation->id] = $expectedLive
        ->getTable($operation->table)
        ?->getRow($operation->rowKey);
}

$rollback = (new RollbackPlanBuilder())->build(
    'rollback-1',
    $plan,
    $operationSelection,
    $liveBeforeRows,
    metadata: ['promotion_id' => 'promotion-1'],
);
```

Plán obsahuje:

- ID plánu zlúčenia,
- ID vybraných operácií,
- dotknuté tabuľky,
- opačné operácie,
- pôvodné riadky,
- očakávané výsledné riadky,
- metadáta,
- haš vrátenia zmien,
- verziu schémy.

## Kontrola odchýlok

Pred použitím plánu na vrátenie zmien porovnajte aktuálne riadky s očakávanými výslednými riadkami v pláne. Ak sa od povýšenia zmenil ktorýkoľvek riadok, predvolene operáciu prerušte.

```php
use Merql\Rollback\RollbackDrift;

$currentRows = [
    $operationId => $currentLiveRow,
];

$drifted = (new RollbackDrift())->driftedOperationIds($rollback, $currentRows);

if ($drifted !== []) {
    throw new RuntimeException('Rollback drifted: ' . implode(', ', $drifted));
}
```

Kontrola odchýlok porovnáva odtlačky riadkov, takže na poradí stĺpcov nezáleží.

## Použitie plánu na vrátenie zmien

Ak sa nevyskytli odchýlky, použite opačné operácie.

```php
use Merql\Rollback\RollbackPlanApplier;

$applied = (new RollbackPlanApplier($connection))->apply($rollback);

if ($applied->hasErrors()) {
    foreach ($applied->errors() as $error) {
        echo $error . "\n";
    }
}
```

Vrátenie zmien použije bežné `MergeResult` vytvorené z opačných operácií. Prebieha rovnakou cestou transakčného vykonávateľa ako bežné použitie zlúčenia.

## Serializácia

Plány na vrátenie zmien uložte pred použitím zlúčenia vpred. Tento artefakt je trvalým podkladom na neskoršie vrátenie zmien.

```php
use Merql\Rollback\RollbackPlanSerializer;

$json = RollbackPlanSerializer::toJson($rollback);
$restored = RollbackPlanSerializer::fromJson($json);
```

Aplikácie by mali uložiť serializovaný plán spolu s operáciou, ktorá vykonala zápis do aktuálnej databázy, a s prípadnými auditnými metadátami špecifickými pre hostiteľskú aplikáciu.
