Introduktion
merql er et rent PHP-bibliotek, der udfører trevejsfletninger af databasetilstand. Det tager snapshots af tabeller, beregner ændringssæt mellem snapshots, fletter to sæt ændringer ud fra en fælles basis og registrerer konflikter på kolonneniveau. Den samme algoritme, som git bruger til kildefiler, anvendes her på rækker og kolonner i stedet for linjer.
Ingen eksterne værktøjer. Understøtter MySQL og SQLite via tilslutningsbare forbindelsesadaptere og dialektdrivere.
Hurtigt eksempel
En fletning kræver tre tilstande af de samme data: den base, begge kopier startede fra, og de to kopier efter uafhængige ændringer. Her blev en sandkasse kopieret fra live-databasen, og begge er siden blevet redigeret.
use Merql\Connection;
use Merql\Merql;
$live = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');
// Base: live at the moment the sandbox was copied from it.
Merql::init($live);
Merql::snapshot('base');
// ... copy live.sqlite to sandbox.sqlite, then both databases change ...
// Ours: the sandbox with our edits. Theirs: live with its own changes.
Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');
$result = Merql::merge('base', 'ours', 'theirs');
if ($result->isClean()) {
foreach ($result->operations() as $operation) {
echo "{$operation->type} {$operation->table} #{$operation->rowKey} ({$operation->source})\n";
}
} else {
echo "Conflicts: {$result->conflictCount()}\n";
}
Hvert øjebliksbillede tages fra den database, der indeholder den pågældende tilstand. At tage alle tre fra én database i rækkefølge beskriver ikke to divergerede kopier: theirs ville allerede indeholde ændringerne fra ours, og hver række, som ours indsatte, ville blive rapporteret som en insert_insert-konflikt.
Resultatet viser de handlinger fra begge sider, der ændrer base til den flettede tilstand, hver markeret med sin kilde (ours, theirs eller merged). Hvis sandboxens ændringer skal overføres til live, skal du anvende de handlinger, som live endnu ikke har, med Guarded Apply.
Eller fra CLI, som opretter forbindelse til databasen med navnet i MERQL_DB_DSN for hver snapshot:
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
# ... copy live.sqlite to sandbox.sqlite, then both databases change ...
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs
vendor/bin/merql merge base ours theirs --dry-run
Hvorfor merql
De fleste databaseværktøjer, der sammenligner tilstande, arbejder på rækkeniveau: Hvis en kolonne i en række afviger mellem to versioner, markeres hele rækken som en konflikt. Det giver falske konflikter, når to personer redigerer forskellige kolonner i samme række.
merql fletter på kolonneniveau. Hvis den ene side har ændret title, og den anden har ændret status, flettes ændringerne uden konflikt. Der opstår kun en konflikt, hvis begge sider ændrer den samme kolonne til forskellige værdier.
For TEXT- og JSON-kolonner kan merql gå et niveau dybere med fletning på celleniveau. To redigeringer af forskellige linjer i en tekstkolonne eller forskellige nøgler i en JSON-kolonne kan flettes uden konflikt ved hjælp af den samme trevejsalgoritme. Fletning på celleniveau er valgfri: Send en CellMergeConfig til ThreeWayMerge. Facaden Merql og CLI fletter kun på kolonneniveau. Se Fletning på celleniveau.
Flettemodellen
Base (snapshot at fork time)
/ \
Ours (one copy's changes) Theirs (the other copy's changes)
\ /
--------- MERGE ----------
|
Merged result
+ conflicts (if any)
Tre tilstande, som i git. Base er den fælles forfader. Vores og deres er de to kopier efter deres forgrening, hver hentet fra sin egen database. Flettereglerne behandler begge sider ens. Navnene vises i hver handlings source, i konflikttyper (update_delete betyder, at vores er opdateret, og deres er slettet) og i løsningspolitikkerne OursWins og TheirsWins. Uden en fælles base kan du ikke skelne mellem »tilføjet« og »uændret«.
En fletning skriver ikke noget i sig selv. Handlingerne ændrer base til den flettede tilstand, så Merql::apply() udfører dem alle uden problemer kun på en database, der stadig indeholder base. Hvis du vil overføre den ene sides ændringer til en database, der allerede indeholder den anden side, f.eks. sandbox-redigeringer til live, skal du kun anvende de handlinger, den mangler. Se Guarded Apply.
Krav
- PHP 8.2 eller nyere.
ext-mbstringogext-zlib, som kræves af afhængighedenpitmaster/pitmaster, der leverer tekstdifferencen.- En databaseudvidelse til den adapter, du bruger:
ext-pdomedext-pdo_sqliteellerext-pdo_mysql, ellerext-mysqli. merqlscomposer.jsonforeslår kunext-pdoogext-mysqli, så Composer kontrollerer ikke, om de findes. - En database af typen MySQL eller SQLite. Andre systemer kræver en brugerdefineret driver.
Hvad det ikke er
merql er ikke et værktøj til skemamigrering. Det replikerer ikke databaser eller synkroniserer dem i realtid. Det løser ét specifikt problem: Givet tre databasetilstande opretter det en flettet fjerde tilstand, hvor konflikterne er identificeret.
Dokumentation
- Kom godt i gang -- installation, første øjebliksbillede, første fletning.
- CLI Reference -- fuld reference til kommandoen
vendor/bin/merql. - PHP API Reference -- komplet API-dokumentation for alle klasser.
- Fletteplaner -- stabile handlings-id'er, ændringsgrupper og valg.
- Guarded Apply -- udvalgte skrivninger med forudbetingelser for live-rækker.
- Tilbagerulning -- tilbagerulningsartefakter og afvigelseskontroller.