
# Apvienošana šūnu līmenī

Kolonnu līmeņa sapludināšana nosaka, vai abas puses mainījušas vienu un to pašu kolonnu. Šūnu līmeņa sapludināšana darbojas detalizētāk, sapludinot šīs kolonnas saturu. Divu cilvēku veiktas izmaiņas dažādās TEXT lauka rindās vai dažādās JSON objekta atslēgās var sapludināt bez konfliktiem.

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;

$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);
```

## Šūnu līmeņa sapludināšanas iespējošana

Šūnu līmeņa sapludināšana pēc noklusējuma nav ieslēgta. Tā darbojas tikai `ThreeWayMerge`, kas izveidots ar `CellMergeConfig`. Bez tā ikviena kolonna, kurai abas puses mainījušas vērtību uz atšķirīgu vērtību, rada `update_update` konfliktu.

`Merql` fasāde nepieņem konfigurāciju: `Merql::merge()`, `Merql::patch()` un `Merql::plan()` izveido `new ThreeWayMerge()` bez tās, bet CLI komanda `merge` tiek izpildīta, izmantojot `Merql::merge()`. Tās vienmēr sapludina kolonnu līmenī ([#7](https://github.com/inline0/merql/issues/7)).

Lai sapludinātu fasādes vai CLI saglabātos momentuzņēmumus ar šūnu līmeņa sapludināšanu, ielādējiet tos un paši izsauciet `ThreeWayMerge`. Rezultāts ir parasts `MergeResult`, ko fasāde joprojām var lietot, un `MergePlanBuilder` to pārveido par [sapludināšanas plānu](https://merql.inline0.dev/lv/docs/merge/plans):

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Merql;
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-1', $base, $ours, $theirs, $result);
```

Šūnu sapludinātāji darbojas tikai kolonnām, kuras mainījušas abas puses. Ja kolonnu mainījusi tikai viena puse, tās vērtība tiek ņemta tāda, kāda tā ir.

## CellMergeConfig

`CellMergeConfig` sasaista kolonnas vai kolonnu tipus ar šūnu sapludinātāju implementācijām. `auto()` rūpnīca nodrošina saprātīgas noklusējuma vērtības:

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
use Merql\CellMerge\TextCellMerger;

// Auto: column types containing "text" (TEXT, MEDIUMTEXT, LONGTEXT, ...) use
// TextCellMerger, column types containing "json" use JsonCellMerger.
$config = CellMergeConfig::auto();

// Custom: assign mergers to specific columns.
$config = (new CellMergeConfig())
    ->forColumn('posts.content', new TextCellMerger())
    ->forColumn('settings', new JsonCellMerger())
    ->forType('json', new JsonCellMerger());
```

Sapludinātāja izvēles prioritāte:

1. Pilnais kolonnas nosaukums (`table.column`).
2. Kolonnas nosaukums bez prefiksa (`column`).
3. Atbilstība kolonnas tipa rakstam (reģistrnejutīgs `str_contains`).
4. Noklusējums: `OpaqueCellMerger` (vienmēr ziņo par konfliktu, ja vērtības atšķiras).

## TextCellMerger

Sapludina vairākrindu tekstu, izmantojot Myers diff — to pašu algoritmu, ko git izmanto failu saturam. Katra rinda tiek uzskatīta par vienību, un izmaiņas dažādās rindās saplūst bez konfliktiem.

```php
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();
```

### Piemērs: tīra teksta sapludināšana

```
Base:    "line one\nline two\nline three"
Ours:    "LINE ONE\nline two\nline three"    // changed line 1
Theirs:  "line one\nline two\nLINE THREE"    // changed line 3
```

Rediģētas dažādas rindas. Sapludināšanas rezultātā tiek iegūts `"LINE ONE\nline two\nLINE THREE"` bez konflikta.

### Piemērs: teksta konflikts

```
Base:    "line one\nline two"
Ours:    "changed by us\nline two"     // changed line 1
Theirs:  "changed by them\nline two"   // also changed line 1
```

Abas puses mainīja vienu un to pašu rindu uz atšķirīgām vērtībām. Sapludinātājs atgriež konflikta rezultātu. Sapludinātajā saturā ir konfliktu marķieri, kas līdzinās git marķieriem.

### Kā tas darbojas

`TextCellMerger` izmanto pitmaster `ThreeWayMerge::merge()`, kas aprēķina Myers diff starp bāzi un katru pusi un pēc tam apvieno abas izmaiņu secības. Ja izmaiņas pārklājas vienā un tajā pašā rindas apgabalā, tas ziņo par konfliktu.

## JsonCellMerger

Sapludina JSON objektus, neatkarīgi salīdzinot augstākā līmeņa atslēgas. Katra atslēga tiek sapludināta, izmantojot standarta trīsvirzienu noteikumus.

```php
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();
```

### Piemērs: tīra JSON sapludināšana

```json
// Base
{"name": "Alice", "role": "editor", "active": true}

// Ours: changed "role"
{"name": "Alice", "role": "admin", "active": true}

// Theirs: changed "name"
{"name": "Bob", "role": "editor", "active": true}
```

Mainītas dažādas atslēgas. Sapludināšanas rezultāts:

```json
{"name": "Bob", "role": "admin", "active": true}
```

### Piemērs: JSON konflikts

```json
// Base
{"color": "red"}

// Ours
{"color": "blue"}

// Theirs
{"color": "green"}
```

Abas puses mainīja `color` atslēgu uz atšķirīgām vērtībām. Tas ir konflikts. Pēc noklusējuma sapludinātājs izvēlas mūsu vērtību un ziņo par vienu konfliktu.

### Atslēgu līmeņa noteikumi

| Bāze | Mūsu | Viņu | Rezultāts |
|---|---|---|---|
| Atslēga nemainīta | Atslēga nemainīta | Pieņemt bāzi |
| Atslēga nemainīta | Atslēga mainīta | Pieņemt viņu vērtību |
| Atslēga mainīta | Atslēga nemainīta | Pieņemt mūsu vērtību |
| Atslēga mainīta (vienādi) | Atslēga mainīta (vienādi) | Pieņemt (sakrīt) |
| Atslēga mainīta (atšķirīgi) | Atslēga mainīta (atšķirīgi) | **Konflikts** (pēc noklusējuma: mūsu vērtība) |
| Atslēga pastāv | Atslēga pastāv | Atslēga noņemta | Pieņemt noņemšanu |
| Atslēga pastāv | Atslēga noņemta | Atslēga pastāv | Pieņemt noņemšanu |
| Atslēgas nav | Atslēga pievienota | Atslēgas nav | Pieņemt pievienošanu |
| Atslēgas nav | Atslēgas nav | Atslēga pievienota | Pieņemt pievienošanu |

Ligzdotie objekti tiek salīdzināti kā necaurredzamas JSON virknes, nevis rekursīvi. Ja ligzdots objekts atšķiras, tiek salīdzināta visa šīs atslēgas vērtība, nevis tās apakšatslēgas.

### Prasības

Visām trim vērtībām jābūt derīgiem JSON objektiem vai masīviem. Ja kāda vērtība nav derīgs JSON vai ir skalāra vērtība JSON (virkne, skaitlis, Būla vērtība), sapludinātājs atgriežas pie konflikta.

## OpaqueCellMerger

Noklusējuma sapludinātājs, ja nav konfigurēta šūnu līmeņa stratēģija. Tas uzskata kolonnas vērtību par necaurredzamu bloku un vienmēr ziņo par konfliktu, ja abu pušu vērtības atšķiras.

```php
use Merql\CellMerge\OpaqueCellMerger;

$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs
```

## CellMergeResult

Visi šūnu sapludinātāji atgriež `CellMergeResult`:

```php
$result = $merger->merge($base, $ours, $theirs);

$result->clean;     // bool: true if merge resolved cleanly
$result->value;     // mixed: the merged value (or ours on conflict)
$result->conflicts; // int: number of conflicts within the cell
```

Rūpnīcas metodes:

```php
CellMergeResult::resolved($value);           // clean merge
CellMergeResult::conflict($oursValue, $n);   // n conflicts, defaults to ours
```

## Pielāgoti šūnu sapludinātāji

Lai pievienotu savu sapludināšanas stratēģiju, implementējiet `CellMerger` saskarni:

```php
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;

class YamlCellMerger implements CellMerger
{
    public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult
    {
        // Parse YAML, merge keys, return result.
        $merged = $this->mergeYaml($base, $ours, $theirs);

        if ($merged['clean']) {
            return CellMergeResult::resolved($merged['value']);
        }

        return CellMergeResult::conflict($ours);
    }
}

$config = (new CellMergeConfig())
    ->forColumn('config_data', new YamlCellMerger());
```
