Pular para o conteúdo

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:

Código
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:

Código
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:

Código
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.

Código
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. 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.