
# Referință pentru CLI

merql include un CLI pentru capturarea instantaneelor, calcularea diferențelor și executarea îmbinărilor direct din terminal. Composer îl instalează ca `vendor/bin/merql`; într-o copie locală a depozitului merql, acesta este `bin/merql`.

`vendor/bin/merql` funcționează după instalarea ca dependență, deoarece merql 0.4.1. Versiunile anterioare căutau autoloaderul Composer doar în directorul `vendor/` propriu al pachetului și eșuau când merql era instalat ca dependență.

## Pornire rapidă

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

O îmbinare în trei direcții necesită instantanee ale versiunilor noastre și ale celorlalți, capturate din două baze de date care au evoluat separat pornind de la baza comună. Indicați baza de date potrivită pentru fiecare instantaneu folosind `MERQL_DB_DSN`:

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

Capturarea pe rând a tuturor celor trei instantanee din aceeași bază de date nu funcționează pentru o îmbinare: versiunea celorlalți ar conține deja modificările noastre, astfel că fiecare rând inserat de noi ar fi raportat drept conflict `insert_insert`.

## Variabile de mediu

CLI citește detaliile conexiunii la baza de date din variabilele de mediu. Vă puteți
conecta folosind fie un șir DSN PDO, fie parametri MySQL individuali.

### Conexiune bazată pe DSN

Folosiți `MERQL_DB_DSN` pentru conexiunile bazate pe PDO. Aceasta este abordarea recomandată
pentru SQLite și pentru configurațiile nestandard. DSN-ul trebuie să indice o bază de date MySQL
sau SQLite: CLI nu poate înregistra un driver pentru alte motoare.

| Variabilă | Descriere | Exemplu |
|---|---|---|
| `MERQL_DB_DSN` | Șir DSN PDO complet | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Nume de utilizator (opțional cu DSN) | `root` |
| `MERQL_DB_PASS` | Parolă (opțională cu DSN) | `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"
```

Folosiți o bază de date SQLite bazată pe fișier. Fiecare comandă CLI rulează
într-un proces propriu, așadar `sqlite::memory:` deschide întotdeauna o bază de date nouă și goală, iar instantaneul acesteia
nu conține tabele.

### Forma prescurtată MySQL

Când `MERQL_DB_DSN` nu este setat, CLI folosește ca alternativă variabilele specifice MySQL.

| Variabilă | Valoare implicită | Descriere |
|---|---|---|
| `MERQL_DB_NAME` | (obligatoriu) | Numele bazei de date |
| `MERQL_DB_HOST` | `127.0.0.1` | Gazda MySQL |
| `MERQL_DB_PORT` | `3306` | Portul MySQL |
| `MERQL_DB_USER` | `root` | Numele de utilizator MySQL |
| `MERQL_DB_PASS` | (gol) | Parola MySQL |
| `MERQL_DB_ADAPTER` | `pdo` | Setați la `mysqli` pentru a folosi adaptorul 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"
```

## Comenzi

### `merql snapshot <name>`

Capturați starea curentă a bazei de date indicate de variabilele de mediu și salvați-o ca instantaneu cu nume. Aceasta este singura comandă care se conectează la o bază de date.

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

Rezultat:

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

Instantaneele sunt salvate ca fișiere JSON în `.merql/snapshots/`, sub directorul de lucru (consultați [Stocarea instantaneelor](#snapshot-storage)). Numele poate conține doar caractere alfanumerice, cratime și liniuțe de subliniere.

Flux de lucru obișnuit: capturați un instantaneu înainte de a face modificări, apoi capturați altul după. Cele două instantanee stau la baza unei comparații sau îmbinări.

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

Comparați două instantanee cu nume și afișați un rezumat al diferențelor.

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

Rezultat:

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

Ambele instantanee trebuie să existe deja (capturate anterior cu `merql snapshot`). Comparația nu necesită o conexiune la baza de date, deoarece operează pe fișierele de instantaneu salvate.

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

Efectuați o îmbinare în trei direcții a trei instantanee cu nume.

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

Rezultat:

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

Toate cele trei instantanee trebuie să existe deja. Îmbinarea nu necesită o conexiune la baza de date, deoarece operează pe fișierele de instantaneu salvate, și nu scrie niciodată într-o bază de date: CLI nu are nicio comandă de aplicare. Folosiți PHP API pentru a aplica rezultatul îmbinării.

CLI face îmbinarea la nivel de coloană. Nu aplică îmbinarea la nivel de celulă pentru coloanele TEXT sau JSON, așadar două editări diferite ale aceleiași coloane sunt întotdeauna un conflict aici ([#7](https://github.com/inline0/merql/issues/7)). Pentru îmbinare la nivel de celulă, folosiți `ThreeWayMerge` cu un `CellMergeConfig` în PHP.

#### `--dry-run`

Adăugați opțiunea `--dry-run` pentru a previzualiza instrucțiunile SQL pe care le-ar genera îmbinarea, fără a executa nimic. Instrucțiunile descriu cum să transformați starea de bază în rezultatul îmbinat, așadar includ modificările ambelor părți.

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

Rezultat:

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

## Comenzi de dezvoltare

O copie locală a depozitului merql include mai multe scripturi în `bin/` pentru suita sa de teste bazată pe oracle. Acestea nu fac parte din pachetul Composer, așadar instalarea ca dependență include doar `vendor/bin/merql`. Rulați-le din rădăcina depozitului după `composer install`.

| Comandă | Descriere |
|---|---|
| `./bin/oracle <name>` | Calculează rezultatul de îmbinare așteptat pentru un scenariu |
| `./bin/actual <name>` | Rulează merql pentru un scenariu și capturează rezultatul |
| `./bin/compare <name>` | Compară rezultatul oracle cu cel efectiv |
| `./bin/test-scenario <name>` | Flux complet: configurare, oracle, rezultat efectiv, comparare |
| `./bin/test-regression` | Rulează toate scenariile |
| `./bin/test-regression --category clean` | Rulează o categorie: `clean`, `conflict`, `identity`, `types`, `scale` sau `edge` |
| `./bin/test-regression --fast` | Doar reușită/eșec, fără rapoarte |
| `./bin/verify-compliance` | Raport complet de conformitate |
| `./bin/verify-all` | PHPStan + stilul codului + PHPUnit + regresie oracle |

`bin/test-regression` acceptă și `--jobs`, dar momentan ignoră valoarea și rulează scenariile unul după altul ([#5](https://github.com/inline0/merql/issues/5)). O valoare `--category` necunoscută afișează `No scenarios found` și se încheie cu succes.

Consultați [Strategia de testare](https://merql.inline0.dev/ro/docs/advanced/testing) pentru structura scenariilor.

## Cod de ieșire

`merql snapshot`, `diff` și `merge` se încheie cu codul 1 când lipsește un argument, iar `snapshot` se încheie la fel și când nu este configurată nicio conexiune. Dacă lipsește un instantaneu, comanda se încheie cu o excepție `SnapshotException` neprinsă și un cod de ieșire diferit de zero. O comandă necunoscută afișează `Unknown command`, dar momentan se încheie cu codul 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Stocarea instantaneelor

Instantaneele sunt stocate în `.merql/snapshots/` relativ la directorul de lucru. Fiecare instantaneu este un singur fișier JSON cu numele `<name>.json`. Rulați toate comenzile din același director pentru ca acestea să găsească instantaneele celorlalte comenzi.

CLI nu are nicio opțiune sau variabilă de mediu pentru o altă locație ([#8](https://github.com/inline0/merql/issues/8)). Pentru a folosi altă locație, schimbați directorul de lucru înainte de a-l rula. În PHP, setați directorul înainte de a captura sau încărca instantanee:

```php
use Merql\Snapshot\SnapshotStore;

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

Fișierele de instantaneu sunt portabile. Le puteți copia între mașini, include în sistemul de control al versiunilor sau partaja pentru depanare colaborativă. Un instantaneu capturat de CLI poate fi încărcat în PHP cu `SnapshotStore::load()` și invers, atât timp cât ambele folosesc același director.
