
# Reference CLI

merql obsahuje CLI pro pořizování snímků, výpočet rozdílů a spouštění sloučení přímo z terminálu. Composer jej nainstaluje jako `vendor/bin/merql`; v kopii repozitáře merql je dostupný jako `bin/merql`.

`vendor/bin/merql` funguje po instalaci závislostí, protože merql 0.4.1. Starší vydání hledala autoloader Composer pouze v adresáři `vendor/` samotného balíčku a při instalaci merql jako závislosti selhávala.

## Rychlý začátek

```bash
# Capture a baseline from your database.
export MERQL_DB_DSN="sqlite:/path/to/db.sqlite"
vendor/bin/merql snapshot base

# Make some changes, then capture again.
vendor/bin/merql snapshot current

# See what changed.
vendor/bin/merql diff base current
```

Třístranné sloučení vyžaduje, aby ours a theirs byly zachyceny ze dvou databází, které se odchýlily od základu. Pro každý snímek nasměrujte `MERQL_DB_DSN` na správnou databázi:

```bash
# Base: live before the sandbox was copied from it.
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

# Three-way merge with dry-run preview.
vendor/bin/merql merge base ours theirs --dry-run
```

Pořízení všech tří snímků ze stejné databáze jeden po druhém nefunguje jako sloučení: theirs by již obsahovalo změny ours, takže každý řádek vložený ours by byl označen jako konflikt `insert_insert`.

## Proměnné prostředí

CLI načítá údaje o připojení k databázi z proměnných prostředí. Připojit se můžete pomocí řetězce DSN pro PDO nebo jednotlivých parametrů MySQL.

### Připojení přes DSN

Pro připojení přes PDO použijte `MERQL_DB_DSN`. Tento doporučený postup se hodí pro SQLite i nestandardní konfigurace. DSN musí odkazovat na databázi MySQL nebo SQLite: CLI neumí zaregistrovat ovladač pro jiné databázové stroje.

| Proměnná | Popis | Příklad |
|---|---|---|
| `MERQL_DB_DSN` | Úplný řetězec DSN pro PDO | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Uživatelské jméno (u DSN volitelné) | `root` |
| `MERQL_DB_PASS` | Heslo (u DSN volitelné) | `secret` |

```bash
# SQLite file.
export MERQL_DB_DSN="sqlite:/var/data/myapp.sqlite"

# MySQL via DSN.
export MERQL_DB_DSN="mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="secret"
```

Použijte databázi SQLite uloženou v souboru. Každý příkaz CLI běží ve vlastním procesu, takže `sqlite::memory:` pokaždé otevře novou prázdnou databázi a její snímek neobsahuje žádné tabulky.

### Zkrácený zápis MySQL

Pokud není nastaveno `MERQL_DB_DSN`, CLI použije proměnné specifické pro MySQL.

| Proměnná | Výchozí hodnota | Popis |
|---|---|---|
| `MERQL_DB_NAME` | (povinné) | Název databáze |
| `MERQL_DB_HOST` | `127.0.0.1` | Hostitel MySQL |
| `MERQL_DB_PORT` | `3306` | Port MySQL |
| `MERQL_DB_USER` | `root` | Uživatelské jméno MySQL |
| `MERQL_DB_PASS` | (prázdné) | Heslo MySQL |
| `MERQL_DB_ADAPTER` | `pdo` | Nastavením na `mysqli` použijete adaptér mysqli |

```bash
export MERQL_DB_NAME="wordpress"
export MERQL_DB_HOST="127.0.0.1"
export MERQL_DB_PORT="3306"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="password"
```

## Příkazy

### `merql snapshot <name>`

Zachytí aktuální stav databáze určené proměnnými prostředí a uloží jej jako pojmenovaný snímek. Je to jediný příkaz, který se připojuje k databázi.

```bash
vendor/bin/merql snapshot baseline
```

Výstup:

```
Snapshot 'baseline' saved
Tables: posts, comments, users, settings
```

Snímky se ukládají jako soubory JSON do `.merql/snapshots/` v pracovním adresáři (viz [Ukládání snímků](#snapshot-storage)). Název smí obsahovat pouze alfanumerické znaky, pomlčky a podtržítka.

Typický postup: před provedením změn pořiďte snímek a poté pořiďte další. Tyto dva snímky slouží jako podklad pro rozdíl nebo sloučení.

### `merql diff <base> <current>`

Porovná dva pojmenované snímky a zobrazí souhrn rozdílů.

```bash
vendor/bin/merql diff baseline current
```

Výstup:

```
Changeset: baseline -> current
  Inserts: 3
  Updates: 7
  Deletes: 1
```

Oba snímky už musí existovat (musely být dříve pořízeny pomocí `merql snapshot`). Rozdíl nevyžaduje připojení k databázi, protože pracuje s uloženými soubory snímků.

### `merql merge <base> <ours> <theirs>`

Provede třícestné sloučení tří pojmenovaných snímků.

```bash
vendor/bin/merql merge base ours theirs
```

Výstup:

```
Merge: base + ours + theirs
  Operations: 12
  Conflicts:  0
  Clean:      yes
```

Všechny tři snímky už musí existovat. Sloučení nevyžaduje připojení k databázi, protože pracuje s uloženými soubory snímků, a do databáze nikdy nic nezapisuje: CLI nemá příkaz pro použití změn. Výsledek sloučení použijte pomocí PHP API.

CLI slučuje na úrovni sloupců. Neslučuje obsah buněk ve sloupcích TEXT ani JSON, takže dvě různé úpravy téhož sloupce vždy představují konflikt ([#7](https://github.com/inline0/merql/issues/7)). Pro slučování na úrovni buněk použijte `ThreeWayMerge` s `CellMergeConfig` v PHP.

#### `--dry-run`

Přidejte příznak `--dry-run`, aby se zobrazily příkazy SQL, které by sloučení vygenerovalo, aniž by se provedly. Příkazy popisují, jak převést základní stav na sloučený výsledek, a zahrnují proto změny z obou stran.

```bash
vendor/bin/merql merge base ours theirs --dry-run
```

Výstup:

```
Merge: base + ours + theirs
  Operations: 3
  Conflicts:  0
  Clean:      yes

Dry run SQL:
  INSERT INTO `posts` (`id`, `title`, `status`) VALUES ('10', 'New Post', 'draft');
  UPDATE `posts` SET `title` = 'Updated Title' WHERE `id` = '5';
  DELETE FROM `comments` WHERE `id` = '3';
```

## Vývojářské příkazy

Klon repozitáře merql obsahuje ve složce `bin/` další skripty pro testovací sadu řízenou referenčními výsledky. Nejsou součástí balíčku Composer, takže instalace závislostí zpřístupní pouze `vendor/bin/merql`. Spouštějte je z kořenové složky repozitáře po provedení `composer install`.

| Příkaz | Popis |
|---|---|
| `./bin/oracle <name>` | Vypočítá očekávaný výsledek sloučení pro scénář |
| `./bin/actual <name>` | Spustí merql pro scénář a zachytí výstup |
| `./bin/compare <name>` | Porovná referenční a skutečný výstup |
| `./bin/test-scenario <name>` | Celý postup: příprava, referenční výsledek, skutečný výsledek, porovnání |
| `./bin/test-regression` | Spustí všechny scénáře |
| `./bin/test-regression --category clean` | Spustí jednu kategorii: `clean`, `conflict`, `identity`, `types`, `scale` nebo `edge` |
| `./bin/test-regression --fast` | Pouze úspěch či neúspěch, bez výkazů |
| `./bin/verify-compliance` | Úplný výkaz o shodě |
| `./bin/verify-all` | PHPStan + kontrola stylu kódu + PHPUnit + regresní testy referenčních výsledků |

`bin/test-regression` přijímá také `--jobs`, jeho hodnotu však v současnosti ignoruje a spouští scénáře jeden po druhém ([#5](https://github.com/inline0/merql/issues/5)). Neznámé `--category` vypíše `No scenarios found` a skončí úspěšně.

Rozvržení scénářů najdete v [Testovací strategii](https://merql.inline0.dev/cs/docs/advanced/testing).

## Návratový stav

Příkazy `merql snapshot`, `diff` a `merge` skončí se stavem 1, pokud chybí argument; `snapshot` skončí stejně také v případě, že není nakonfigurováno připojení. Při chybějícím snímku příkaz skončí nezachycenou výjimkou `SnapshotException` a nenulovým stavem. Neznámý příkaz vypíše `Unknown command`, ale v současnosti skončí se stavem 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Ukládání snímků

Snímky se ukládají do `.merql/snapshots/` vzhledem k pracovnímu adresáři. Každý snímek tvoří jeden soubor JSON s názvem `<name>.json`. Všechny příkazy spouštějte ze stejného adresáře, aby našly snímky vytvořené ostatními příkazy.

CLI nemá volbu ani proměnnou prostředí pro změnu umístění ([#8](https://github.com/inline0/merql/issues/8)). Chcete-li použít jiné umístění, přejděte před spuštěním do jiného pracovního adresáře. V PHP nastavte adresář před pořízením nebo načtením snímků:

```php
use Merql\Snapshot\SnapshotStore;

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

Soubory snímků jsou přenositelné. Můžete je kopírovat mezi počítači, zařadit do správy verzí nebo sdílet při společném ladění. Snímek pořízený pomocí CLI lze načíst v PHP pomocí `SnapshotStore::load()`, a také naopak, pokud oba používají stejný adresář.
