
# CLI Reference

merql leveres med en CLI til at oprette øjebliksbilleder, beregne diff og udføre fletninger direkte fra terminalen. Composer installerer den som `vendor/bin/merql`; i et checkout af merql-arkivet er den `bin/merql`.

`vendor/bin/merql` fungerer ved installation som afhængighed, fordi merql 0.4.1. Tidligere versioner søgte kun efter Composer-autoloaderen i pakkens egen `vendor/`-mappe og fejlede, når merql var installeret som afhængighed.

## Hurtig start

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

En trevejsfletning kræver, at ours og theirs hentes fra to databaser, der er divergeret fra base. Ret `MERQL_DB_DSN` mod den rette database for hvert øjebliksbillede:

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

Det fungerer ikke som en fletning at tage alle tre øjebliksbilleder fra den samme database efter hinanden: theirs ville allerede indeholde ændringerne fra ours, så hver række, som ours indsatte, ville blive rapporteret som en `insert_insert`-konflikt.

## Miljøvariabler

CLI henter oplysninger om databaseforbindelsen fra miljøvariabler. Du kan
oprette forbindelse enten med en PDO-DSN-streng eller individuelle MySQL-parametre.

### DSN-baseret forbindelse

Brug `MERQL_DB_DSN` til PDO-baserede forbindelser. Dette er den anbefalede tilgang
for SQLite og for konfigurationer, der ikke er standard. DSN'en skal pege på en MySQL-
eller SQLite-database: CLI kan ikke registrere en driver til andre databasemotorer.

| Variabel | Beskrivelse | Eksempel |
|---|---|---|
| `MERQL_DB_DSN` | Fuld PDO-DSN-streng | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Brugernavn (valgfrit med DSN) | `root` |
| `MERQL_DB_PASS` | Adgangskode (valgfrit med 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"
```

Brug en filbaseret SQLite-database. Hver CLI-kommando kører i sin egen proces, så
`sqlite::memory:` åbner altid en ny, tom database, og et øjebliksbillede af den
indeholder ingen tabeller.

### MySQL-genvej

Når `MERQL_DB_DSN` ikke er angivet, falder CLI tilbage på variabler, der er specifikke for MySQL.

| Variabel | Standard | Beskrivelse |
|---|---|---|
| `MERQL_DB_NAME` | (påkrævet) | Databasenavn |
| `MERQL_DB_HOST` | `127.0.0.1` | MySQL-vært |
| `MERQL_DB_PORT` | `3306` | MySQL-port |
| `MERQL_DB_USER` | `root` | MySQL-brugernavn |
| `MERQL_DB_PASS` | (tom) | MySQL-adgangskode |
| `MERQL_DB_ADAPTER` | `pdo` | Sæt til `mysqli` for at bruge mysqli-adapteren |

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

## Kommandoer

### `merql snapshot <name>`

Hent den aktuelle tilstand for databasen, der angives af miljøvariablerne, og gem den som et navngivet øjebliksbillede. Dette er den eneste kommando, der opretter forbindelse til en database.

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

Output:

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

Øjebliksbilleder gemmes som JSON-filer i `.merql/snapshots/` under arbejdsbiblioteket (se [Lagring af øjebliksbilleder](#snapshot-storage)). Navnet må kun indeholde alfanumeriske tegn, bindestreger og understregningstegn.

Typisk arbejdsgang: Opret et øjebliksbillede før ændringerne og derefter et nyt efter. De to øjebliksbilleder danner grundlag for en diff eller fletning.

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

Sammenlign to navngivne øjebliksbilleder, og vis en oversigt over forskellene.

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

Output:

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

Begge øjebliksbilleder skal allerede findes (tidligere oprettet med `merql snapshot`). Diff kræver ikke en databaseforbindelse, da den arbejder på gemte øjebliksbilledfiler.

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

Udfør en trevejsfletning af tre navngivne øjebliksbilleder.

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

Output:

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

Alle tre øjebliksbilleder skal allerede findes. Fletningen kræver ikke en databaseforbindelse, da den arbejder på gemte øjebliksbilledfiler, og den skriver aldrig til en database: CLI har ingen anvendelseskommando. Brug PHP API til at anvende et fletningsresultat.

CLI fletter på kolonneniveau. Den udfører ikke fletning på celleniveau for TEXT- eller JSON-kolonner, så to forskellige ændringer af samme kolonne altid er en konflikt her ([#7](https://github.com/inline0/merql/issues/7)). Brug `ThreeWayMerge` med en `CellMergeConfig` i PHP til fletning på celleniveau.

#### `--dry-run`

Tilføj flaget `--dry-run` for at få vist de SQL-sætninger, som fletningen ville generere, uden at udføre noget. Sætningerne beskriver, hvordan grundtilstanden ændres til det flettede resultat, så de omfatter ændringerne fra begge sider.

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

## Udviklingskommandoer

Et checkout af merql-arkivet indeholder flere scripts i `bin/` til dets oracle-drevne testsuite. De er ikke en del af Composer-pakken, så en installation som afhængighed kun har `vendor/bin/merql`. Kør dem fra arkivets rodmappe efter `composer install`.

| Kommando | Beskrivelse |
|---|---|
| `./bin/oracle <name>` | Beregn det forventede fletningsresultat for et scenarie |
| `./bin/actual <name>` | Kør merql på et scenarie, og registrer outputtet |
| `./bin/compare <name>` | Sammenlign oracle-output med det faktiske output |
| `./bin/test-scenario <name>` | Komplet arbejdsgang: opsætning, oracle, faktisk resultat, sammenligning |
| `./bin/test-regression` | Kør alle scenarier |
| `./bin/test-regression --category clean` | Kør én kategori: `clean`, `conflict`, `identity`, `types`, `scale` eller `edge` |
| `./bin/test-regression --fast` | Kun bestået/ikke bestået, ingen rapporter |
| `./bin/verify-compliance` | Komplet overensstemmelsesrapport |
| `./bin/verify-all` | PHPStan + kodestil + PHPUnit + oracle-regression |

`bin/test-regression` accepterer også `--jobs`, men ignorerer i øjeblikket værdien og kører scenarierne efter hinanden ([#5](https://github.com/inline0/merql/issues/5)). En ukendt `--category` udskriver `No scenarios found` og afsluttes uden fejl.

Se [Teststrategi](https://merql.inline0.dev/da/docs/advanced/testing) for scenariernes struktur.

## Afslutningsstatus

`merql snapshot`, `diff` og `merge` afsluttes med status 1, hvis et argument mangler, og `snapshot` gør det også, hvis der ikke er konfigureret nogen forbindelse. Hvis et øjebliksbillede mangler, afsluttes kommandoen med en ufanget `SnapshotException` og en status, der ikke er nul. En ukendt kommando udskriver `Unknown command`, men afsluttes i øjeblikket med status 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Lagring af øjebliksbilleder

Øjebliksbilleder gemmes i `.merql/snapshots/` i forhold til arbejdsbiblioteket. Hvert øjebliksbillede er en enkelt JSON-fil med navnet `<name>.json`. Kør alle kommandoer fra samme mappe, så de kan finde hinandens øjebliksbilleder.

CLI har ingen indstilling eller miljøvariabel til en anden placering ([#8](https://github.com/inline0/merql/issues/8)). Hvis du vil bruge en anden placering, skal du skifte til et andet arbejdsbibliotek, før du kører den. I PHP skal du angive biblioteket, før du opretter eller indlæser øjebliksbilleder:

```php
use Merql\Snapshot\SnapshotStore;

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

Øjebliksbilledfiler er flytbare. Du kan kopiere dem mellem maskiner, indsende dem til versionsstyring eller dele dem til fælles fejlfinding. Et øjebliksbillede oprettet af CLI kan indlæses i PHP med `SnapshotStore::load()` og omvendt, så længe begge bruger samme mappe.
