
# Sujungimas stulpelių lygmeniu

Sujungimas stulpelių lygmeniu yra pagrindinis merql pranašumas prieš naivų palyginimą eilučių lygmeniu. Kai abi pusės pakeičia tą pačią eilutę, merql lygina kiekvieną stulpelį atskirai, užuot paskelbęs konfliktu visą eilutę.

## Eilučių lygmens sujungimo problema

Tarkime, `posts` lentelėje du žmonės redaguoja tą pačią eilutę:

```
Base:    post #42  { title: "Hello",     content: "Body",    status: "draft"   }
Ours:    post #42  { title: "Hello",     content: "Body v2", status: "draft"   }
Theirs:  post #42  { title: "New Title", content: "Body",    status: "publish" }
```

Eilučių lygmens sujungimas nustato, kad abi pusės pakeitė eilutę, ir paskelbia konfliktą. Tačiau pakeitimai visiškai nesutampa. Mes redagavome `content`, o jie redagavo `title` ir `status`.

## Kaip sujungimas stulpelių lygmeniu išsprendžia problemą

merql kiekvienam stulpeliui atskirai taiko tas pačias trijų krypčių sujungimo taisykles:

```
title:   base="Hello", ours="Hello",  theirs="New Title"  -> accept theirs
content: base="Body",  ours="Body v2", theirs="Body"      -> accept ours
status:  base="draft", ours="draft",  theirs="publish"    -> accept theirs
```

Rezultatas: `{ title: "New Title", content: "Body v2", status: "publish" }`. Sklandus sujungimas, be konflikto.

## Kaip tai veikia

Kai `ThreeWayMerge` aptinka, kad abi pusės atnaujino tą pačią eilutę, jis perduoda darbą `ColumnMerge::merge()`:

```php
use Merql\Merge\ColumnMerge;

$result = ColumnMerge::merge(
    table: 'posts',
    rowKey: '42',
    base: ['title' => 'Hello', 'content' => 'Body', 'status' => 'draft'],
    ours: ['title' => 'Hello', 'content' => 'Body v2', 'status' => 'draft'],
    theirs: ['title' => 'New Title', 'content' => 'Body', 'status' => 'publish'],
);

// $result['values']    -> merged column values
// $result['conflicts'] -> list of Conflict objects (empty if clean)
```

Kiekvienam stulpeliui taikomos tos pačios taisyklės:

| Bazė | Mūsų pusė | Jų pusė | Rezultatas |
|---|---|---|---|
| A | A | A | Palikti bazinę reikšmę (nepakeista) |
| A | A | B | Priimti jų reikšmę |
| A | B | A | Priimti mūsų reikšmę |
| A | B | B | Priimti (abi pusės sutaria) |
| A | B | C | **Konfliktas** (skirtingos reikšmės) |

## Kada vis dar kyla konfliktų

Konfliktas stulpelių lygmeniu kyla, kai abi pusės pakeičia tą patį stulpelį į skirtingas reikšmes:

```
Base:    post #42  { title: "Hello" }
Ours:    post #42  { title: "Welcome" }
Theirs:  post #42  { title: "Greetings" }
```

Abi pusės pakeitė `title` į skirtingas reikšmes. Tai tikras konfliktas, kurį reikia išspręsti.

```php
$result = ColumnMerge::merge(
    'posts', '42',
    ['title' => 'Hello'],
    ['title' => 'Welcome'],
    ['title' => 'Greetings'],
);

// $result['conflicts'] contains one Conflict:
//   table: "posts", column: "title"
//   oursValue: "Welcome", theirsValue: "Greetings", baseValue: "Hello"
```

## Daliniai konfliktai

Vienoje eilutėje gali būti ir sklandžiai sujungtų pakeitimų, ir konfliktų. Jei vienas stulpelis sujungiamas sklandžiai, o kitame kyla konfliktas, eilutės `MergeOperation` yra sujungtos reikšmės sklandžiai sujungtuose stulpeliuose ir mūsų reikšmė (pagal numatytąją nuostatą) konfliktuojančiuose stulpeliuose. Apie konfliktą vis tiek pranešama atskirai.

```
Base:    { title: "Hello", content: "Body",    status: "draft" }
Ours:    { title: "Welcome", content: "Body v2", status: "draft" }
Theirs:  { title: "Greetings", content: "Body",    status: "publish" }
```

Čia `title` konfliktuoja (abi pusės jį pakeitė skirtingai), `content` sujungiamas sklandžiai (pakeitė tik mūsų pusė), o `status` sujungiamas sklandžiai (pakeitė tik jų pusė). Operacijoje pateikiama:

```php
// values: { title: "Welcome", content: "Body v2", status: "publish" }
// One conflict on the "title" column.
```

## Reikšmių palyginimas

Stulpelių reikšmės po konvertavimo palyginamos kaip eilutės. `NULL` laikoma atskira reikšme:

- `NULL` į `NULL` = nėra pakeitimo.
- `NULL` į `"hello"` = atnaujinimas.
- `"hello"` į `NULL` = atnaujinimas.
- `"1"` į `1` = nėra pakeitimo (abi reikšmės konvertuojamos į eilutę `"1"`).

Tai atitinka MerQL ryšio adapterio gavimo semantiką: visos duomenų bazės reikšmės grąžinamos kaip eilutės (arba NULL).

## Sujungimas langelio lygmeniu

Kai sujungiant stulpelių lygmeniu vis tiek kyla konfliktas (abi pusės pakeitė tą patį stulpelį į skirtingas reikšmes), merql gali leistis vienu lygmeniu giliau ir atlikti [sujungimą langelio lygmeniu](https://merql.inline0.dev/lt/docs/merge/cell-level). Tai taikoma TEXT stulpeliams (palyginamos eilutės po eilutės) ir JSON stulpeliams (palyginami raktai po rakto), taip išsprendžiant atvejus, kai abi pusės redagavo skirtingas to paties stulpelio reikšmės dalis.
