
# Довідник 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
```

Для тристороннього злиття потрібно створити знімки ours і theirs із двох баз даних, що розійшлися з base. Для кожного знімка вкажіть `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
```

Створення всіх трьох знімків поспіль з однієї бази даних не дасть змоги виконати злиття: theirs уже міститиме зміни ours, тому кожен вставлений ours рядок буде позначено як конфлікт `insert_insert`.

## Змінні середовища

CLI зчитує дані для підключення до бази даних зі змінних середовища. Підключитися можна за допомогою рядка PDO DSN або окремих параметрів MySQL.

### Підключення на основі DSN

Для підключень на основі PDO використовуйте `MERQL_DB_DSN`. Цей рекомендований спосіб підходить для 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/uk/docs/advanced/testing).

## Код завершення

`merql snapshot`, `diff` і `merge` завершуються зі статусом 1, якщо бракує аргументу; `snapshot` також завершується зі статусом 1, якщо не налаштовано підключення. Якщо знімка немає, команда завершується через необроблений виняток `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()`, і навпаки, якщо обидва використовують той самий каталог.
