Ελεγχόμενη εφαρμογή
Το GuardedApplier εφαρμόζει μια καθαρή MergeResult μόνο αν η βάση δεδομένων προορισμού εξακολουθεί
να αντιστοιχεί στο αναμενόμενο ενεργό στιγμιότυπο. Είναι χρήσιμο όταν το σχέδιο συγχώνευσης έχει
ελεγχθεί νωρίτερα και οι ενεργές γραμμές μπορεί να έχουν αλλάξει πριν από την εφαρμογή.
Η συνήθης ρύθμιση προωθεί τις αλλαγές ενός απομονωμένου περιβάλλοντος σε μια ενεργή βάση δεδομένων. Η βάση
είναι η ενεργή βάση τη στιγμή που αντιγράφηκε το απομονωμένο περιβάλλον, εμείς είναι το επεξεργασμένο απομονωμένο περιβάλλον
και εκείνοι είναι η ενεργή βάση όπως είναι τώρα. Στόχος είναι η ενεργή βάση, επομένως
το αναμενόμενο ενεργό στιγμιότυπο είναι το theirs και οι λειτουργίες προς εγγραφή είναι όσες
λείπουν ακόμη από την ενεργή βάση (βλ. Επιλογή λειτουργιών).
use Merql\Connection;
use Merql\Merql;
use Merql\Plan\OperationSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;
Merql::init(Connection::sqlite('/data/live.sqlite'));
$plan = Merql::plan('promote-1', 'base', 'ours', 'theirs');
// Skip rows with unresolved conflicts.
$conflicted = [];
foreach ($plan->conflicts as $conflict) {
$conflicted[$conflict->table . "\0" . $conflict->rowKey] = true;
}
$ids = [];
foreach ($plan->operations as $operation) {
$missing = $operation->source === 'ours'
|| ($operation->source === 'merged' && $operation->type === 'update');
if ($missing && !isset($conflicted[$operation->table . "\0" . $operation->rowKey])) {
$ids[] = $operation->id;
}
}
$selected = (new SelectedMergeResultFactory())->fromOperationSelection(
$plan,
OperationSelection::fromIds($ids),
SnapshotStore::load('base'),
);
$applied = Merql::applyGuarded($selected, SnapshotStore::load('theirs'));
if ($applied->hasErrors()) {
foreach ($applied->errors() as $error) {
echo $error . "\n";
}
}
Το Merql::applyGuarded() γράφει στη βάση δεδομένων που περνάτε στο Merql::init(). Το
αναμενόμενο ενεργό στιγμιότυπο πρέπει να περιγράφει την ίδια βάση δεδομένων: λάβετέ το από τον
στόχο και φροντίστε να είναι αρκετά πρόσφατο ώστε οι προϋποθέσεις να έχουν νόημα.
Προϋποθέσεις
Η ελεγχόμενη SQL προσθέτει προϋποθέσεις για τις ενεργές γραμμές στις δημιουργούμενες εντολές:
- οι ενημερώσεις απαιτούν να υπάρχει η ταυτότητα της γραμμής-στόχου και οι τιμές των στηλών που δεν αφορούν την ταυτότητα να αντιστοιχούν στην αναμενόμενη ενεργή γραμμή,
- οι διαγραφές απαιτούν να υπάρχει η ταυτότητα της γραμμής-στόχου και οι τιμές των στηλών που δεν αφορούν την ταυτότητα να αντιστοιχούν στην αναμενόμενη ενεργή γραμμή,
- οι εισαγωγές απαιτούν να μην υπάρχει ήδη η ταυτότητα-στόχος.
Αν οποιαδήποτε εντολή επηρεάσει μηδενικές γραμμές, το merql θεωρεί ότι το σχέδιο είναι παρωχημένο. Η συναλλαγή αναστρέφεται και το επιστρεφόμενο ApplyResult περιέχει το σφάλμα Optimistic precondition failed for guarded merge statement.
Στο MySQL, μια ενημέρωση της οποίας οι τιμές είναι ήδη ίδιες με εκείνες της ενεργής γραμμής επηρεάζει επίσης μηδενικές γραμμές, επειδή το MySQL μετρά τις γραμμές που άλλαξαν και όχι όσες αντιστοιχίστηκαν. Μια τέτοια ενημέρωση αποτυγχάνει ως παρωχημένη, παρόλο που η γραμμή αντιστοιχεί (#2). Το SQLite μετρά τις γραμμές που αντιστοιχίστηκαν και την αποδέχεται. Αυτό μπορεί να συμβεί με μια ενημέρωση merged όταν και οι δύο πλευρές έκαναν την ίδια αλλαγή σε μια γραμμή.
Επιλογή ενεργειών
Ένα αποτέλεσμα συγχώνευσης περιλαμβάνει τις ενέργειες και των δύο πλευρών, καθώς μετατρέπει τη βάση στην κατάσταση που προέκυψε από τη συγχώνευση. Αν εφαρμοστεί σε έναν στόχο που περιέχει ήδη τις αλλαγές της άλλης πλευράς, οι ενέργειες που προήλθαν από αυτήν περιγράφουν αλλαγές που υπάρχουν ήδη στον στόχο, οπότε οι προϋποθέσεις τους αποτυγχάνουν:
| Ενέργεια | Κατάσταση σε στόχο που περιέχει τις αλλαγές της άλλης πλευράς | Επιλογή |
|---|---|---|
ours εισαγωγή, ενημέρωση ή διαγραφή |
Απουσιάζει | Ναι |
merged ενημέρωση (και οι δύο πλευρές άλλαξαν τη γραμμή) |
Έχει τις στήλες της άλλης πλευράς, λείπουν οι δικές μας | Ναι |
theirs εισαγωγή |
Η γραμμή υπάρχει, άρα η προστατευμένη εισαγωγή επηρεάζει μηδενικές γραμμές | Όχι |
merged διαγραφή (και οι δύο πλευρές διέγραψαν τη γραμμή) |
Η γραμμή έχει διαγραφεί, άρα η προστατευμένη διαγραφή επηρεάζει μηδενικές γραμμές | Όχι |
theirs ενημέρωση ή διαγραφή |
Έχει ήδη εφαρμοστεί | Όχι |
Επομένως, η μεταβίβαση ολόκληρου του αποτελέσματος του Merql::merge() στο applyGuarded() αποτυγχάνει μόλις η άλλη πλευρά εισαγάγει μια γραμμή ή και οι δύο πλευρές διαγράψουν μια γραμμή. Επιλέξτε πρώτα τις ενέργειες, με βάση την πηγή όπως παραπάνω ή με ένα ChangeGroupSelection που δημιουργήθηκε από μια ανασκόπηση UI. Παραλείψτε τις γραμμές που αναφέρονται στο $plan->conflicts: ένα επιλεγμένο αποτέλεσμα είναι πάντα καθαρό και η ενέργεια μιας γραμμής σε διένεξη διατηρεί τη δική μας τιμή στη στήλη που έχει τη διένεξη (δείτε τα Σχέδια συγχώνευσης).
Επιλεκτική εφαρμογή
Η προστατευμένη εφαρμογή λειτουργεί με επιλεγμένα αποτελέσματα συγχώνευσης που παράγονται από σχέδιο συγχώνευσης, συμπεριλαμβανομένων των επιλογών που γίνονται ανά ομάδα αλλαγών.
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;
$selection = ChangeGroupSelection::fromIds([$plan->changeGroups[0]->id]);
$selected = (new SelectedMergeResultFactory())->fromChangeGroupSelection(
$plan,
$selection,
SnapshotStore::load($plan->baseSnapshot),
);
$applied = Merql::applyGuarded($selected, SnapshotStore::load($plan->theirsSnapshot));
Έτσι, μια εφαρμογή υποδοχής μπορεί να προετοιμάσει ένα υποσύνολο των ομάδων που εξετάστηκαν και να επιβεβαιώσει ότι οι ενεργές γραμμές δεν άλλαξαν από τη δημιουργία του σχεδίου.
Προεπισκόπηση SQL
Χρησιμοποιήστε το SqlGenerator::generateGuarded() για να επιθεωρήσετε τις προστατευμένες εντολές χωρίς να τις εκτελέσετε.
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;
$statements = SqlGenerator::generateGuarded(
$selected,
SnapshotStore::load($plan->theirsSnapshot),
);
foreach ($statements as $statement) {
echo $statement['sql'] . "\n";
}
Οι εντολές που δημιουργούνται εξακολουθούν να χρησιμοποιούν παραμέτρους. Οι προϋποθέσεις εκφράζονται με πρόσθετες ρήτρες WHERE για ενημερώσεις και διαγραφές και ελέγχους NOT EXISTS για εισαγωγές.
Προστατευμένη ή απλή εφαρμογή
Το Merql::apply() εκτελεί τις ίδιες ενέργειες χωρίς προϋποθέσεις. Οι ενημερώσεις και οι διαγραφές πετυχαίνουν ανεξάρτητα από το αν άλλαξε η ενεργή γραμμή από τη δημιουργία του σχεδίου, ενώ μια εισαγωγή γραμμής που υπάρχει ήδη αποτυγχάνει με το σφάλμα διπλού κλειδιού της βάσης δεδομένων. Χρησιμοποιήστε απλή εφαρμογή για έναν στόχο που γνωρίζετε ότι εξακολουθεί να περιέχει τη βάση και προστατευμένη εφαρμογή όταν άλλοι συντάκτες μπορεί να έχουν τροποποιήσει τον στόχο μετά τη λήψη του στιγμιότυπου.