
# Referentie voor CLI

merql wordt geleverd met een CLI om rechtstreeks vanaf de terminal snapshots te maken, verschillen te berekenen en samenvoegingen uit te voeren. Composer installeert deze als `vendor/bin/merql`; in een checkout van de merql-repository is deze `bin/merql`.

`vendor/bin/merql` werkt na installatie als dependency, omdat merql 0.4.1. Eerdere releases zochten de Composer-autoloader alleen in de eigen map `vendor/` van het pakket en mislukten wanneer merql als dependency was geïnstalleerd.

## Snel aan de slag

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

Voor een driewegssamenvoeging moeten ours en theirs zijn vastgelegd vanuit twee databases die uiteen zijn gegaan vanaf de basis. Richt `MERQL_DB_DSN` voor elke snapshot op de juiste database:

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

Achtereenvolgens alle drie de snapshots maken van dezelfde database werkt niet als samenvoeging: theirs zou de wijzigingen van ours al bevatten, waardoor elke rij die ours heeft ingevoegd als een `insert_insert`-conflict zou worden gemeld.

## Omgevingsvariabelen

CLI leest verbindingsgegevens voor de database uit omgevingsvariabelen. U kunt verbinding maken met een PDO DSN-string of met afzonderlijke MySQL-parameters.

### Verbinding op basis van een DSN

Gebruik `MERQL_DB_DSN` voor verbindingen op basis van PDO. Dit is de aanbevolen aanpak voor SQLite en voor niet-standaardconfiguraties. De DSN moet verwijzen naar een MySQL- of SQLite-database: de CLI kan geen driver voor andere database-engines registreren.

| Variabele | Beschrijving | Voorbeeld |
|---|---|---|
| `MERQL_DB_DSN` | Volledige PDO DSN-string | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Gebruikersnaam (optioneel bij DSN) | `root` |
| `MERQL_DB_PASS` | Wachtwoord (optioneel bij 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"
```

Gebruik een SQLite-database die is opgeslagen in een bestand. Elke opdracht van CLI wordt in een eigen proces uitgevoerd, dus `sqlite::memory:` opent altijd een nieuwe, lege database en een snapshot daarvan bevat geen tabellen.

### Verkorte notatie voor MySQL

Als `MERQL_DB_DSN` niet is ingesteld, valt CLI terug op variabelen die specifiek zijn voor MySQL.

| Variabele | Standaardwaarde | Beschrijving |
|---|---|---|
| `MERQL_DB_NAME` | (vereist) | Databasenaam |
| `MERQL_DB_HOST` | `127.0.0.1` | Host van MySQL |
| `MERQL_DB_PORT` | `3306` | Poort van MySQL |
| `MERQL_DB_USER` | `root` | Gebruikersnaam van MySQL |
| `MERQL_DB_PASS` | (leeg) | Wachtwoord van MySQL |
| `MERQL_DB_ADAPTER` | `pdo` | Stel in op `mysqli` om de mysqli-adapter te gebruiken |

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

## Opdrachten

### `merql snapshot <name>`

Leg de huidige status vast van de database die door de omgevingsvariabelen wordt aangegeven en sla deze op als een snapshot met een naam. Dit is de enige opdracht die verbinding maakt met een database.

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

Uitvoer:

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

Snapshots worden opgeslagen als JSON-bestanden in `.merql/snapshots/` onder de werkmap (zie [Snapshotopslag](#snapshot-storage)). De naam mag alleen alfanumerieke tekens, streepjes en underscores bevatten.

Typische werkwijze: maak een snapshot voordat u wijzigingen aanbrengt en daarna nog een. De twee snapshots vormen de basis voor een vergelijking of samenvoeging.

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

Vergelijk twee snapshots met een naam en geef een samenvatting van de verschillen weer.

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

Uitvoer:

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

Beide snapshots moeten al bestaan (eerder vastgelegd met `merql snapshot`). Voor de vergelijking is geen databaseverbinding nodig, omdat deze met opgeslagen snapshotbestanden werkt.

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

Voer een driewegssamenvoeging uit van drie snapshots met een naam.

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

Uitvoer:

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

Alle drie de snapshots moeten al bestaan. Voor de samenvoeging is geen databaseverbinding nodig, omdat deze met opgeslagen snapshotbestanden werkt. De samenvoeging schrijft nooit naar een database: de CLI heeft geen apply-opdracht. Gebruik PHP API om een samenvoegingsresultaat toe te passen.

De CLI voegt samen op kolomniveau. Hij voert geen samenvoeging op celniveau uit voor TEXT- of JSON-kolommen, dus twee verschillende bewerkingen aan dezelfde kolom zijn hier altijd een conflict ([#7](https://github.com/inline0/merql/issues/7)). Gebruik `ThreeWayMerge` met een `CellMergeConfig` in PHP voor samenvoeging op celniveau.

#### `--dry-run`

Voeg de vlag `--dry-run` toe om een voorbeeld te bekijken van de SQL-instructies die de samenvoeging zou genereren, zonder iets uit te voeren. De instructies beschrijven hoe de basisstatus wordt omgezet in het samengevoegde resultaat en bevatten daarom de wijzigingen van beide kanten.

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

Uitvoer:

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

## Ontwikkelopdrachten

Een checkout van de merql-repository bevat meer scripts in `bin/` voor de oracle-gestuurde testsuite. Deze maken geen deel uit van het Composer-pakket, dus na het installeren van afhankelijkheden is alleen `vendor/bin/merql` beschikbaar. Voer ze uit vanuit de hoofdmap van de repository nadat je `composer install` hebt uitgevoerd.

| Opdracht | Beschrijving |
|---|---|
| `./bin/oracle <name>` | Verwacht samenvoegingsresultaat voor een scenario berekenen |
| `./bin/actual <name>` | merql op een scenario uitvoeren en de uitvoer vastleggen |
| `./bin/compare <name>` | Oracle-uitvoer vergelijken met de werkelijke uitvoer |
| `./bin/test-scenario <name>` | Volledige pijplijn: instellen, oracle, werkelijk resultaat, vergelijken |
| `./bin/test-regression` | Alle scenario's uitvoeren |
| `./bin/test-regression --category clean` | Eén categorie uitvoeren: `clean`, `conflict`, `identity`, `types`, `scale` of `edge` |
| `./bin/test-regression --fast` | Alleen geslaagd/mislukt, geen rapporten |
| `./bin/verify-compliance` | Volledig nalevingsrapport |
| `./bin/verify-all` | PHPStan + codestijl + PHPUnit + oracle-regressietests |

`bin/test-regression` accepteert ook `--jobs`, maar negeert de waarde momenteel en voert scenario's een voor een uit ([#5](https://github.com/inline0/merql/issues/5)). Bij een onbekende `--category` wordt `No scenarios found` weergegeven en eindigt het programma succesvol.

Zie [Teststrategie](https://merql.inline0.dev/nl/docs/advanced/testing) voor de indeling van de scenario's.

## Afsluitstatus

`merql snapshot`, `diff` en `merge` eindigen met status 1 als een argument ontbreekt, en `snapshot` ook als er geen verbinding is ingesteld. Bij een ontbrekende snapshot eindigt de opdracht met een niet-afgevangen `SnapshotException` en een niet-nulstatus. Bij een onbekende opdracht wordt `Unknown command` weergegeven, maar het programma eindigt momenteel met status 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Snapshotopslag

Snapshots worden opgeslagen in `.merql/snapshots/` ten opzichte van de werkmap. Elke snapshot is één JSON-bestand met de naam `<name>.json`. Voer elke opdracht uit vanuit dezelfde map, zodat de opdrachten elkaars snapshots kunnen vinden.

De CLI heeft geen optie of omgevingsvariabele voor een andere locatie ([#8](https://github.com/inline0/merql/issues/8)). Om een andere locatie te gebruiken, ga je naar een andere werkmap voordat je de opdracht uitvoert. Stel in PHP de map in voordat je snapshots vastlegt of laadt:

```php
use Merql\Snapshot\SnapshotStore;

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

Snapshotbestanden zijn overdraagbaar. Je kunt ze tussen machines kopiëren, aan versiebeheer toevoegen of delen om samen problemen op te sporen. Een snapshot die door de CLI is vastgelegd, kan in PHP worden geladen met `SnapshotStore::load()`, en omgekeerd, zolang beide dezelfde map gebruiken.
