Liigu sisu juurde

Konfliktide käsitlemine

Konflikt tekib, kui liitmise mõlemad pooled muudavad samu andmeid viisil, mis ei sobi kokku. merql tuvastab nelja tüüpi konflikte ning pakub automaatseid ja käsitsi lahendamise strateegiaid.

PHP
$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";
    }
}

Konfliktitüübid

update_update

Mõlemad pooled muutsid sama rea sama veeru erinevaks väärtuseks. See on kõige levinum konfliktitüüp.

Kood
Base:    posts #42  title = "Hello"
Ours:    posts #42  title = "Welcome"
Theirs:  posts #42  title = "Greetings"

Konfliktiandmed: tabel posts, reavõti 42, veerg title, meie väärtus Welcome, nende väärtus Greetings, alusväärtus Hello.

update_delete

Üks pool uuendas rea, teine kustutas selle. merql ei saa otsustada, kas võidab uuendus või kustutamine.

Kood
Ours:    posts #42  title = "Updated Title"    (updated)
Theirs:  posts #42  (deleted)

Konfliktiandmed: tabel posts, reavõti 42, tüüp update_delete. Meie väärtus sisaldab kogu uuendatud rida. Nende väärtus on null.

delete_update

Vastupidine olukorrale update_delete. Nemad uuendasid rida, meie kustutasime selle.

Kood
Ours:    posts #42  (deleted)
Theirs:  posts #42  title = "Updated Title"    (updated)

Konfliktiandmed: tüüp delete_update. Meie väärtus on null, nende väärtus sisaldab kogu uuendatud rida.

insert_insert

Mõlemad pooled lisasid sama primaarvõtmega rea. Kuna mõlemad read on uued (aluses neid pole), ei saa merql neid liita.

Kood
Base:    (no row #99)
Ours:    posts #99  { title: "My Post" }
Theirs:  posts #99  { title: "Their Post" }

Konfliktiandmed: tüüp insert_insert. Meie väärtus sisaldab meie rea andmeid, nende väärtus sisaldab nende rea andmeid.

Conflict-klass

Iga konflikt on kirjutuskaitstud objekt, millel on järgmised juurdepääsumeetodid:

PHP
$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)

Meetod column() tagastab veerunime update_update konfliktide korral ja väärtuse null struktuursete konfliktide korral (update_delete, delete_update, insert_insert).

Primaarvõtme dekodeerimine

Reavõti on kodeeritud string. Nimega primaarvõtme massiivi saamiseks edastage identiteediveerud:

PHP
$pk = $conflict->primaryKey(['id']);
// ['id' => '42']

$pk = $conflict->primaryKey(['tenant_id', 'user_id']);
// ['tenant_id' => '1', 'user_id' => '99']

Automaatne lahendamine ConflictPolicy abil

ConflictResolver rakendab kõigi konfliktide korraga lahendamiseks poliitikat:

PHP
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 enum

Väärtus Käitumine
OursWins Kasuta update_update puhul meie väärtust. Jäta update_delete puhul uuendus alles. Jäta delete_update puhul kustutamine alles. Kasuta insert_insert puhul meie lisatud rida.
TheirsWins Kasuta update_update puhul nende väärtust. Kustuta update_delete puhul. Jäta delete_update puhul uuendus alles. Kasuta insert_insert puhul nende lisatud rida.
Manual Tagasta tulemus muutmata kujul. Kõik konfliktid jäävad lahendamata.

Kuidas lahendamine käib

update_update konfliktide korral parandab lahendaja selle rea olemasolevat liitmistehet, asendades konfliktse veeru väärtuse võitnud poole väärtusega.

Struktuursete konfliktide korral (update_delete, delete_update, insert_insert) lisab lahendaja tulemusse uue tehte:

  • update_delete koos OursWins lisab UPDATE-tehte.
  • update_delete koos TheirsWins lisab DELETE-tehte.
  • delete_update koos OursWins lisab DELETE-tehte.
  • delete_update koos TheirsWins lisab UPDATE-tehte.
  • insert_insert kasutab võitnud poole rea väärtusi.

Lahendatud MergeResult konfliktide loend on tühi ja selle saab otse rakendada.

Käsitsi lahendamine

Üksikasjalikuks juhtimiseks vaadake iga konflikt üle ja koostage oma lahendus:

PHP
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";
    }
}

Rakendamine lahendamata konfliktidega

Applier keeldub rakendamast liitmise tulemust, milles on lahendamata konflikte. See viskab ConflictException:

PHP
use Merql\Exceptions\ConflictException;

try {
    $applier->apply($result);
} catch (ConflictException $e) {
    echo $e->getMessage();
    // "Cannot apply merge with 3 unresolved conflicts"
}

Lahendage konfliktid alati enne rakendamist, kasutades kas ConflictResolver::resolve() või koostades puhta MergeResult käsitsi.