
# Fletning på celleniveau

Fletning på kolonneniveau registrerer, når begge sider har ændret den samme kolonne. Fletning på celleniveau går dybere og fletter indholdet i kolonnen. To personer, der redigerer forskellige linjer i et TEXT-felt eller forskellige nøgler i et JSON-objekt, kan flette uden konflikt.

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

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

## Aktivér fletning på celleniveau

Fletning på celleniveau er valgfri. Den kører kun i en `ThreeWayMerge`, der er konstrueret med en `CellMergeConfig`. Uden en sådan bliver enhver kolonne, som begge sider har ændret til forskellige værdier, en `update_update`-konflikt.

Facaden `Merql` tager ikke imod en konfiguration: `Merql::merge()`, `Merql::patch()` og `Merql::plan()` konstruerer `new ThreeWayMerge()` uden en, og kommandoen `merge` i CLI går gennem `Merql::merge()`. De fletter altid på kolonneniveau ([#7](https://github.com/inline0/merql/issues/7)).

Hvis du vil flette øjebliksbilleder, der er gemt af facaden eller CLI, med fletning på celleniveau, skal du indlæse dem og selv kalde `ThreeWayMerge`. Resultatet er en almindelig `MergeResult`, så facaden stadig kan anvende det, og `MergePlanBuilder` omdanner det til en [fletteplan](https://merql.inline0.dev/da/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);
```

Celleflettere kører kun for kolonner, som begge sider har ændret. Hvis kun den ene side har ændret en kolonne, bruges dens værdi uændret.

## CellMergeConfig

`CellMergeConfig` knytter kolonner eller kolonnetyper til cellefletterimplementeringer. Fabrikken `auto()` leverer fornuftige standardindstillinger:

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

Prioritet for valg af fletter:

1. Fuldt kvalificeret kolonnenavn (`table.column`).
2. Ukvalificeret kolonnenavn (`column`).
3. Mønstermatch af kolonnetype (`str_contains` uden forskel på store og små bogstaver).
4. Standard: `OpaqueCellMerger` (rapporterer altid en konflikt, når værdierne afviger).

## TextCellMerger

Fletter tekst med flere linjer ved hjælp af Myers-difference, samme algoritme som git bruger til filindhold. Hver linje behandles som en enhed, og ændringer af forskellige linjer flettes uden konflikt.

```php
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();
```

### Eksempel: konfliktfri tekstfletning

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

Der blev redigeret forskellige linjer. Fletningen giver `"LINE ONE\nline two\nLINE THREE"` uden konflikt.

### Eksempel: tekstkonflikt

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

Begge sider ændrede den samme linje til forskellige værdier. Fletteren returnerer et konfliktresultat. Det flettede indhold indeholder konfliktmarkører, der minder om dem i git.

### Sådan fungerer det

`TextCellMerger` bruger pitmasters `ThreeWayMerge::merge()`, som beregner en Myers-difference mellem base og hver side og derefter kombinerer de to redigeringsscripts. Hvis redigeringerne overlapper i det samme linjeområde, rapporterer den en konflikt.

## JsonCellMerger

Fletter JSON-objekter ved at sammenligne nøgler på øverste niveau uafhængigt af hinanden. Hver nøgle flettes efter de almindelige trevejsregler.

```php
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();
```

### Eksempel: konfliktfri JSON-fletning

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

Der blev ændret forskellige nøgler. Det flettede resultat er:

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

### Eksempel: JSON-konflikt

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

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

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

Begge sider ændrede nøglen `color` til forskellige værdier. Det er en konflikt. Fletteren vælger som standard vores værdi og rapporterer én konflikt.

### Regler for nøgler

| Base | Vores | Deres | Resultat |
|---|---|---|---|
| Nøgle uændret | Nøgle uændret | Brug base |
| Nøgle uændret | Nøgle ændret | Brug deres |
| Nøgle ændret | Nøgle uændret | Brug vores |
| Nøgle ændret (ens) | Nøgle ændret (ens) | Brug værdien (enighed) |
| Nøgle ændret (forskellig) | Nøgle ændret (forskellig) | **Konflikt** (standard: vores) |
| Nøgle findes | Nøgle findes | Nøgle fjernet | Accepter fjernelse |
| Nøgle findes | Nøgle fjernet | Nøgle findes | Accepter fjernelse |
| Nøgle mangler | Nøgle tilføjet | Nøgle mangler | Accepter tilføjelse |
| Nøgle mangler | Nøgle mangler | Nøgle tilføjet | Accepter tilføjelse |

Indlejrede objekter sammenlignes som uigennemsigtige JSON-strenge, ikke rekursivt. Hvis et indlejret objekt afviger, sammenlignes hele værdien af den pågældende nøgle, ikke dens undernøgler.

### Krav

Alle tre værdier skal være gyldige JSON-objekter eller -arrays. Hvis en værdi ikke er gyldig JSON eller er en skalar af typen JSON (streng, tal, boolesk værdi), falder fletteren tilbage til en konflikt.

## OpaqueCellMerger

Standardfletteren, når der ikke er konfigureret en strategi for fletning på celleniveau. Den behandler kolonneværdien som en uigennemsigtig blok og rapporterer altid en konflikt, når de to sider er forskellige.

```php
use Merql\CellMerge\OpaqueCellMerger;

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

## CellMergeResult

Alle celleflettere returnerer en `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
```

Fabrikmetoder:

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

## Brugerdefinerede celleflettere

Implementér grænsefladen `CellMerger` for at tilføje din egen flette-strategi:

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