
# Sammanslagning på kolumnnivå

Sammanslagning på kolumnnivå är merql:s främsta fördel jämfört med en naiv jämförelse på radnivå. När båda sidor ändrar samma rad jämför merql varje kolumn för sig, i stället för att markera hela raden som en konflikt.

## Problemet med sammanslagning på radnivå

Tänk dig en tabell av typen `posts` där två personer redigerar samma rad:

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

En sammanslagning på radnivå upptäcker att båda sidor ändrade raden och deklarerar en konflikt. Men ändringarna överlappar inte alls. Vi redigerade `content`, medan de redigerade `title` och `status`.

## Så löser sammanslagning på kolumnnivå problemet

merql tillämpar samma trevägsregler för sammanslagning på varje kolumn separat:

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

Resultat: `{ title: "New Title", content: "Body v2", status: "publish" }`. Konfliktfri sammanslagning.

## Så fungerar det

När `ThreeWayMerge` upptäcker att båda sidor uppdaterat samma rad delegerar den till `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)
```

Samma regler gäller för varje kolumn:

| Bas | Vår | Deras | Resultat |
|---|---|---|---|
| A | A | A | Behåll basen (ingen ändring) |
| A | A | B | Acceptera deras |
| A | B | A | Acceptera vårt |
| A | B | B | Acceptera (båda överens) |
| A | B | C | **Konflikt** (olika värden) |

## När konflikter ändå uppstår

En konflikt på kolumnnivå uppstår när båda sidor ändrar samma kolumn till olika värden:

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

Båda ändrade `title` till olika värden. Det är en faktisk konflikt som måste lösas.

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

## Partiella konflikter

En och samma rad kan innehålla både konfliktfria sammanslagningar och konflikter. Om en kolumn slås samman utan problem medan en annan hamnar i konflikt innehåller `MergeOperation` för raden de sammanslagna värdena för kolumner utan konflikt och värdet från vår sida (som standard) för kolumner med konflikt. Konflikten rapporteras separat.

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

Här uppstår en konflikt i `title` (båda ändrade den på olika sätt), `content` slås samman utan konflikt (endast vi ändrade den) och `status` slås samman utan konflikt (endast de ändrade den). Åtgärden innehåller:

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

## Jämförelse av värden

Kolumnvärden jämförs som strängar efter typkonvertering. `NULL` är ett separat värde:

- `NULL` till `NULL` = ingen ändring.
- `NULL` till `"hello"` = uppdatering.
- `"hello"` till `NULL` = uppdatering.
- `"1"` till `1` = ingen ändring (båda konverteras till strängen `"1"`).

Detta motsvarar hämtningssemantiken för anslutningsadaptern MerQL: alla databasvärden returneras som strängar (eller NULL).

## Sammanslagning på cellnivå

När en sammanslagning på kolumnnivå fortfarande leder till en konflikt (båda sidorna ändrade samma kolumn till olika värden) kan merql gå ett steg djupare med [sammanslagning på cellnivå](https://merql.inline0.dev/sv/docs/merge/cell-level). Detta gäller kolumner av typen TEXT (rad-för-rad-jämförelse) och JSON (nyckel-för-nyckel-jämförelse), och löser fall där båda sidor har redigerat olika delar av samma kolumnvärde.
