Liigu sisu juurde

Alustamine

See juhend käsitleb paigaldamist, andmebaasiga ühenduse loomist, hetktõmmiste salvestamist, erinevuste arvutamist ja kolmeosalist ühendamist.

Paigaldamine

Shell
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.

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

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

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

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

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

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

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

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

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

Shell
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:

Shell
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.

PHP
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