
# Wprowadzenie

merql to czysta biblioteka PHP do przeprowadzania trójstronnych scaleń stanu bazy danych. Tworzy migawki tabel, oblicza zestawy zmian między migawkami, scala dwa zestawy zmian względem wspólnego stanu bazowego i wykrywa konflikty na poziomie kolumn. Ten sam algorytm, którego git używa do plików źródłowych, zastosowany do wierszy i kolumn zamiast linii.

Bez zewnętrznych narzędzi. Obsługuje MySQL i SQLite przez wymienne adaptery połączeń i sterowniki dialektów.

## Szybki przykład

Scalenie wymaga trzech stanów tych samych danych: wspólnego stanu bazowego, od którego rozpoczęły obie kopie, oraz dwóch kopii po niezależnym wprowadzeniu zmian. W tym przykładzie piaskownicę skopiowano z działającej bazy danych, a od tego czasu zmiany wprowadzono w obu.

```php
use Merql\Connection;
use Merql\Merql;

$live    = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');

// Base: live at the moment the sandbox was copied from it.
Merql::init($live);
Merql::snapshot('base');

// ... copy live.sqlite to sandbox.sqlite, then both databases change ...

// Ours: the sandbox with our edits. Theirs: live with its own changes.
Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');

$result = Merql::merge('base', 'ours', 'theirs');

if ($result->isClean()) {
    foreach ($result->operations() as $operation) {
        echo "{$operation->type} {$operation->table} #{$operation->rowKey} ({$operation->source})\n";
    }
} else {
    echo "Conflicts: {$result->conflictCount()}\n";
}
```

Każda migawka pochodzi z bazy danych, która zawiera dany stan. Utworzenie wszystkich trzech kolejno z jednej bazy danych nie opisuje dwóch rozbieżnych kopii: theirs zawierałaby już zmiany ours, a każdy wiersz wstawiony przez ours zostałby zgłoszony jako konflikt `insert_insert`.

Wynik zawiera operacje, które przekształcają stan base w stan scalony, pochodzące od obu stron i oznaczone źródłem (`ours`, `theirs` lub `merged`). Aby zapisać zmiany z piaskownicy w działającej bazie, zastosuj operacje, których brakuje w tej bazie, za pomocą [Zabezpieczone zastosowanie](https://merql.inline0.dev/pl/docs/apply/guarded).

Lub z poziomu CLI, które łączy się z bazą danych wskazaną w `MERQL_DB_DSN` dla każdego `snapshot`:

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

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

## Dlaczego merql

Większość narzędzi bazodanowych porównujących stan działa na poziomie wierszy: jeśli jakakolwiek kolumna w wierszu różni się między dwiema wersjami, cały wiersz jest oznaczany jako konflikt. Powoduje to fałszywe konflikty, gdy dwie osoby edytują różne kolumny tego samego wiersza.

merql scala na poziomie kolumn. Jeśli jedna strona zmieniła `title`, a druga `status`, zmiany zostaną poprawnie scalone bez konfliktu. Konflikt występuje tylko wtedy, gdy obie strony zmienią tę samą kolumnę na różne wartości.

W przypadku kolumn TEXT i JSON merql może zejść poziom niżej i scalać na poziomie komórek. Dwie zmiany różnych wierszy w kolumnie tekstowej lub różnych kluczy kolumny JSON można poprawnie scalić za pomocą tego samego algorytmu trójstronnego. Scalenie na poziomie komórek jest opcjonalne: przekaż `CellMergeConfig` do `ThreeWayMerge`. Fasada `Merql` i CLI scalają tylko na poziomie kolumn. Zobacz [Scalanie na poziomie komórek](https://merql.inline0.dev/pl/docs/merge/cell-level).

## Model scalania

```
         Base (snapshot at fork time)
        /                              \
   Ours (one copy's changes)            Theirs (the other copy's changes)
        \                              /
         --------- MERGE ----------
                     |
              Merged result
              + conflicts (if any)
```

Trzy stany, tak jak w git. Base to wspólny przodek. Ours i theirs to dwie kopie po ich rozdzieleniu, każda utworzona na podstawie własnej bazy danych. Reguły scalania traktują obie strony jednakowo. Nazwy pojawiają się w polu `source` każdej operacji, w typach konfliktów (`update_delete` oznacza, że ours zaktualizowało, a theirs usunęło) oraz w politykach rozstrzygania `OursWins` i `TheirsWins`. Bez wspólnego stanu bazowego nie można odróżnić elementu „dodano” od „bez zmian”.

Scalenie samo niczego nie zapisuje. Jego operacje przekształcają stan base w stan scalony, więc `Merql::apply()` wykonuje je wszystkie poprawnie tylko w bazie danych, która wciąż zawiera stan base. Aby przenieść zmiany jednej strony do bazy zawierającej już zmiany drugiej, na przykład zmiany z piaskownicy do działającej bazy, zastosuj tylko brakujące w niej operacje; zobacz [Zabezpieczone zastosowanie](https://merql.inline0.dev/pl/docs/apply/guarded).

## Wymagania

- PHP 8.2 lub nowszy.
- `ext-mbstring` i `ext-zlib`, wymagane przez zależność `pitmaster/pitmaster` zapewniającą różnicę tekstową.
- Rozszerzenie bazy danych dla używanego adaptera: `ext-pdo` z `ext-pdo_sqlite` lub `ext-pdo_mysql` albo `ext-mysqli`. `composer.json` merql jedynie sugeruje `ext-pdo` i `ext-mysqli`, dlatego Composer ich nie sprawdza.
- Baza danych MySQL lub SQLite. Inne silniki wymagają niestandardowego [sterownika](https://merql.inline0.dev/pl/docs/apply/drivers).

## Czym nie jest

merql nie jest narzędziem do migracji schematów. Nie replikuje baz danych ani nie synchronizuje ich w czasie rzeczywistym. Rozwiązuje jeden konkretny problem: na podstawie trzech stanów bazy danych tworzy czwarty, scalony stan z oznaczonymi konfliktami.

## Dokumentacja

- [Pierwsze kroki](https://merql.inline0.dev/pl/docs/getting-started) -- instalacja, pierwszy zrzut, pierwsze scalanie.
- [CLI Dokumentacja referencyjna](https://merql.inline0.dev/pl/docs/cli) -- pełna dokumentacja polecenia `vendor/bin/merql`.
- [PHP API Dokumentacja referencyjna](https://merql.inline0.dev/pl/docs/api) -- kompletna dokumentacja API wszystkich klas.
- [Plany scalania](https://merql.inline0.dev/pl/docs/merge/plans) -- stabilne identyfikatory operacji, grupy zmian i wybory.
- [Zabezpieczone zastosowanie](https://merql.inline0.dev/pl/docs/apply/guarded) -- wybrane zapisy z warunkami wstępnymi dla bieżących wierszy.
- [Wycofywanie](https://merql.inline0.dev/pl/docs/apply/rollback) -- artefakty wycofania i kontrole rozbieżności.
