Sloučení na úrovni sloupců
Sloučení na úrovni sloupců je hlavní výhodou merql oproti naivnímu porovnávání na úrovni řádků. Když obě strany upraví stejný řádek, merql porovná každý sloupec samostatně místo toho, aby celý řádek označil jako konflikt.
Problém se slučováním na úrovni řádků
Představte si tabulku posts, ve které dva lidé upravují stejný řádek:
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" }
Sloučení na úrovni řádků zjistí, že obě strany změnily řádek, a označí jej jako konflikt. Změny se ale vůbec nepřekrývají. My jsme upravili content, oni upravili title a status.
Jak sloučení na úrovni sloupců problém řeší
merql použije stejná pravidla třícestného sloučení na každý sloupec zvlášť:
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
Výsledek: { title: "New Title", content: "Body v2", status: "publish" }. Čisté sloučení bez konfliktu.
Jak to funguje
Když ThreeWayMerge zjistí, že obě strany aktualizovaly stejný řádek, deleguje na 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)
Pro každý sloupec platí stejná pravidla:
| Základ | Naše | Jejich | Výsledek |
|---|---|---|---|
| A | A | A | Ponechat základ (beze změny) |
| A | A | B | Přijmout jejich |
| A | B | A | Přijmout naši verzi |
| A | B | B | Přijmout (obě strany souhlasí) |
| A | B | C | Konflikt (odlišné hodnoty) |
Kdy ke konfliktům stále dochází
Ke konfliktu na úrovni sloupce dojde, když obě strany změní stejný sloupec na různé hodnoty:
Base: post #42 { title: "Hello" }
Ours: post #42 { title: "Welcome" }
Theirs: post #42 { title: "Greetings" }
Obě strany změnily title na různé hodnoty. Jde o skutečný konflikt, který je třeba vyřešit.
$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"
Částečné konflikty
Jeden řádek může obsahovat čistá sloučení i konflikty. Pokud se jeden sloupec sloučí bez konfliktu, ale u jiného konflikt nastane, MergeOperation daného řádku obsahuje sloučené hodnoty čistých sloupců a hodnotu naší strany (ve výchozím nastavení) u konfliktních sloupců. Konflikt se nahlásí samostatně.
Base: { title: "Hello", content: "Body", status: "draft" }
Ours: { title: "Welcome", content: "Body v2", status: "draft" }
Theirs: { title: "Greetings", content: "Body", status: "publish" }
Zde je u title konflikt (obě strany jej změnily odlišně), content se sloučí čistě (změnila jej pouze naše strana) a status se sloučí čistě (změnila jej pouze jejich strana). Operace obsahuje:
// values: { title: "Welcome", content: "Body v2", status: "publish" }
// One conflict on the "title" column.
Porovnávání hodnot
Hodnoty sloupců se po převodu porovnávají jako řetězce. NULL je samostatná hodnota:
NULLnaNULL= beze změny.NULLna"hello"= aktualizace."hello"naNULL= aktualizace."1"na1= beze změny (obojí se převede na řetězec"1").
To odpovídá sémantice načítání hodnot adaptéru připojení MerQL: všechny databázové hodnoty se vracejí jako řetězce (nebo NULL).
Sloučení na úrovni buněk
Pokud sloučení na úrovni sloupců přesto skončí konfliktem (obě strany změnily stejný sloupec na různé hodnoty), merql může jít o úroveň hlouběji pomocí sloučení na úrovni buněk. To se používá u sloupců TEXT (rozdíl po řádcích) a sloupců JSON (rozdíl po klíčích) a řeší případy, kdy obě strany upravily různé části hodnoty stejného sloupce.