
# Merge a livello di colonna

Il merge a livello di colonna è il principale vantaggio di merql rispetto al confronto ingenuo a livello di riga. Quando entrambi i lati modificano la stessa riga, merql confronta ogni colonna separatamente invece di segnalare un conflitto per l'intera riga.

## Il problema del merge a livello di riga

Considerate una tabella `posts` in cui due persone modificano la stessa riga:

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

Un merge a livello di riga rileva che entrambi i lati hanno modificato la riga e segnala un conflitto. Ma le modifiche non si sovrappongono. Ours ha modificato `content`, mentre theirs ha modificato `title` e `status`.

## Come il merge a livello di colonna risolve il problema

merql applica a ogni colonna, separatamente, le stesse regole di merge a tre vie:

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

Risultato: `{ title: "New Title", content: "Body v2", status: "publish" }`. Merge senza conflitti.

## Come funziona

Quando `ThreeWayMerge` rileva che entrambi i lati hanno aggiornato la stessa riga, delega a `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)
```

Per ogni colonna si applicano le stesse regole:

| Base | Ours | Theirs | Risultato |
|---|---|---|---|
| A | A | A | Mantieni la base (nessuna modifica) |
| A | A | B | Accetta theirs |
| A | B | A | Accetta ours |
| A | B | B | Accetta (entrambi concordano) |
| A | B | C | **Conflitto** (valori diversi) |

## Quando si verificano ancora conflitti

Si verifica un conflitto a livello di colonna quando entrambi i lati modificano la stessa colonna assegnandole valori diversi:

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

Entrambi hanno modificato `title` assegnandole valori diversi. È un conflitto effettivo che richiede una risoluzione.

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

## Conflitti parziali

Una singola riga può contenere sia merge senza conflitti sia conflitti. Se una colonna viene unita senza conflitti ma un'altra genera un conflitto, il `MergeOperation` della riga contiene i valori uniti delle colonne senza conflitti e, per impostazione predefinita, il valore ours delle colonne in conflitto. Il conflitto viene comunque segnalato separatamente.

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

Qui `title` è in conflitto (entrambi i lati lo hanno modificato diversamente), `content` viene unito senza conflitti (è cambiato solo ours) e `status` viene unito senza conflitti (è cambiato solo theirs). L'operazione contiene:

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

## Confronto dei valori

I valori delle colonne vengono confrontati come stringhe dopo la conversione. `NULL` è un valore distinto:

- Da `NULL` a `NULL` = nessuna modifica.
- Da `NULL` a `"hello"` = aggiornamento.
- Da `"hello"` a `NULL` = aggiornamento.
- Da `"1"` a `1` = nessuna modifica (entrambi diventano la stringa `"1"`).

Questo corrisponde alla semantica di fetch dell'adapter di connessione MerQL: tutti i valori del database vengono restituiti come stringhe (o NULL).

## Merge a livello di cella

Quando l’unione a livello di colonna genera ancora un conflitto (entrambi i lati hanno modificato la stessa colonna con valori diversi), merql può scendere di un livello con [unione a livello di cella](https://merql.inline0.dev/it/docs/merge/cell-level). Si applica alle colonne TEXT (confronto riga per riga) e alle colonne JSON (confronto chiave per chiave), risolvendo i casi in cui entrambi i lati hanno modificato parti diverse del valore della stessa colonna.
