
# Справочник за CLI

merql включва CLI за създаване на моментни снимки, изчисляване на разлики и извършване на сливания директно от терминала. Composer го инсталира като `vendor/bin/merql`; в копие на хранилището на merql това е `bin/merql`.

`vendor/bin/merql` работи и при инсталиране като зависимост, тъй като merql 0.4.1. По-ранните версии търсеха автоматично зареждащия файл Composer само в собствената директория `vendor/` на пакета и се проваляха, когато merql беше инсталиран като зависимост.

## Бърз старт

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

Тристранното сливане изисква нашата и тяхната моментна снимка да са създадени от две бази данни, които са се разклонили от базовата. Насочете `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
```

Създаването на трите моментни снимки от една и съща база данни, една след друга, не работи за сливане: тяхната версия вече съдържа промените на нашата и всеки ред, вмъкнат от нашата страна, ще бъде отчетен като конфликт `insert_insert`.

## Променливи на средата

CLI чете подробностите за връзката към базата данни от променливите на средата. Можете да се свържете чрез PDO DSN низ или чрез отделни параметри MySQL.

### Връзка чрез DSN

Използвайте `MERQL_DB_DSN` за връзки, поддържани от PDO. Това е препоръчителният подход за SQLite и нестандартни конфигурации. DSN трябва да сочи към база данни MySQL или SQLite: CLI не може да регистрира драйвер за други машини за бази данни.

| Променлива | Описание | Пример |
|---|---|---|
| `MERQL_DB_DSN` | Пълен PDO DSN низ | `sqlite:/path/to/db.sqlite` |
| `MERQL_DB_USER` | Потребителско име (незадължително с DSN) | `root` |
| `MERQL_DB_PASS` | Парола (незадължителна с 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"
```

Използвайте база данни SQLite, съхранявана във файл. Всяка команда CLI се изпълнява в отделен процес, затова `sqlite::memory:` винаги отваря нова, празна база данни и нейната моментна снимка не съдържа таблици.

### Съкратен запис за MySQL

Когато не е зададена `MERQL_DB_DSN`, CLI използва резервните променливи, специфични за MySQL.

| Променлива | По подразбиране | Описание |
|---|---|---|
| `MERQL_DB_NAME` | (задължително) | Име на базата данни |
| `MERQL_DB_HOST` | `127.0.0.1` | Хост на MySQL |
| `MERQL_DB_PORT` | `3306` | Порт на MySQL |
| `MERQL_DB_USER` | `root` | Потребителско име за MySQL |
| `MERQL_DB_PASS` | (празно) | Парола за MySQL |
| `MERQL_DB_ADAPTER` | `pdo` | Задайте `mysqli`, за да използвате адаптера 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"
```

## Команди

### `merql snapshot <name>`

Запишете текущото състояние на базата данни, чието име е зададено в променливите на средата, като наименувана моментна снимка. Това е единствената команда, която се свързва с база данни.

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

Изход:

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

Моментните снимки се съхраняват като файлове JSON в `.merql/snapshots/` под работната директория (вижте [Съхранение на моментни снимки](#snapshot-storage)). Името може да съдържа само букви, цифри, тирета и долни черти.

Типичен работен процес: създайте моментна снимка преди промените и след това създайте още една. Двете моментни снимки са основата за сравнение или сливане.

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

Сравнете две наименувани моментни снимки и покажете обобщение на разликите.

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

Изход:

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

И двете моментни снимки трябва вече да съществуват (създадени по-рано с `merql snapshot`). Сравнението не изисква връзка с база данни, тъй като работи със запазени файлове с моментни снимки.

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

Извършете тристранно сливане на три наименувани моментни снимки.

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

Изход:

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

И трите моментни снимки трябва вече да съществуват. Сливането не изисква връзка с база данни, тъй като работи със запазени файлове с моментни снимки, и никога не записва в база данни: CLI няма команда за прилагане. Използвайте PHP API, за да приложите резултат от сливане.

CLI извършва сливане на ниво колона. Не слива на ниво клетка колони от тип TEXT или JSON, затова две различни промени в една и съща колона винаги са конфликт (тук: [#7](https://github.com/inline0/merql/issues/7)). Използвайте `ThreeWayMerge` с `CellMergeConfig` в PHP за сливане на ниво клетка.

#### `--dry-run`

Добавете флага `--dry-run`, за да прегледате инструкциите SQL, които сливането би генерирало, без да изпълнявате нищо. Инструкциите описват как базовото състояние да се превърне в слетия резултат и затова включват промените и от двете страни.

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

Изход:

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

## Команди за разработка

Копието на хранилището на merql съдържа още скриптове в `bin/` за тестовия набор, управляван от оракул. Те не са част от пакета Composer, затова при инсталиране като зависимост разполагате само с `vendor/bin/merql`. Изпълнявайте ги от основната директория на хранилището след `composer install`.

| Команда | Описание |
|---|---|
| `./bin/oracle <name>` | Изчислява очаквания резултат от сливането за даден сценарий |
| `./bin/actual <name>` | Изпълнява merql за даден сценарий и записва изхода |
| `./bin/compare <name>` | Сравнява изхода от оракула с действителния изход |
| `./bin/test-scenario <name>` | Пълен процес: настройка, оракул, действителен резултат, сравнение |
| `./bin/test-regression` | Изпълнява всички сценарии |
| `./bin/test-regression --category clean` | Изпълнява една категория: `clean`, `conflict`, `identity`, `types`, `scale` или `edge` |
| `./bin/test-regression --fast` | Само успех/неуспех, без отчети |
| `./bin/verify-compliance` | Пълен отчет за съответствие |
| `./bin/verify-all` | PHPStan + стил на кода + PHPUnit + регресия на оракула |

`bin/test-regression` приема и `--jobs`, но в момента игнорира стойността и изпълнява сценариите един след друг ([#5](https://github.com/inline0/merql/issues/5)). Непозната `--category` показва `No scenarios found` и завършва успешно.

Вижте [Стратегия за тестване](https://merql.inline0.dev/bg/docs/advanced/testing) за структурата на сценариите.

## Изходен статус

`merql snapshot`, `diff` и `merge` завършват със статус 1, когато липсва аргумент; `snapshot` също го прави, когато няма конфигурирана връзка. При липсваща моментна снимка командата се прекратява с необработено изключение `SnapshotException` и ненулев статус. Непозната команда показва `Unknown command`, но в момента завършва със статус 0 ([#3](https://github.com/inline0/merql/issues/3)).

## Съхранение на моментни снимки

Моментните снимки се съхраняват в `.merql/snapshots/` спрямо работната директория. Всяка моментна снимка е един файл JSON с име `<name>.json`. Изпълнявайте всички команди от една и съща директория, за да могат да намират моментните снимки една на друга.

CLI няма опция или променлива на средата за друга директория ([#8](https://github.com/inline0/merql/issues/8)). За да използвате друга директория, преминете към нея, преди да стартирате командата. В PHP задайте директорията преди създаването или зареждането на моментни снимки:

```php
use Merql\Snapshot\SnapshotStore;

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

Файловете с моментни снимки са преносими. Можете да ги копирате между машини, да ги добавите към система за контрол на версиите или да ги споделите за съвместно отстраняване на грешки. Моментна снимка, създадена от CLI, може да бъде заредена в PHP с `SnapshotStore::load()`, както и обратното, стига и двете да използват една и съща директория.
