
# Ievads

merql ir tīra PHP bibliotēka trīspusējai datubāzes stāvokļa apvienošanai. Tā izveido tabulu momentuzņēmumus, aprēķina izmaiņu kopas starp tiem, apvieno divas izmaiņu kopas, salīdzinot ar kopīgu bāzi, un nosaka konfliktus kolonnu līmenī. Tas pats algoritms, ko git izmanto avota failiem, tikai rindu un kolonnu, nevis rindu tekstā apvienošanai.

Bez ārējiem rīkiem. Atbalsta MySQL un SQLite, izmantojot pieslēdzamus savienojuma adapterus un dialektu draiverus.

## Īss piemērs

Apvienošanai nepieciešami trīs viena un tā paša datu kopuma stāvokļi: bāze, no kuras sāka abas kopijas, un abas kopijas pēc neatkarīgām izmaiņām. Šeit smilškaste tika izveidota, kopējot reāllaika datubāzi, un kopš tā laika ir rediģētas abas.

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

Katrs momentuzņēmums tiek iegūts no datubāzes ar atbilstošo stāvokli. Visu trīs secīga iegūšana no vienas datubāzes neattēlo divas atšķīrušās kopijas: theirs jau ietvertu ours izmaiņas, un katra ours ievietotā rinda tiktu uzrādīta kā `insert_insert` konflikts.

Rezultātā ir uzskaitītas darbības, kas pārveido base par apvienoto stāvokli, ietverot abu pušu izmaiņas, un katrai norādīts tās avots (`ours`, `theirs` vai `merged`). Lai pārnestu smilškastes izmaiņas uz reāllaika datubāzi, lietojiet tikai darbības, kuru tajā vēl nav, izmantojot [Nosacītā lietošana](https://merql.inline0.dev/lv/docs/apply/guarded).

Vai no CLI, kas izveido savienojumu ar `snapshot` norādīto datubāzi katram `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
```

## Kāpēc izvēlēties merql

Lielākā daļa datubāzu rīku, kas salīdzina stāvokļus, darbojas rindu līmenī: ja starp divām versijām atšķiras kaut viena rindas kolonna, visa rinda tiek atzīmēta kā konflikts. Tādēļ kļūdaini konflikti rodas, ja divi cilvēki rediģē vienas rindas dažādas kolonnas.

merql apvieno kolonnu līmenī. Ja viena puse mainīja `title`, bet otra — `status`, izmaiņas tiek veiksmīgi apvienotas bez konflikta. Konflikts rodas tikai tad, ja abas puses maina vienu un to pašu kolonnu uz atšķirīgām vērtībām.

TEXT un JSON kolonnām merql var iet vēl vienu līmeni dziļāk un veikt apvienošanu šūnu līmenī. Divas izmaiņas dažādās teksta kolonnas rindās vai dažādās JSON kolonnas atslēgās var veiksmīgi apvienot, izmantojot to pašu trīspusējo algoritmu. Šūnu līmeņa apvienošana jāieslēdz atsevišķi: nododiet `CellMergeConfig` uz `ThreeWayMerge`. Fasāde `Merql` un CLI apvieno tikai kolonnu līmenī. Skatiet sadaļu [Šūnu līmeņa apvienošana](https://merql.inline0.dev/lv/docs/merge/cell-level).

## Apvienošanas modelis

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

Trīs stāvokļi, tāpat kā git. Base ir kopīgais priekštecis. Ours un theirs ir abas kopijas pēc to atšķiršanās; katra iegūta no savas datubāzes. Apvienošanas noteikumi abām pusēm ir vienādi. Šie nosaukumi parādās katras darbības laukā `source`, konfliktu veidos (`update_delete` nozīmē, ka ours atjaunināja, bet theirs izdzēsa) un atrisināšanas politikās `OursWins` un `TheirsWins`. Bez kopīgas bāzes nevar atšķirt “pievienots” no “nemainīts”.

Apvienošana pati par sevi neko neraksta. Tās darbības pārveido base par apvienoto stāvokli, tāpēc `Merql::apply()` tās visas var veiksmīgi izpildīt tikai datubāzē, kurā joprojām ir base stāvoklis. Lai pārnestu vienas puses izmaiņas datubāzē, kurā jau ir otras puses izmaiņas, piemēram, pārnestu smilškastes rediģējumus uz reāllaika datubāzi, lietojiet tikai trūkstošās darbības; skatiet [Nosacītā lietošana](https://merql.inline0.dev/lv/docs/apply/guarded).

## Prasības

- PHP 8.2 vai jaunāka versija.
- `ext-mbstring` un `ext-zlib`, kas nepieciešami `pitmaster/pitmaster` atkarībai teksta atšķirību noteikšanai.
- Izmantotajam adapterim vajadzīgs datubāzes paplašinājums: `ext-pdo` ar `ext-pdo_sqlite` vai `ext-pdo_mysql`, vai `ext-mysqli`. merql `composer.json` tikai iesaka `ext-pdo` un `ext-mysqli`, tāpēc Composer tos nepārbauda.
- Datubāze MySQL vai SQLite. Citām sistēmām nepieciešams pielāgots [draiveris](https://merql.inline0.dev/lv/docs/apply/drivers).

## Kas tas nav

merql nav shēmas migrācijas rīks. Tas nereplicē datubāzes un nesinhronizē tās reāllaikā. Tas risina vienu konkrētu problēmu: no trim datubāzes stāvokļiem izveidot ceturto, apvienoto stāvokli, nosakot konfliktus.

## Dokumentācija

- [Darba sākšana](https://merql.inline0.dev/lv/docs/getting-started) — instalēšana, pirmais momentuzņēmums un pirmā apvienošana.
- [CLI atsauce](https://merql.inline0.dev/lv/docs/cli) — pilna atsauce par komandu `vendor/bin/merql`.
- [PHP API atsauce](https://merql.inline0.dev/lv/docs/api) — pilna API dokumentācija par visām klasēm.
- [Apvienošanas plāni](https://merql.inline0.dev/lv/docs/merge/plans) — stabili darbību ID, izmaiņu grupas un atlases.
- [Nosacītā lietošana](https://merql.inline0.dev/lv/docs/apply/guarded) — atlasīti ieraksti ar reāllaika rindu priekšnosacījumiem.
- [Atcelšana](https://merql.inline0.dev/lv/docs/apply/rollback) — atcelšanas artefakti un noviržu pārbaudes.
