Pāriet uz saturu

Konfliktu apstrāde

Konflikts rodas, ja abas sapludināšanas puses maina vienus un tos pašus datus nesavietojamā veidā. merql nosaka četrus konfliktu veidus un piedāvā automātiskas un manuālas risināšanas stratēģijas.

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

Konfliktu veidi

update_update

Abas puses mainīja vienu un to pašu vienas rindas kolonnu uz atšķirīgām vērtībām. Šis ir visizplatītākais konflikta veids.

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

Konfliktā tiek norādīts: tabula posts, rindas atslēga 42, kolonna title, mūsu vērtība Welcome, viņu vērtība Greetings, bāzes vērtība Hello.

update_delete

Viena puse atjaunināja rindu, bet otra to izdzēsa. merql nevar noteikt, kurai darbībai — atjaunināšanai vai dzēšanai — jāuzvar.

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

Konfliktā tiek norādīts: tabula posts, rindas atslēga 42, veids update_delete. Mūsu vērtība satur pilnībā atjaunināto rindu. Viņu vērtība ir null.

delete_update

Pretējais gadījums konfliktam update_delete. Viņi atjaunināja rindu, bet mēs to izdzēsām.

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

Konfliktā tiek norādīts: veids delete_update. Mūsu vērtība ir null, bet viņu vērtība satur pilnībā atjaunināto rindu.

insert_insert

Abas puses ievietoja rindu ar vienu un to pašu primāro atslēgu. Tā kā abas rindas ir jaunas (bāzē to nav), merql nevar tās sapludināt.

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

Konfliktā tiek norādīts: veids insert_insert. Mūsu vērtība satur mūsu rindas datus, bet viņu vērtība — viņu rindas datus.

Conflict klase

Katrs konflikts ir tikai lasāms objekts ar šādām piekļuves metodēm:

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)

Metode column() atgriež kolonnas nosaukumu konfliktiem update_update, bet null — strukturālajiem konfliktiem (update_delete, delete_update, insert_insert).

Primārās atslēgas dekodēšana

Rindas atslēga ir kodēta virkne. Lai iegūtu nosauktu primārās atslēgas masīvu, norādiet identitātes kolonnas:

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

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

Automātiska risināšana ar ConflictPolicy

ConflictResolver piemēro politiku, lai atrisinātu visus konfliktus vienlaikus:

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 uzskaitījums

Vērtība Darbība
OursWins Izmanto mūsu vērtību update_update gadījumā. Saglabā atjauninājumu update_delete gadījumā. Saglabā dzēšanu delete_update gadījumā. Izmanto mūsu ievietoto rindu insert_insert gadījumā.
TheirsWins Izmanto viņu vērtību update_update gadījumā. Dzēš update_delete gadījumā. Saglabā atjauninājumu delete_update gadījumā. Izmanto viņu ievietoto rindu insert_insert gadījumā.
Manual Atgriež rezultātu bez izmaiņām. Visi konflikti paliek neatrisināti.

Kā notiek risināšana

Konfliktiem update_update risinātājs pārveido esošo sapludināšanas darbību šai rindai, aizstājot konfliktējošās kolonnas vērtību ar uzvarējušās puses vērtību.

Strukturālo konfliktu gadījumā (update_delete, delete_update, insert_insert) risinātājs rezultātam pievieno jaunu darbību:

  • update_delete kopā ar OursWins pievieno UPDATE darbību.
  • update_delete kopā ar TheirsWins pievieno DELETE darbību.
  • delete_update kopā ar OursWins pievieno DELETE darbību.
  • delete_update kopā ar TheirsWins pievieno UPDATE darbību.
  • insert_insert izmanto uzvarējušās puses rindas vērtības.

Atrisinātajam MergeResult ir tukšs konfliktu saraksts, un to var lietot tieši.

Manuāla risināšana

Lai precīzi kontrolētu procesu, pārbaudiet katru konfliktu un izveidojiet savu risinājumu:

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

Lietošana ar neatrisinātiem konfliktiem

Applier atsakās lietot sapludināšanas rezultātu, kurā ir neatrisināti konflikti. Tas izmet ConflictException:

PHP
use Merql\Exceptions\ConflictException;

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

Pirms lietošanas vienmēr atrisiniet konfliktus, izmantojot ConflictResolver::resolve() vai manuāli izveidojot tīru MergeResult.