
# Riferimento CLI

merql include una CLI per acquisire snapshot, calcolare differenze ed eseguire fusioni direttamente dal terminale. Composer la installa come `vendor/bin/merql`; in una copia del repository merql si trova in `bin/merql`.

`vendor/bin/merql` funziona anche quando viene installato come dipendenza, poiché merql 0.4.1. Le versioni precedenti cercavano l'autoloader Composer solo nella directory `vendor/` del pacchetto e non funzionavano quando merql era installato come dipendenza.

## Avvio rapido

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

Una fusione a tre vie richiede che ours e theirs siano acquisiti da due database divergenti rispetto a base. Indicate a `MERQL_DB_DSN` il database corretto per ogni snapshot:

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

Acquisire tutti e tre gli snapshot dallo stesso database, uno dopo l'altro, non funziona come fusione: theirs includerebbe già le modifiche di ours, quindi ogni riga inserita da ours verrebbe segnalata come conflitto `insert_insert`.

## Variabili d'ambiente

CLI legge i dettagli di connessione al database dalle variabili di ambiente. Potete connettervi usando una stringa DSN PDO oppure parametri MySQL individuali.

### Connessione basata su DSN

Usate `MERQL_DB_DSN` per le connessioni basate su PDO. È l'approccio consigliato per SQLite e per le configurazioni non standard. Il DSN deve puntare a un database MySQL o SQLite: CLI non può registrare driver per altri motori.

| Variabile | Descrizione | Esempio |
|---|---|---|
| `MERQL_DB_DSN` | Stringa DSN PDO completa | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Nome utente (facoltativo con DSN) | `root` |
| `MERQL_DB_PASS` | Password (facoltativa con 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"
```

Usate un database SQLite basato su file. Ogni comando CLI viene eseguito in un processo separato, quindi `sqlite::memory:` apre sempre un nuovo database vuoto e il relativo snapshot non contiene tabelle.

### Forma abbreviata di MySQL

Se `MERQL_DB_DSN` non è impostata, CLI usa come fallback le variabili specifiche di MySQL.

| Variabile | Predefinito | Descrizione |
|---|---|---|
| `MERQL_DB_NAME` | (obbligatorio) | Nome del database |
| `MERQL_DB_HOST` | `127.0.0.1` | Host MySQL |
| `MERQL_DB_PORT` | `3306` | Porta MySQL |
| `MERQL_DB_USER` | `root` | Nome utente MySQL |
| `MERQL_DB_PASS` | (vuota) | Password MySQL |
| `MERQL_DB_ADAPTER` | `pdo` | Impostate su `mysqli` per usare l'adapter 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"
```

## Comandi

### `merql snapshot <name>`

Acquisite lo stato attuale del database indicato dalle variabili di ambiente e salvatelo come snapshot con nome. È l'unico comando che si connette a un database.

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

Output:

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

Gli snapshot vengono salvati come file JSON in `.merql/snapshots/` nella directory di lavoro (vedere [Archiviazione degli snapshot](#snapshot-storage)). Il nome può contenere solo caratteri alfanumerici, trattini e trattini bassi.

Flusso di lavoro tipico: acquisite uno snapshot prima di apportare modifiche e un altro dopo. I due snapshot costituiscono la base per un confronto o una fusione.

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

Confrontate due snapshot con nome e visualizzate un riepilogo delle differenze.

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

Output:

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

Entrambi gli snapshot devono già esistere (acquisiti in precedenza con `merql snapshot`). Il confronto non richiede una connessione al database, perché opera sui file di snapshot salvati.

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

Eseguite una fusione a tre vie di tre snapshot con nome.

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

Output:

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

Tutti e tre gli snapshot devono già esistere. La fusione non richiede una connessione al database, perché opera sui file di snapshot salvati, e non scrive mai in un database: la CLI non dispone di un comando apply. Usate PHP API per applicare il risultato della fusione.

CLI esegue fusioni a livello di colonna. Non applica fusioni a livello di cella alle colonne TEXT o JSON, quindi in questo caso due modifiche diverse alla stessa colonna sono sempre un conflitto ([#7](https://github.com/inline0/merql/issues/7)). Per le fusioni a livello di cella, usate `ThreeWayMerge` con un `CellMergeConfig` in PHP.

#### `--dry-run`

Aggiungete il flag `--dry-run` per visualizzare in anteprima le istruzioni SQL che la fusione genererebbe, senza eseguire nulla. Le istruzioni descrivono come trasformare lo stato base nel risultato della fusione, quindi includono le modifiche di entrambi i lati.

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

Output:

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

## Comandi di sviluppo

Una copia del repository merql include altri script in `bin/` per la suite di test guidata dall'oracolo. Non fanno parte del pacchetto Composer, quindi un'installazione come dipendenza include solo `vendor/bin/merql`. Eseguiteli dalla radice del repository dopo `composer install`.

| Comando | Descrizione |
|---|---|
| `./bin/oracle <name>` | Calcola il risultato di fusione atteso per uno scenario |
| `./bin/actual <name>` | Esegue merql su uno scenario e acquisisce l'output |
| `./bin/compare <name>` | Confronta l'output effettivo con quello dell'oracolo |
| `./bin/test-scenario <name>` | Flusso completo: configurazione, oracolo, risultati effettivi, confronto |
| `./bin/test-regression` | Esegue tutti gli scenari |
| `./bin/test-regression --category clean` | Esegue una categoria: `clean`, `conflict`, `identity`, `types`, `scale` o `edge` |
| `./bin/test-regression --fast` | Solo esito positivo o negativo, senza rapporti |
| `./bin/verify-compliance` | Rapporto completo sulla conformità |
| `./bin/verify-all` | PHPStan + stile del codice + PHPUnit + regressione dell'oracolo |

`bin/test-regression` accetta anche `--jobs`, ma al momento ignora il valore ed esegue gli scenari uno dopo l'altro ([#5](https://github.com/inline0/merql/issues/5)). Un `--category` sconosciuto stampa `No scenarios found` e termina correttamente.

Per la struttura degli scenari, consultate [Strategia di test](https://merql.inline0.dev/it/docs/advanced/testing).

## Codici di uscita

`merql snapshot`, `diff` e `merge` terminano con codice 1 se manca un argomento; anche `snapshot` lo fa se non è configurata alcuna connessione. Se manca uno snapshot, il comando termina con un'`SnapshotException` non gestita e un codice diverso da zero. Un comando sconosciuto stampa `Unknown command`, ma al momento termina con codice 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Archiviazione degli snapshot

Gli snapshot vengono archiviati in `.merql/snapshots/` rispetto alla directory di lavoro. Ogni snapshot è un singolo file JSON denominato `<name>.json`. Eseguite tutti i comandi dalla stessa directory affinché trovino gli snapshot creati dagli altri comandi.

La CLI non offre opzioni né variabili di ambiente per usare un'altra posizione ([#8](https://github.com/inline0/merql/issues/8)). Per usarne una, spostatevi in un'altra directory di lavoro prima di avviarla. In PHP, impostate la directory prima di acquisire o caricare gli snapshot:

```php
use Merql\Snapshot\SnapshotStore;

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

I file snapshot sono portabili. Potete copiarli tra macchine, aggiungerli al controllo versione o condividerli per il debugging collaborativo. Uno snapshot acquisito da CLI può essere caricato in PHP con `SnapshotStore::load()`, e viceversa, purché entrambi usino la stessa directory.
