
# Egyesítési tervek

A `MergeResult` az egyesítés végrehajtható eredménye. A `MergePlan` ennek az eredménynek a
megvizsgálható formája. Akkor használja, ha az alkalmazásnak az adatbázisba írás előtt meg kell jelenítenie, elő kell készítenie, szerializálnia vagy szelektíven alkalmaznia kell az adatbázis-módosításokat.

```php
use Merql\Merql;

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

A `Merql::plan()` betölti a három megnevezett pillanatképet, és oszlopszinten egyesíti őket,
ugyanúgy, mint a(z) `Merql::merge()`. Ha olyan egyesítést szeretne megtervezni, amely TEXT és JSON oszlopoknál cellaszintű egyesítést használ, hozza létre saját maga az eredményt, és adja át a(z) `MergePlanBuilder` számára:

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

A terv tartalma:

- az elkészítéséhez használt pillanatképek nevei,
- a műveletek, ütközések, sémakülönbségek, táblák és csoportok összefoglalója,
- stabil műveletazonosítók,
- stabil módosításcsoport-azonosítók,
- a sorazonosító oszlopok és azonosítóértékek,
- minden művelet alap-, ours-, theirs- és eredménybeli sorértékei,
- opcionális, befogadó alkalmazásra vonatkozó metaadatok,
- a terv hashértéke,
- a sémaverzió.

## Stabil azonosítók

Azonos művelettartalom esetén a műveletazonosítók determinisztikusak. A tábla nevéből, a sorkulcsból, a művelet típusából, a művelet forrásából, a módosított oszlopokból és az eredményértékekből származnak.

Azonos csoporttartalom esetén a módosításcsoport-azonosítók determinisztikusak. Az alapértelmezett tervkészítő műveletenként egy műveletcsoportot hoz létre. A befogadó alkalmazások nagyobb, saját üzleti logikához igazított csoportokat állíthatnak össze a műveletlistából, és ugyanazzal a DTO-alakkal szerializálhatják őket.

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

## Művelet szerkezete

Minden `MergePlanOperation` elegendő kontextust tartalmaz az áttekintéshez és a visszaállításhoz.

```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
```

## Kijelölések

A(z) `ChangeGroupSelection` értéket használja, ha a(z) UI csoportokat készít elő. Alkalmazáskor vagy visszaállítási melléktermékek létrehozásakor alakítsa át `OperationSelection` értékké.

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

A kiválasztott eredmény egy tiszta `MergeResult`, amely csak a kijelölt műveleteket tartalmazza. Átadható a(z) `Merql::apply()` vagy `Merql::applyGuarded()` számára.

## Annak kijelölése, ami még hiányzik a célból

A terv mindkét oldal műveleteit tartalmazza, mert az egyesítési eredmény a base állapotot alakítja át az egyesített állapottá. Ha a cél már az egyik oldal állapotát tartalmazza, csak azokat a műveleteket jelölje ki, amelyek még hiányoznak belőle. Ha a cél a theirs állapotát tartalmazza, például egy éles adatbázis egy sandboxmásolat módosításait fogadja, ez minden `ours` forrású művelet, valamint a `merged` frissítések, amelyek a két oldal oszlopmódosításait egyesítik:

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

Az `theirs` forrású műveletek és az `merged` törlések (azok a sorok, amelyeket mindkét oldal törölt) már szerepelnek ebben a célban.

Az ütközésekkel járó egyesítésből készített terv továbbra is tartalmaz egy műveletet minden olyan ütköző sorhoz, amelyet mindkét oldal frissített. Eredményértékei az ütköző oszlopban az ours értékét tartalmazzák, az `SelectedMergeResultFactory` pedig bármely kijelöléshez tiszta eredményt ad vissza. A művelet és a módosításcsoport `conflictState` mezője még ilyenkor is `clean` értéket ad vissza ([#9](https://github.com/inline0/merql/issues/9)), ezért ellenőrizze saját maga a(z) `$plan->conflicts` értékét a fentiek szerint, vagy oldja fel az ütközéseket a(z) `ConflictResolver` használatával, majd készítse el a tervet a feloldott eredményből a(z) `MergePlanBuilder` segítségével. A kijelölés éles sorokra vonatkozó előfeltételekkel történő kiírásához lásd: [Védett alkalmazás](https://merql.inline0.dev/hu/docs/apply/guarded).

## Sorosítás

Az egyesítési tervek és kijelölések szerializálása stabil JSON formátumú. Ha egy későbbi alkalmazási lépésnek pontosan az áttekintett műveletkészletre van szüksége, tárolja a szerializált tervet.

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

## Aliasolt pillanatképek

Az egyesítési tervek kanonikus táblaneveket használnak. Ha a fizikai táblanevek eltérnek a környezetek között, a tervezés előtt rögzítse őket ugyanazon kanonikus név alatt.

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

A pillanatképben tárolt séma a kanonikus táblanevet használja, miközben megőrzi a fizikai tábla oszlopait, kulcsait, identitásoszlopait, sorkulcsait és szűrőit.
