
# Inleiding

merql is een pure PHP-bibliotheek die drieweg-samenvoegingen uitvoert op de status van databases. De bibliotheek maakt snapshots van tabellen, berekent wijzigingensets tussen snapshots, voegt twee sets wijzigingen samen op basis van een gedeelde basis en detecteert conflicten op kolomniveau. Hetzelfde algoritme dat git gebruikt voor bronbestanden, toegepast op rijen en kolommen in plaats van regels.

Geen externe tools. Ondersteunt MySQL en SQLite via verwisselbare verbindingsadapters en dialectstuurprogramma's.

## Snel voorbeeld

Voor een samenvoeging zijn drie statussen van dezelfde gegevens nodig: de basis waar beide kopieën vanuit zijn gestart en de twee kopieën nadat ze onafhankelijk zijn gewijzigd. Hier is een sandbox gekopieerd vanuit de live database en zijn beide sindsdien bewerkt.

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

Elke snapshot wordt gemaakt vanuit de database die de betreffende status bevat. Alle drie achter elkaar vanuit één database maken beschrijft geen twee uiteenlopende kopieën: theirs bevat dan al de wijzigingen van ours, waardoor elke rij die ours heeft toegevoegd als een `insert_insert`-conflict wordt aangemerkt.

Het resultaat vermeldt de bewerkingen van beide kanten die base omzetten in de samengevoegde status, elk voorzien van de herkomst (`ours`, `theirs` of `merged`). Pas voor het overzetten van de sandbox-wijzigingen naar live de bewerkingen toe die live nog niet heeft, met [Beveiligd toepassen](https://merql.inline0.dev/nl/docs/apply/guarded).

Of gebruik de CLI, die verbinding maakt met de database die voor elke `snapshot` is opgegeven in `MERQL_DB_DSN`:

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

## Waarom merql

De meeste databasetools die statussen vergelijken, werken op rijniveau: als een kolom in een rij verschilt tussen twee versies, wordt de hele rij als conflict aangemerkt. Daardoor ontstaan onterechte conflicten wanneer twee mensen verschillende kolommen van dezelfde rij bewerken.

merql voegt samen op kolomniveau. Als de ene kant de `title` heeft gewijzigd en de andere kant de `status`, worden die wijzigingen probleemloos samengevoegd. Alleen als beide kanten dezelfde kolom wijzigen in verschillende waarden, ontstaat er een conflict.

Voor TEXT- en JSON-kolommen kan merql met samenvoeging op celniveau nog een niveau dieper gaan. Twee bewerkingen op verschillende regels van een tekstkolom, of op verschillende sleutels van een JSON-kolom, kunnen probleemloos worden samengevoegd met hetzelfde drieweg-algoritme. Samenvoeging op celniveau is optioneel: geef een `CellMergeConfig` door aan `ThreeWayMerge`. De `Merql`-gevel en de CLI voegen alleen samen op kolomniveau. Zie [Samenvoeging op celniveau](https://merql.inline0.dev/nl/docs/merge/cell-level).

## Het samenvoegingsmodel

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

Drie statussen, net als bij git. Base is de gemeenschappelijke voorouder. Ours en theirs zijn de twee kopieën nadat ze uiteen zijn gaan lopen; elke kopie wordt vastgelegd vanuit de eigen database. De samenvoegregels behandelen beide kanten hetzelfde. De namen verschijnen in de `source` van elke bewerking, in conflicttypen (`update_delete` betekent dat ours is bijgewerkt en theirs is verwijderd) en in het beleid voor het oplossen van `OursWins` en `TheirsWins`. Zonder een gemeenschappelijke basis kun je geen onderscheid maken tussen "toegevoegd" en "ongewijzigd".

Een samenvoeging schrijft zelf niets weg. De bewerkingen ervan zetten base om in de samengevoegde status, dus `Merql::apply()` voert ze allemaal probleemloos uit, maar alleen op een database die nog de basisstatus bevat. Om de wijzigingen van één kant over te zetten naar een database die de andere kant al bevat, bijvoorbeeld sandbox-bewerkingen naar live, pas je alleen de ontbrekende bewerkingen toe; zie [Beveiligd toepassen](https://merql.inline0.dev/nl/docs/apply/guarded).

## Vereisten

- PHP 8.2 of later.
- `ext-mbstring` en `ext-zlib`, vereist door de afhankelijkheid `pitmaster/pitmaster` die de tekstdiff levert.
- Een database-extensie voor de gebruikte adapter: `ext-pdo` met `ext-pdo_sqlite` of `ext-pdo_mysql`, of `ext-mysqli`. De `composer.json` van merql beveelt alleen `ext-pdo` en `ext-mysqli` aan, dus Composer controleert niet of deze zijn geïnstalleerd.
- Een database van het type MySQL of SQLite. Voor andere engines is een aangepast [stuurprogramma](https://merql.inline0.dev/nl/docs/apply/drivers) nodig.

## Wat het niet is

merql is geen schema-migratietool. Het repliceert geen databases en synchroniseert ze niet in realtime. Het lost één specifiek probleem op: gegeven drie databasestatussen een vierde samengevoegde status produceren, met conflicten aangeduid.

## Documentatie

- [Aan de slag](https://merql.inline0.dev/nl/docs/getting-started) -- installatie, eerste snapshot, eerste samenvoeging.
- [CLI-referentie](https://merql.inline0.dev/nl/docs/cli) -- volledige referentie voor de opdracht `vendor/bin/merql`.
- [PHP API-referentie](https://merql.inline0.dev/nl/docs/api) -- volledige API-documentatie voor alle klassen.
- [Samenvoegplannen](https://merql.inline0.dev/nl/docs/merge/plans) -- stabiele bewerkings-ID's, wijzigingsgroepen en selecties.
- [Beveiligd toepassen](https://merql.inline0.dev/nl/docs/apply/guarded) -- geselecteerde schrijfbewerkingen met voorwaarden voor live rijen.
- [Terugdraaien](https://merql.inline0.dev/nl/docs/apply/rollback) -- artefacten voor terugdraaien en afwijkingscontroles.
