
# Začíname

Táto príručka vás prevedie inštaláciou, pripojením k databáze, zachytávaním snímok, výpočtom rozdielov a vykonaním trojstranného zlúčenia.

## Inštalácia

```bash
composer require merql/merql
```

merql vyžaduje PHP 8.2+ s `ext-mbstring` a `ext-zlib` (obe vyžaduje závislosť `pitmaster/pitmaster`). Potrebujete aj rozšírenie pre použitý ovládač: `ext-pdo` s `ext-pdo_sqlite` alebo `ext-pdo_mysql` pre ovládač PDO, prípadne `ext-mysqli` pre ovládač mysqli. Composer tieto rozšírenia iba odporúča, preto skontrolujte, či je potrebné rozšírenie nainštalované.

Balík nainštaluje CLI ako `vendor/bin/merql`. Pre CLI použite merql 0.4.1 alebo novšiu verziu; v starších vydaniach binárny súbor nedokázal nájsť zavádzač, keď bol merql nainštalovaný ako závislosť.

## Pripojenie k databáze

merql používa jednoduché rozhranie adaptéra pripojenia. Obsahuje vstavané adaptéry pre PDO a mysqli a vstavané ovládače dialektov pre MySQL a SQLite.

```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()` otvára každý DSN podporovaný PDO, ale merql obsahuje ovládače dialektov iba pre MySQL a SQLite. Pri použití iného databázového systému, napríklad `pgsql:`, sa pripojenie otvorí, no `Merql::init()` vyvolá `Unsupported database driver: pgsql`, kým preň nezaregistrujete ovládač. Pozrite si [Ovládače databáz](https://merql.inline0.dev/sk/docs/apply/drivers).

## Zachytenie snímky

Snímka zaznamenáva každý riadok každej tabuľky (alebo podmnožiny tabuliek) vo forme odtlačkov a údajov. Odtlačky umožňujú rýchlo zisťovať zmeny; úplné údaje riadkov sú k dispozícii pri porovnávaní.

```php
use Merql\Merql;

Merql::init($connection);

// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');

// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);
```

Snímky sa predvolene ukladajú ako súbory JSON v adresári `.merql/snapshots/`. Toto umiestnenie môžete zmeniť:

```php
use Merql\Snapshot\SnapshotStore;

SnapshotStore::setDirectory('/var/data/merql-snapshots');
```

## Výpočet rozdielu

Porovnanie dvoch snímok vráti súbor zmien obsahujúci vloženia, aktualizácie a odstránenia. Obe snímky už musia existovať; tu je `current` druhá snímka zachytená po zmene databázy.

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

## Trojstranné zlúčenie

Základná operácia. Prevezme tri pomenované snímky (base, ours, theirs) a zlúči dve množiny zmien.

Base je stav, z ktorého vychádzali obe kópie. Ours a theirs sú dve kópie po tom, ako sa nezávisle zmenili, preto treba každú zachytiť z databázy, v ktorej sa nachádza. Napríklad keď bola testovacia kópia vytvorená z produkčnej databázy:

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

Nevytvárajte všetky tri snímky postupne z jednej databázy. Theirs by už obsahoval zmeny ours a každý riadok vložený v ours by sa zobrazil ako konflikt `insert_insert`.

`Merql::merge()` vykonáva zlúčenie na úrovni stĺpcov. Ak chcete zlúčiť aj obsah hodnôt TEXT a JSON, použite `ThreeWayMerge` s `CellMergeConfig`; pozrite si [Zlučovanie na úrovni buniek](https://merql.inline0.dev/sk/docs/merge/cell-level).

### Riešenie konfliktov

Keď obe strany zmenia ten istý stĺpec na rôzne hodnoty, merql nahlási konflikt. Konflikty môžete vyriešiť automaticky alebo ich preskúmať ručne.

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

## Použitie zlúčenia

Keď máte čistý výsledok zlúčenia (bez nevyriešených konfliktov), použite ho v databáze zadanej cez `Merql::init()`.

Operácie vo výsledku zlúčenia prevedú base na zlúčený stav a zahŕňajú zmeny oboch strán. `Merql::apply()` vykoná každú z nich, preto sa dajú bez problémov použiť v databáze, ktorá stále obsahuje stav base. Ak ich použijete v databáze, ktorá už obsahuje zmeny jednej strany, každý jej vložený riadok narazí na už existujúci riadok, operácia zlyhá a celé zlúčenie sa vráti späť. Ak chcete preniesť zmeny jednej strany do databázy, ktorá už obsahuje zmeny druhej strany (napríklad úpravy v testovacom prostredí do produkcie), použite iba operácie, ktoré jej chýbajú, pomocou [Kontrolované použitie](https://merql.inline0.dev/sk/docs/apply/guarded).

```php
$applied = Merql::apply($result);

echo "Rows affected: {$applied->rowsAffected()}\n";

if ($applied->hasErrors()) {
    foreach ($applied->errors() as $error) {
        echo "Error: {$error}\n";
    }
}
```

Aplikátor zabalí všetky operácie do transakcie. Ak ktorýkoľvek príkaz zlyhá, celé zlúčenie sa vráti späť a chyba sa vráti v `errors()`. V takom prípade `rowsAffected()` stále počíta príkazy vykonané pred zlyhaním, hoci boli vrátené späť ([#4](https://github.com/inline0/merql/issues/4)); najprv skontrolujte `hasErrors()`.

## Skúšobné spustenie

Zobrazte náhľad SQL, ktoré by zlúčenie vytvorilo, bez jeho vykonania.

```php
use Merql\Apply\DryRun;

$statements = DryRun::generate($result);

foreach ($statements as $sql) {
    echo "{$sql};\n";
}
```

## Dvojstranná záplata

Ak máte iba base a množinu zmien (bez súbežných úprav v „ours“), použite `patch()`. To zodpovedá zlúčeniu, pri ktorom sa „ours“ nezmenilo oproti base.

```php
$result = Merql::patch('base', 'changes');
// Always clean: no concurrent edits means no conflicts.
Merql::apply($result);
```

## Používanie CLI

Všetky tieto operácie sú dostupné aj z príkazového riadka. Úplné podrobnosti nájdete v [CLI Referencia](https://merql.inline0.dev/sk/docs/cli).

```bash
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
```

Pri trojstrannom zlúčení vytvorte každú snímku z databázy, ktorá obsahuje príslušný stav, a potom ich zlúčte:

```bash
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
```

## Filtrovanie tabuliek a stĺpcov

Zo snímok možno vylúčiť tabuľky (napríklad tabuľky vyrovnávacej pamäte alebo relácií) a ignorovať nestále stĺpce (napríklad časové značky `updated_at`).

```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']),
]);
```

## Ďalšie kroky

- [CLI Referencia](https://merql.inline0.dev/sk/docs/cli) pre úplné rozhranie príkazového riadka.
- [PHP API Referencia](https://merql.inline0.dev/sk/docs/api) pre podrobnú dokumentáciu každej triedy a metódy.
