
# Povrnitev

Načrti za povrnitev opisujejo, kako razveljaviti izbrane operacije združitve po njihovi uporabi. Ustvarijo se pred uporabo na podlagi natančnih aktivnih vrstic, ki obstajajo tik pred zapisom.

Načrta za povrnitev ne ustvarjajte samo iz osnovnega posnetka. Osnova je skupni prednik in ni nujno enaka aktivnemu stanju, ki ga boste prepisali.

## Ustvarjanje načrta za povrnitev

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

Načrt shranjuje:

- ID načrta združitve,
- ID-je izbranih operacij,
- tabele, na katere vpliva,
- obratne operacije,
- vrstice pred spremembo,
- pričakovane vrstice po spremembi,
- metapodatke,
- zgoščeno vrednost povrnitve,
- različico sheme.

## Preverjanje odstopanj

Pred uporabo povrnitve primerjajte trenutne aktivne vrstice s pričakovanimi vrsticami po spremembi v načrtu za povrnitev. Če se je katera koli vrstica od uveljavitve spremenila, se postopek privzeto prekine.

```php
use Merql\Rollback\RollbackDrift;

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

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

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

Preverjanje odstopanj primerja prstne odtise vrstic, zato vrstni red stolpcev ni pomemben.

## Uporaba povrnitve

Če ni odstopanj, uporabite obratne operacije.

```php
use Merql\Rollback\RollbackPlanApplier;

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

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

Povrnitev uporabi običajen `MergeResult`, sestavljen iz obratnih operacij. Izvede se po isti poti za uporabo transakcij kot običajna uporaba združitve.

## Serializacija

Načrte za povrnitev shranite pred uporabo združitve naprej. Ta artefakt je trajna osnova za poznejšo povrnitev.

```php
use Merql\Rollback\RollbackPlanSerializer;

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

Aplikacije naj serializirani načrt shranijo skupaj z operacijo, ki je izvedla zapis v aktivno zbirko, ter z morebitnimi metapodatki za revizijo, značilnimi za gostitelja.
