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():
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.
$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:
// 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:
NULLtillNULL= ingen ändring.NULLtill"hello"= uppdatering."hello"tillNULL= uppdatering."1"till1= 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å. 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.