
# Sujungimas langelio lygmeniu

Sujungimas stulpelių lygmeniu aptinka, kai abi pusės pakeitė tą patį stulpelį. Sujungimas langelio lygmeniu veikia išsamiau – sujungia to stulpelio turinį. Du žmonės gali sklandžiai sujungti pakeitimus, jei vienas redagavo skirtingas TEXT lauko eilutes, o kitas – skirtingus JSON objekto raktus.

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

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

## Sujungimo langelio lygmeniu įjungimas

Sujungimas langelio lygmeniu yra pasirenkamas. Jis veikia tik `ThreeWayMerge`, sukurtame su `CellMergeConfig`. Jei jo nėra, kiekvienas stulpelis, kurį abi pusės pakeitė į skirtingas reikšmes, laikomas `update_update` konfliktu.

`Merql` fasadas nepriima konfigūracijos: `Merql::merge()`, `Merql::patch()` ir `Merql::plan()` sukuria `new ThreeWayMerge()` be jos, o CLI komanda `merge` vykdoma per `Merql::merge()`. Jie visada sujungia stulpelių lygmeniu ([#7](https://github.com/inline0/merql/issues/7)).

Norėdami sujungti fasado arba CLI išsaugotus momentinius vaizdus langelio lygmens sujungimu, įkelkite juos ir patys iškvieskite `ThreeWayMerge`. Rezultatas yra įprastas `MergeResult`, todėl fasadas vis tiek gali jį pritaikyti, o `MergePlanBuilder` paverčia jį [sujungimo planu](https://merql.inline0.dev/lt/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);
```

Langeliai sujungiami tik tuose stulpeliuose, kuriuos pakeitė abi pusės. Jei stulpelį pakeitė tik viena pusė, jo reikšmė perimama nepakeista.

## CellMergeConfig

`CellMergeConfig` susieja stulpelius arba stulpelių tipus su langelių sujungimo realizacijomis. `auto()` gamykloje nustatytos reikšmės yra tinkamos:

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

Sujungimo būdo parinkimo prioritetas:

1. Pilnas stulpelio pavadinimas (`table.column`).
2. Stulpelio pavadinimas be kvalifikatoriaus (`column`).
3. Stulpelio tipo šablono atitiktis (`str_contains`, nepaisant raidžių dydžio).
4. Numatytoji reikšmė: `OpaqueCellMerger` (visada praneša apie konfliktą, kai reikšmės skiriasi).

## TextCellMerger

Sujungia kelių eilučių tekstą naudodamas Myers skirtumų algoritmą, tą patį, kurį git naudoja failų turiniui. Kiekviena eilutė laikoma vienetu, todėl skirtingų eilučių pakeitimai sujungiami sklandžiai.

```php
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();
```

### Pavyzdys: sklandus teksto sujungimas

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

Buvo redaguotos skirtingos eilutės. Sujungimo rezultatas – `"LINE ONE\nline two\nLINE THREE"` be konflikto.

### Pavyzdys: teksto konfliktas

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

Abi pusės pakeitė tą pačią eilutę į skirtingas reikšmes. Sujungimo būdas grąžina konflikto rezultatą. Sujungtame turinyje pateikiami į git panašūs konfliktų žymekliai.

### Kaip tai veikia

`TextCellMerger` naudoja pitmaster `ThreeWayMerge::merge()`, kuris apskaičiuoja Myers skirtumą tarp bazinės versijos ir kiekvienos pusės, tada sujungia abu redagavimo scenarijus. Jei pakeitimai persidengia toje pačioje eilučių srityje, pranešama apie konfliktą.

## JsonCellMerger

Sujungia JSON objektus, atskirai palygindamas aukščiausio lygio raktus. Kiekvienas raktas sujungiamas pagal standartines trijų krypčių taisykles.

```php
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();
```

### Pavyzdys: sklandus JSON sujungimas

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

Buvo pakeisti skirtingi raktai. Sujungimo rezultatas:

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

### Pavyzdys: JSON konfliktas

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

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

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

Abi pusės pakeitė tą patį `color` raktą į skirtingas reikšmes. Tai konfliktas. Pagal numatytąją nuostatą sujungimo būdas pasirenka mūsų reikšmę ir praneša apie vieną konfliktą.

### Raktų lygmens taisyklės

| Bazė | Mūsų pusė | Jų pusė | Rezultatas |
|---|---|---|---|
| Raktas nepakeistas | Raktas nepakeistas | Priimti bazinę reikšmę |
| Raktas nepakeistas | Raktas pakeistas | Priimti jų reikšmę |
| Raktas pakeistas | Raktas nepakeistas | Priimti mūsų reikšmę |
| Raktas pakeistas (vienodai) | Raktas pakeistas (vienodai) | Priimti (sutampa) |
| Raktas pakeistas (skirtingai) | Raktas pakeistas (skirtingai) | **Konfliktas** (numatyta: mūsų reikšmė) |
| Raktas yra | Raktas yra | Raktas pašalintas | Priimti pašalinimą |
| Raktas yra | Raktas pašalintas | Raktas yra | Priimti pašalinimą |
| Raktas trūksta | Raktas pridėtas | Raktas trūksta | Priimti pridėjimą |
| Raktas trūksta | Raktas trūksta | Raktas pridėtas | Priimti pridėjimą |

Įdėtiniai objektai lyginami kaip vientisos JSON eilutės, o ne rekursyviai. Jei įdėtinis objektas skiriasi, lyginama visa to rakto reikšmė, o ne jo po-rakčiai.

### Reikalavimai

Visos trys reikšmės turi būti galiojantys JSON objektai arba masyvai. Jei bent viena reikšmė nėra galiojantis JSON arba yra JSON skaliaras (eilutė, skaičius, loginė reikšmė), sujungimo būdas grįžta prie konflikto.

## OpaqueCellMerger

Numatytasis sujungimo būdas, kai nesukonfigūruota sujungimo langelio lygmeniu strategija. Stulpelio reikšmė laikoma vientisu objektu ir visada pranešama apie konfliktą, jei abiejų pusių reikšmės skiriasi.

```php
use Merql\CellMerge\OpaqueCellMerger;

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

## CellMergeResult

Visi langelių sujungimo būdai grąžina `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
```

Gamyklos metodai:

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

## Pasirinktiniai langelių sujungimo būdai

Įgyvendinkite `CellMerger` sąsają, kad pridėtumėte savo sujungimo strategiją:

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