
# Mesclagem no nível da coluna

A mesclagem no nível das colunas é a principal vantagem do merql em relação à comparação simplista no nível das linhas. Quando os dois lados modificam a mesma linha, o merql compara cada coluna de forma independente, em vez de marcar a linha inteira como conflito.

## O problema da mesclagem no nível das linhas

Considere uma tabela `posts` em que duas pessoas editam a mesma linha:

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

Uma mesclagem no nível das linhas detecta que os dois lados alteraram a linha e declara um conflito. Mas as alterações não se sobrepõem. Nosso editou `content`; deles editaram `title` e `status`.

## Como a mesclagem no nível das colunas resolve o problema

merql aplica as mesmas regras de mesclagem de três vias a cada coluna individualmente:

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

Resultado: `{ title: "New Title", content: "Body v2", status: "publish" }`. Mesclagem sem conflitos.

## Como funciona

Quando `ThreeWayMerge` detecta que os dois lados atualizaram a mesma linha, delega a operação para `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)
```

Para cada coluna, aplicam-se as mesmas regras:

| Base | Nosso | Deles | Resultado |
|---|---|---|---|
| A | A | A | Manter a base (sem alterações) |
| A | A | B | Aceitar deles |
| A | B | A | Aceitar nosso |
| A | B | B | Aceitar (ambos concordam) |
| A | B | C | **Conflito** (valores diferentes) |

## Quando ainda ocorrem conflitos

Ocorre um conflito no nível da coluna quando os dois lados alteram a mesma coluna para valores diferentes:

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

Os dois lados alteraram `title` para valores diferentes. Esse é um conflito real que precisa ser resolvido.

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

## Conflitos parciais

Uma única linha pode conter mesclagens sem conflitos e conflitos. Se uma coluna for mesclada sem conflitos, mas outra gerar um conflito, o `MergeOperation` da linha conterá os valores mesclados das colunas sem conflitos e, por padrão, o valor de nosso nas colunas conflitantes. O conflito ainda será informado separadamente.

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

Neste caso, `title` gera um conflito (ambos alteraram a coluna de forma diferente), `content` é mesclada sem conflitos (apenas nosso alterou) e `status` é mesclada sem conflitos (apenas deles alteraram). A operação contém:

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

## Comparação de valores

Os valores das colunas são comparados como strings após a conversão de tipo. `NULL` é um valor distinto:

- `NULL` para `NULL` = sem alterações.
- `NULL` para `"hello"` = atualização.
- `"hello"` para `NULL` = atualização.
- `"1"` para `1` = sem alterações (ambos são convertidos para a string `"1"`).

Isso corresponde à semântica de recuperação de dados do adaptador de conexão MerQL: todos os valores do banco de dados são retornados como strings (ou NULL).

## Mesclagem no nível da célula

Quando a mesclagem no nível das colunas ainda resulta em um conflito (os dois lados alteraram a mesma coluna para valores diferentes), o merql pode ir além com a [mesclagem no nível da célula](https://merql.inline0.dev/pt/docs/merge/cell-level). Ela se aplica a colunas TEXT (diff linha a linha) e colunas JSON (diff chave por chave), resolvendo casos em que os dois lados editaram partes diferentes do valor da mesma coluna.
