Konfliktų tvarkymas
Konfliktas kyla, kai abi sujungimo pusės pakeičia tuos pačius duomenis nesuderinamais būdais. merql aptinka keturis konfliktų tipus ir siūlo automatines bei rankines jų sprendimo strategijas.
$result = $merge->merge($base, $ours, $theirs);
if (!$result->isClean()) {
foreach ($result->conflicts() as $conflict) {
echo "{$conflict->table()}.{$conflict->column()}: "
. "{$conflict->oursValue()} vs {$conflict->theirsValue()}\n";
}
}
Konfliktų tipai
update_update
Abi pusės pakeitė tą patį tos pačios eilutės stulpelį į skirtingas reikšmes. Tai dažniausiai pasitaikantis konflikto tipas.
Base: posts #42 title = "Hello"
Ours: posts #42 title = "Welcome"
Theirs: posts #42 title = "Greetings"
Konflikte nurodoma: lentelė posts, eilutės raktas 42, stulpelis title, mūsų reikšmė Welcome, jų reikšmė Greetings, bazinė reikšmė Hello.
update_delete
Viena pusė atnaujino eilutę, o kita ją ištrynė. merql negali nustatyti, kuris veiksmas turi laimėti.
Ours: posts #42 title = "Updated Title" (updated)
Theirs: posts #42 (deleted)
Konflikte nurodoma: lentelė posts, eilutės raktas 42, tipas update_delete. Mūsų reikšmėje yra visa atnaujinta eilutė. Jų reikšmė yra null.
delete_update
Priešingas atvejis nei update_delete. Jie atnaujino eilutę, o mes ją ištrynėme.
Ours: posts #42 (deleted)
Theirs: posts #42 title = "Updated Title" (updated)
Konflikte nurodoma: tipas delete_update. Mūsų reikšmė yra null, o jų reikšmėje pateikta visa atnaujinta eilutė.
insert_insert
Abi pusės įterpė eilutę su tuo pačiu pirminiu raktu. Kadangi abi eilutės naujos (bazinėje versijoje jų nebuvo), merql negali jų sujungti.
Base: (no row #99)
Ours: posts #99 { title: "My Post" }
Theirs: posts #99 { title: "Their Post" }
Konflikte nurodoma: tipas insert_insert. Mūsų reikšmėje pateikti mūsų eilutės duomenys, o jų reikšmėje – jų eilutės duomenys.
Konfliktų klasė
Kiekvienas konfliktas yra tik skaitomas objektas su šiais prieigos metodais:
$conflict->table(); // string: table name
$conflict->rowKey(); // string: encoded row identity key
$conflict->type(); // string: "update_update"|"update_delete"|"delete_update"|"insert_insert"
$conflict->column(); // ?string: column name (null for structural conflicts)
$conflict->oursValue(); // mixed: our value (null for delete side, full row for structural)
$conflict->theirsValue(); // mixed: their value (null for delete side, full row for structural)
$conflict->baseValue(); // mixed: base value (null for inserts)
column() metodas grąžina stulpelio pavadinimą update_update konfliktams, o struktūriniams konfliktams (update_delete, delete_update, insert_insert) – null.
Pirminio rakto dekodavimas
Eilutės raktas yra užkoduota eilutė. Norėdami gauti įvardytą pirminių raktų masyvą, perduokite tapatybės stulpelius:
$pk = $conflict->primaryKey(['id']);
// ['id' => '42']
$pk = $conflict->primaryKey(['tenant_id', 'user_id']);
// ['tenant_id' => '1', 'user_id' => '99']
Automatinis sprendimas naudojant ConflictPolicy
ConflictResolver taiko strategiją, kad iš karto išspręstų visus konfliktus:
use Merql\Merge\ConflictPolicy;
use Merql\Merge\ConflictResolver;
// One side wins everywhere.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::OursWins);
$resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);
// Manual: return the result unchanged (inspect conflicts yourself).
$resolved = ConflictResolver::resolve($result, ConflictPolicy::Manual);
ConflictPolicy išvardijimas
| Reikšmė | Veikimas |
|---|---|
OursWins |
update_update atveju naudoti mūsų reikšmę. update_delete atveju palikti atnaujinimą. delete_update atveju palikti ištrynimą. insert_insert atveju naudoti mūsų įterpimą. |
TheirsWins |
update_update atveju naudoti jų reikšmę. update_delete atveju ištrinti. delete_update atveju palikti atnaujinimą. insert_insert atveju naudoti jų įterpimą. |
Manual |
Grąžinti nepakeistą rezultatą. Visi konfliktai lieka neišspręsti. |
Kaip veikia sprendimas
update_update konfliktų atveju sprendiklis pataiso esamą tos eilutės sujungimo operaciją ir pakeičia konfliktuojančio stulpelio reikšmę laiminčios pusės reikšme.
Struktūrinių konfliktų (update_delete, delete_update, insert_insert) atveju sprendiklis į rezultatą įtraukia naują operaciją:
update_deletesuOursWinsprideda UPDATE operaciją.update_deletesuTheirsWinsprideda DELETE operaciją.delete_updatesuOursWinsprideda DELETE operaciją.delete_updatesuTheirsWinsprideda UPDATE operaciją.insert_insertnaudoja laiminčios pusės eilutės reikšmes.
Išspręstame MergeResult yra tuščias konfliktų sąrašas, todėl jį galima iškart pritaikyti.
Rankinis sprendimas
Norėdami tiksliai kontroliuoti procesą, patikrinkite kiekvieną konfliktą ir sukurkite savo sprendimą:
foreach ($result->conflicts() as $conflict) {
echo "Table: {$conflict->table()}\n";
echo "Row: {$conflict->rowKey()}\n";
echo "Type: {$conflict->type()}\n";
if ($conflict->column() !== null) {
echo "Column: {$conflict->column()}\n";
echo "Base: " . var_export($conflict->baseValue(), true) . "\n";
echo "Ours: " . var_export($conflict->oursValue(), true) . "\n";
echo "Theirs: " . var_export($conflict->theirsValue(), true) . "\n";
}
}
Taikymas esant neišspręstų konfliktų
Applier atsisako taikyti sujungimo rezultatą su neišspręstais konfliktais. Išmetama ConflictException:
use Merql\Exceptions\ConflictException;
try {
$applier->apply($result);
} catch (ConflictException $e) {
echo $e->getMessage();
// "Cannot apply merge with 3 unresolved conflicts"
}
Prieš taikydami visada išspręskite konfliktus: naudokite ConflictResolver::resolve() arba rankiniu būdu sukurkite švarų MergeResult.