Samenvoegen op kolomniveau
Samenvoegen op kolomniveau is het belangrijkste voordeel van merql ten opzichte van een naïeve vergelijking op rijniveau. Wanneer beide kanten dezelfde rij aanpassen, vergelijkt merql elke kolom afzonderlijk in plaats van de hele rij als conflict aan te merken.
Het probleem met samenvoegen op rijniveau
Neem een tabel posts waarin twee mensen dezelfde rij bewerken:
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" }
Een samenvoeging op rijniveau ziet dat beide kanten de rij hebben gewijzigd en verklaart een conflict. Maar de wijzigingen overlappen helemaal niet. Wij hebben content bewerkt, zij hebben title en status bewerkt.
Hoe samenvoegen op kolomniveau dit oplost
merql past dezelfde driewegsamenvoegregels afzonderlijk op elke kolom toe:
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
Resultaat: { title: "New Title", content: "Body v2", status: "publish" }. Schone samenvoeging, geen conflict.
Werking
Wanneer ThreeWayMerge detecteert dat beide kanten dezelfde rij hebben bijgewerkt, delegeert het aan ColumnMerge::merge():
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)
Voor elke kolom gelden dezelfde regels:
| Basis | Wij | Zij | Resultaat |
|---|---|---|---|
| A | A | A | Basis behouden (ongewijzigd) |
| A | A | B | Hun wijziging accepteren |
| A | B | A | Onze wijziging accepteren |
| A | B | B | Accepteren (beide zijn het eens) |
| A | B | C | Conflict (verschillende waarden) |
Wanneer conflicten nog steeds optreden
Een conflict op kolomniveau treedt op wanneer beide kanten dezelfde kolom in verschillende waarden hebben veranderd:
Base: post #42 { title: "Hello" }
Ours: post #42 { title: "Welcome" }
Theirs: post #42 { title: "Greetings" }
Beide kanten hebben title gewijzigd in verschillende waarden. Dit is een echt conflict dat moet worden opgelost.
$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"
Gedeeltelijke conflicten
Eén rij kan zowel schone samenvoegingen als conflicten bevatten. Als de ene kolom netjes wordt samengevoegd maar een andere conflicteert, bevat de MergeOperation voor de rij de samengevoegde waarden voor schone kolommen en standaard onze waarde voor conflicterende kolommen. Het conflict wordt daarnaast afzonderlijk gemeld.
Base: { title: "Hello", content: "Body", status: "draft" }
Ours: { title: "Welcome", content: "Body v2", status: "draft" }
Theirs: { title: "Greetings", content: "Body", status: "publish" }
Hier conflicteert title (beide kanten hebben deze anders gewijzigd), wordt content netjes samengevoegd (alleen wij hebben deze gewijzigd) en wordt status netjes samengevoegd (alleen zij hebben deze gewijzigd). De bewerking bevat:
// values: { title: "Welcome", content: "Body v2", status: "publish" }
// One conflict on the "title" column.
Waarden vergelijken
Kolomwaarden worden na conversie vergeleken als strings. NULL is een aparte waarde:
NULLnaarNULL= geen wijziging.NULLnaar"hello"= bijgewerkt."hello"naarNULL= bijgewerkt."1"naar1= geen wijziging (beide worden geconverteerd naar de string"1").
Dit komt overeen met de ophaalsemantiek van de MerQL-verbindingsadapter: alle databasewaarden komen terug als strings (of NULL).
Samenvoegen op celniveau
Wanneer samenvoegen op kolomniveau nog steeds een conflict oplevert (beide kanten hebben dezelfde kolom in verschillende waarden gewijzigd), kan merql een niveau dieper gaan met samenvoegen op celniveau. Dit werkt voor TEXT-kolommen (verschillen regel voor regel) en JSON-kolommen (verschillen sleutel voor sleutel) en lost gevallen op waarin beide kanten verschillende delen van dezelfde kolomwaarde hebben bewerkt.