Alustamine
See juhend käsitleb paigaldamist, andmebaasiga ühenduse loomist, hetktõmmiste salvestamist, erinevuste arvutamist ja kolmeosalist ühendamist.
Paigaldamine
composer require merql/merql
merql vajab versiooni PHP 8.2 või uuemat koos laiendustega ext-mbstring ja ext-zlib (mõlemad on vajalikud sõltuvusele pitmaster/pitmaster). Samuti vajate kasutatava adapteri laiendust: PDO-adapteri jaoks ext-pdo koos ext-pdo_sqlite või ext-pdo_mysql-ga või mysqli-adapteri jaoks ext-mysqli. Composer ainult soovitab neid, seega kontrollige, et vajalik laiendus oleks paigaldatud.
Pakett paigaldab CLI-i nimega vendor/bin/merql. Kasutage merqli versiooni 0.4.1 või uuemat CLI jaoks; varasemates versioonides ei leidnud binaarfail automaatlaadijat, kui merql oli paigaldatud sõltuvusena.
Andmebaasiga ühenduse loomine
merql kasutab väikest ühendusadapteri liidest. Sisseehitatud adapterid on saadaval PDO ja mysqli jaoks ning sisseehitatud dialektidraiverid MySQL ja SQLite jaoks.
use Merql\Connection;
// SQLite (in-memory or file-based, through PDO).
$connection = Connection::sqlite(':memory:');
$connection = Connection::sqlite('/path/to/database.sqlite');
// MySQL through PDO.
$connection = Connection::mysql('127.0.0.1', 'my_database', 'root', 'password');
// MySQL through mysqli.
$connection = Connection::mysqli('127.0.0.1', 'my_database', 'root', 'password');
// Any MySQL or SQLite PDO DSN.
$connection = Connection::fromDsn('mysql:host=127.0.0.1;dbname=my_database;charset=utf8mb4', 'root', 'password');
fromDsn() avab mis tahes DSN-i, mida PDO toetab, kuid merql sisaldab dialektidraivereid ainult MySQL ja SQLite jaoks. Teise andmebaasimootori, näiteks pgsql: korral, ühendus küll avaneb, kuid Merql::init() annab vea Unsupported database driver: pgsql, kuni registreerite selle jaoks draiveri. Vaadake andmebaasidraivereid.
Hetktõmmise salvestamine
Hetktõmmis talletab iga tabeli iga rea (või valitud tabelite read) sõrmejälgede ja andmetena. Sõrmejäljed võimaldavad muudatusi kiiresti tuvastada; erinevuse arvutamisel on saadaval terve rea andmed.
use Merql\Merql;
Merql::init($connection);
// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');
// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);
Hetktõmmised salvestatakse vaikimisi failidena JSON asukohta .merql/snapshots/. Saate seda asukohta muuta:
use Merql\Snapshot\SnapshotStore;
SnapshotStore::setDirectory('/var/data/merql-snapshots');
Erinevuse arvutamine
Erinevuse arvutamisel võrreldakse kaht hetktõmmist ning tagastatakse lisamiste, uuenduste ja kustutamiste muudatuste komplekt. Mõlemad hetktõmmised peavad juba olemas olema; siin on current teine hetktõmmis, mis salvestati pärast andmebaasi muutmist.
$changeset = Merql::diff('baseline', 'current');
echo "Inserts: " . count($changeset->inserts()) . "\n";
echo "Updates: " . count($changeset->updates()) . "\n";
echo "Deletes: " . count($changeset->deletes()) . "\n";
// Inspect changes for a single table.
$postChanges = $changeset->forTable('posts');
// Check per-column diffs on updates.
foreach ($changeset->updates() as $update) {
echo "Row {$update->rowKey} in {$update->table}:\n";
foreach ($update->columnDiffs as $diff) {
echo " {$diff->column}: {$diff->oldValue} -> {$diff->newValue}\n";
}
}
Kolmeosaline ühendamine
Põhitoiming. Võtab kolm nimega hetktõmmist (base, ours, theirs) ja ühendab kaks muudatuste komplekti.
Base on olek, millest mõlemad koopiad alustasid. Ours ja theirs on kaks koopiat pärast nende sõltumatuid muudatusi, seega tuleb kumbki salvestada seda sisaldavast andmebaasist. Näiteks kui liivakast kopeeriti aktiivsest andmebaasist:
use Merql\Connection;
use Merql\Merql;
$live = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');
Merql::init($live);
Merql::snapshot('base'); // before the sandbox is copied from live
// ... copy live.sqlite to sandbox.sqlite, then both databases change ...
Merql::init($sandbox);
Merql::snapshot('ours'); // the sandbox with our edits
Merql::init($live);
Merql::snapshot('theirs'); // live with its own changes
$result = Merql::merge('base', 'ours', 'theirs');
echo "Operations: {$result->operationCount()}\n";
echo "Conflicts: {$result->conflictCount()}\n";
echo "Clean: " . ($result->isClean() ? 'yes' : 'no') . "\n";
Ärge salvestage kõiki kolme hetktõmmist järjest ühest andmebaasist. Sel juhul sisaldaks theirs juba ours-i muudatusi ning iga ours-i lisatud rida märgitaks insert_insert konfliktiks.
Merql::merge() ühendab veerutasemel. TEXT- ja JSON-väärtuste sisemuse ühendamiseks kasutage ThreeWayMerge koos CellMergeConfig-ga; vt lahtritasemel ühendamist.
Konfliktide käsitlemine
Kui mõlemad pooled muudavad sama veeru väärtuse erinevaks, annab merql konfliktiteate. Saate konfliktid automaatselt lahendada või neid käsitsi kontrollida.
use Merql\Merge\ConflictPolicy;
use Merql\Merge\ConflictResolver;
if (!$result->isClean()) {
// Auto-resolve: one side wins.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);
// Or inspect each conflict.
foreach ($result->conflicts() as $conflict) {
echo "Conflict on {$conflict->table()} row {$conflict->rowKey()}:\n";
echo " Type: {$conflict->type()}\n";
echo " Column: {$conflict->column()}\n";
echo " Ours: " . var_export($conflict->oursValue(), true) . "\n";
echo " Theirs: " . var_export($conflict->theirsValue(), true) . "\n";
}
}
Ühendamise rakendamine
Kui ühendamistulemus on puhas (lahendamata konflikte pole), rakendage see andmebaasile, mis on antud käsule Merql::init().
Ühendamistulemuse toimingud viivad baasolukorra ühendatud olekusse ja hõlmavad mõlema poole muudatusi. Merql::apply() käivitab need kõik, seega saab neid puhtalt rakendada andmebaasile, milles on endiselt baasolek. Andmebaasis, mis sisaldab juba ühe poole muudatusi, ebaõnnestub selle poole lisamistoiming, sest rida on juba olemas, ning kogu ühendamine pööratakse tagasi. Ühe poole muudatuste kandmiseks andmebaasi, kus on juba teise poole muudatused (näiteks liivakasti muudatuste lisamiseks aktiivsesse andmebaasi), rakendage ainult puuduvaid toiminguid käsuga kaitstud rakendamine.
$applied = Merql::apply($result);
echo "Rows affected: {$applied->rowsAffected()}\n";
if ($applied->hasErrors()) {
foreach ($applied->errors() as $error) {
echo "Error: {$error}\n";
}
}
Rakendaja ümbritseb kõik toimingud tehinguga. Kui mõni lause ebaõnnestub, pööratakse kogu ühendamine tagasi ja viga tagastatakse väärtuses errors(). Sel juhul loendab rowsAffected() endiselt enne viga käivitatud laused, kuigi nende mõju pöörati tagasi (#4); kontrollige esmalt hasErrors().
Kuivkäivitus
Vaadake eelvaates SQL, mille ühendamine looks, ilma seda käivitamata.
use Merql\Apply\DryRun;
$statements = DryRun::generate($result);
foreach ($statements as $sql) {
echo "{$sql};\n";
}
Kahesuunaline paigamoodustus
Kui teil on ainult baas ja muudatuste komplekt (samaaegseid "ours"-muudatusi pole), kasutage patch(). See vastab ühendamisele, kus ours pole baasi suhtes muutunud.
$result = Merql::patch('base', 'changes');
// Always clean: no concurrent edits means no conflicts.
Merql::apply($result);
CLI kasutamine
Kõik need toimingud on saadaval ka käsurealt. Üksikasjalikku teavet leiate CLI viitejuhendist.
export MERQL_DB_DSN="sqlite:mydb.sqlite"
vendor/bin/merql snapshot base
# ... change the database ...
vendor/bin/merql snapshot current
vendor/bin/merql diff base current
Kolmeosalise ühendamise jaoks salvestage iga hetktõmmis seda olekut sisaldavast andmebaasist ning seejärel ühendage need:
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
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
Tabelite ja veergude filtreerimine
Hetktõmmistest saab tabelid (nt vahemälu- või seansitabelid) välja jätta ja muutlikke veerge (nt updated_at ajatemplid) eirata.
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;
$snapshotter = new Snapshotter($connection);
$snapshot = $snapshotter->capture('baseline', filters: [
TableFilter::exclude(['sessions', 'cache_*']),
ColumnFilter::ignore(['updated_at', 'modified_date']),
]);
Järgmised sammud
- CLI viitejuhend kogu käsurealiidese kohta.
- PHP API viitejuhend kõigi klasside ja meetodite üksikasjaliku dokumentatsiooniga.