
# Birleştirme Planları

Bir `MergeResult`, birleştirmenin çalıştırılabilir çıktısıdır. Bir `MergePlan`, bu çıktının incelenebilir biçimidir. Bir uygulamanın hedef veritabanına yazmadan önce veritabanı değişikliklerini göstermesi, hazırlaması, serileştirmesi veya seçerek uygulaması gerektiğinde bunu kullanın.

```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()`, adı belirtilen üç anlık görüntüyü yükler ve `Merql::merge()` gibi sütun düzeyinde birleştirir. TEXT ve JSON sütunları için hücre düzeyinde birleştirme kullanan bir plan oluşturmak üzere sonucu kendiniz oluşturup `MergePlanBuilder` öğesine iletin:

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

Plan şunları içerir:

- Oluşturulurken kullanılan anlık görüntü adları,
- İşlemlerin, çakışmaların, şema uyuşmazlıklarının, tabloların ve grupların özeti,
- Kararlı işlem kimlikleri,
- Kararlı değişiklik grubu kimlikleri,
- Satır kimlik sütunları ve kimlik değerleri,
- Her işlem için base, ours, theirs ve sonuç satır değerleri,
- İsteğe bağlı ana uygulama meta verileri,
- Plan karması,
- Şema sürümü.

## Kararlı kimlikler

Aynı işlem içeriği için işlem kimlikleri deterministiktir. Tablo adından, satır anahtarından, işlem türünden, işlem kaynağından, değiştirilen sütunlardan ve sonuç değerlerinden türetilir.

Aynı grup içeriği için değişiklik grubu kimlikleri deterministiktir. Varsayılan oluşturucu her işlem için bir işlem grubu oluşturur. Ana uygulamalar, işlem listesinden daha büyük ve alana özgü gruplar oluşturabilir ve bunları yine aynı DTO biçimiyle serileştirebilir.

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

## İşlem yapısı

Her `MergePlanOperation` inceleme ve geri alma için yeterli bağlamı korur.

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

## Seçimler

UI grupları hazırlarken `ChangeGroupSelection` kullanın. Uygulama yaparken veya geri alma yapıtları oluştururken bunu bir `OperationSelection` öğesine dönüştürün.

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

Seçilen sonuç, yalnızca seçili işlemleri içeren temiz bir `MergeResult` olur. `Merql::apply()` veya `Merql::applyGuarded()` öğesine iletilebilir.

## Hedefte Eksik Olanları Seçme

Bir plan her iki tarafın işlemlerini de içerir; çünkü birleştirme sonucu base'i birleştirilmiş duruma dönüştürür. Hedefte taraflardan biri zaten varsa yalnızca onda henüz bulunmayan işlemleri seçin. Theirs'i tutan bir hedefe, örneğin sandbox kopyasındaki düzenlemeleri alan canlı bir veritabanına, `ours` kaynağına sahip tüm işlemler ve her iki tarafın sütun değişikliklerini birleştiren `merged` güncellemeleri gönderilir:

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

`theirs` kaynağına sahip işlemler ve `merged` silmeleri (her iki tarafın da sildiği satırlar) hedefte zaten bulunur.

Çakışmalar içeren bir birleştirmeden oluşturulan plan, her iki tarafın da güncellediği çakışmalı satırların her biri için yine bir işlem listeler. Sonuç değerleri, çakışan sütunda ours değerini tutar ve `SelectedMergeResultFactory` her seçim için temiz bir sonuç döndürür. İşlemin ve değişiklik grubunun `conflictState` alanları bu durumda da `clean` olarak görünür ([#9](https://github.com/inline0/merql/issues/9)); bu nedenle yukarıda belirtildiği gibi `$plan->conflicts` öğesini kendiniz denetleyin veya çakışmaları `ConflictResolver` ile çözerek planı çözümlenmiş sonuçtan `MergePlanBuilder` ile oluşturun. Seçimi canlı satır ön koşullarıyla yazmak için bkz. [Korumalı Uygulama](https://merql.inline0.dev/tr/docs/apply/guarded).

## Serileştirme

Birleştirme planları ve seçimleri kararlı JSON serileştirmesine sahiptir. Daha sonraki bir uygulama adımında gözden geçirilmiş işlem kümesinin aynısının kullanılması gerekiyorsa serileştirilmiş planı saklayın.

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

## Takma Adlı Anlık Görüntüler

Birleştirme planları standart tablo adlarını kullanır. Fiziksel tablo adları ortamlar arasında farklıysa planlamadan önce bunları aynı standart ad altında kaydedin.

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

Anlık görüntüde saklanan şema, fiziksel tablonun sütunlarını, anahtarlarını, kimlik sütunlarını, satır anahtarlarını ve filtrelerini korurken standart tablo adını kullanır.
