
# PHP API viide

Kõigi merql-i avalike klasside ja meetodite täielik viide.

## Merql (fassaad)

`Merql\Merql` on levinud toimingute staatiline sisenemispunkt. See ümbritseb madalama taseme klasse ja haldab automaatselt hetkeseisu püsisalvestust.

```php
use Merql\Connection;
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;
use Merql\Merql;

$connection = Connection::sqlite(':memory:');
Merql::init($connection, identityRules: new IdentityRuleSet([
    'options' => IdentityRule::natural(['option_name']),
]));
```

### `init(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null): void`

Initsialiseeri fassaad andmebaasiühendusega. Seda tuleb teha enne `snapshot()`, `apply()` või `applyGuarded()` kasutamist; andmebaasi vahetamiseks kutsu seda uuesti, näiteks hetkeseisu salvestamiseks meie ja nende andmebaasist kahest eri koopiast. Kui `$driver` puudub, kutsub see välja `DriverFactory::create()`, mis tekitab erindi muude mootorite korral peale MySQL ja SQLite, välja arvatud juhul, kui draiver on registreeritud. Edasta draiver automaatse tuvastuse ülekirjutamiseks või identiteedireeglite kogum tabelipõhise reaidentiteedi ülekirjutamiseks hetkeseisu hõivamisel.

### `snapshot(string $name, array $tables = []): Snapshot`

Hõiva andmebaasi praegune olek ja salvesta see kettale. Edasta kindlate tabelite hetkeseisu salvestamiseks tabelinimede massiiv või jäta see kõigi tabelite kaasamiseks ära.

```php
$snapshot = Merql::snapshot('baseline');
$snapshot = Merql::snapshot('baseline', ['posts', 'users']);
```

### `diff(string $base, string $current): Changeset`

Laadi kaks nimega hetkeseisu ja arvuta nendevaheline muudatuste kogum. `init()` pole vaja, sest töö käib püsisalvestatud hetkeseisude põhjal.

```php
$changeset = Merql::diff('before', 'after');
```

### `merge(string $base, string $ours, string $theirs): MergeResult`

Kolme nimega hetkeseisu kolmepoolne ühendamine. Tagastab tulemuse, mis sisaldab puhtaid toiminguid ja võimalikke konflikte. Ühendab veerutasemel: fassaad loob `ThreeWayMerge` ilma `CellMergeConfig`-ita, seega lahtritaseme ühendamist ei rakendata. Kasuta selleks otse [`ThreeWayMerge`](#threewaymerge).

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

### `patch(string $base, string $changes): MergeResult`

Kahepoolne ühendamine: rakendab muudatused algolekule. Võrdub toiminguga `merge($base, $base, $changes)`. Annab alati puhta tulemuse, sest samaaegseid muudatusi pole. Ainult veerutasemel, nagu ka `merge()`.

```php
$result = Merql::patch('base', 'changes');
```

### `apply(MergeResult $result): ApplyResult`

Käivita puhta ühendamistulemuse toimingud andmebaasis, mis edastati meetodile `init()`. Nõuab `init()`. Kui lahendamata konflikte on alles, tekitab erindi `ConflictException`.

Tulemuses olevad toimingud käivitatakse kõik, seega rakendub `merge()` täielik tulemus puhtalt ainult andmebaasile, milles on endiselt algolek. Andmebaasi puhul, kus on juba üks pool, rakenda neist toimingutest ainult valik, mis sealt puudub; vt [Valikuline rakendamine](https://merql.inline0.dev/et/docs/apply/guarded).

```php
$applied = Merql::apply($result);
echo $applied->rowsAffected();
```

### `plan(string $id, string $base, string $ours, string $theirs, array $metadata = []): MergePlan`

Koosta kolme nimega hetkeseisu põhjal ühendamisplaan, mis sobib UI-iga. Plaan sisaldab stabiilseid toimingu ID-sid, muudatuste rühmade ID-sid, toimingu konteksti, konflikte, skeemivastuolusid, kokkuvõtet, metaandmeid ja plaani räsi. Ühendamine toimub veerutasemel nagu meetodis `merge()`; lahtritaseme ühendamiseks edasta lahtrid ühendanud tulemus meetodile `MergePlanBuilder::build()`.

```php
$plan = Merql::plan('plan-1', 'base', 'ours', 'theirs', [
    'source' => 'review-ui',
]);
```

### `applyGuarded(MergeResult $result, Snapshot $expectedLive): ApplyResult`

Rakenda puhas ühendamistulemus optimistlike aktiivrea eeltingimustega. Uuenduste ja kustutamiste korral peavad praegused aktiivread vastama väärtusele `$expectedLive`; lisamiste korral ei tohi sihtidentiteet juba olemas olla. `$expectedLive` on sihtandmebaasi hetkeseis (nende oma, kui meie omad viiakse üle andmebaasi, millest nende hetkeseis tehti). Iga päring, mis ei mõjuta ühtki rida, pöörab tehingu tagasi.

```php
use Merql\Snapshot\SnapshotStore;

$applied = Merql::applyGuarded($selectedResult, SnapshotStore::load('theirs'));
```

### `reset(): void`

Tühjenda sisemine ühenduse ja Snapshotteri eksemplar. Kasutatakse peamiselt testides oleku lähtestamiseks käivituste vahel.

---

## Ühendus

`Merql\Connection` loob mõistlike vaikeväärtustega ühenduse adapterid. PDO-ühendused kasutavad vigade korral erindeid, assotsiatiivset päringutulemuste režiimi, emuleerimata ettevalmistusi ja stringidena tagastatavaid väärtusi. mysqli-adapter normaliseerib tagastatud väärtused samasse stringi või nulli vormingusse.

### `mysql(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): PdoDatabaseConnection`

```php
use Merql\Connection;

$connection = Connection::mysql('127.0.0.1', 'my_app', 'root', 'secret');
```

### `mysqli(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): MysqliDatabaseConnection`

```php
$connection = Connection::mysqli('127.0.0.1', 'my_app', 'root', 'secret');
```

### `sqlite(string $path = ':memory:'): PdoDatabaseConnection`

Loob ühenduse objektiga SQLite. Lubab võõrvõtmed automaatselt meetodi `PRAGMA foreign_keys = ON` kaudu.

```php
$connection = Connection::sqlite('/var/data/app.sqlite');
$connection = Connection::sqlite(':memory:');
```

### `fromDsn(string $dsn, string $username = '', string $password = ''): PdoDatabaseConnection`

Ühenda mis tahes PDO DSN-stringi abil. merql sisaldab draivereid ainult `mysql` ja `sqlite` jaoks; muude DSN-idega saab ühenduse luua, kuid `Merql::init()`, `Snapshotter` ja rakendajad tekitavad erindi `Unsupported database driver`, välja arvatud juhul, kui meetodi `DriverFactory::register()` abil on draiver registreeritud.

```php
$connection = Connection::fromDsn('mysql:host=localhost;dbname=app', 'root', 'pass');
```

### `fromPdo(PDO $pdo): PdoDatabaseConnection`

Ümbritse olemasolev PDO eksemplar.

### `fromMysqli(mysqli $mysqli, string $charset = 'utf8mb4'): MysqliDatabaseConnection`

Ümbritse olemasolev mysqli eksemplar.

### Adapteri leping

Kõik adapterid rakendavad liidest `Merql\Database\DatabaseConnection`:

```php
interface DatabaseConnection
{
    public function driverName(): string;
    public function execute(string $sql, array $params = []): int;
    public function query(string $sql, array $params = []): array;
    public function scalar(string $sql, array $params = []): ?string;
    public function beginTransaction(): void;
    public function commit(): void;
    public function rollBack(): void;
    public function lastInsertId(): string;
}
```

`execute()`, `query()` ja `scalar()` võtavad `list<scalar|null>` kohaparameetrid `?` kohatäitjate jaoks. `query()` tagastab `list<array<string, scalar|null>>`; väärtused normaliseeritakse PDO ja mysqli adapterites ühtsesse stringi või nulli vormingusse.

---

## Snapshotter

`Merql\Snapshot\Snapshotter` hõivab andmebaasi oleku. Erinevalt fassaadist annab see filtrite üle täieliku kontrolli ega salvesta automaatselt püsivalt.

### `__construct(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null)`

Kui draiverit pole määratud, tuvastatakse see ühenduse identiteedi põhjal automaatselt. Edasta `IdentityRuleSet`, kui tabelipõhine reaidentiteet peab skeemi vaikeväärtused üle kirjutama.

### `capture(string $name, array $tables = [], array $filters = []): Snapshot`

Hõiva praegune olek. Ulatus määramiseks edasta tabelinimed. Tabelite, veergude või ridade välistamiseks edasta filtriobjektid.

```php
use Merql\Snapshot\Snapshotter;
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Filter\RowFilter;
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;

$snapshotter = new Snapshotter(
    $connection,
    identityRules: new IdentityRuleSet([
        'wp_options' => IdentityRule::natural(['option_name']),
    ]),
);

// All tables.
$snapshot = $snapshotter->capture('full');

// Specific tables with filters.
$snapshot = $snapshotter->capture('filtered', ['posts', 'users'], [
    TableFilter::exclude(['cache_*', 'sessions']),
    ColumnFilter::ignore(['updated_at', 'created_at']),
    RowFilter::create(fn(string $table, array $row) => $row['status'] !== 'trash'),
]);
```

### `captureAliased(string $name, array $physicalToCanonicalTableMap, array $filters = []): Snapshot`

Hõiva füüsilised tabelid kanooniliste tabelinimede all. Kasuta seda, kui sama loogilise tabeli füüsilised nimed on eri keskkondades erinevad.

```php
$snapshot = $snapshotter->captureAliased('sandbox', [
    'wp_onumia_abcd_posts' => 'wp_posts',
    'wp_onumia_abcd_postmeta' => 'wp_postmeta',
]);
```

Saadud hetkeseis salvestab kanoonilised tabelinimed, säilitades füüsilise tabeli skeemi, seadistatud identiteediveerud, reapõhised võtmed ja filtrid.

### `fromData(string $name, array $tableData): Snapshot` (staatiline)

Koosta hetkeseis toorandmetest ilma andmebaasiühenduseta. Kasulik testimiseks või teisest allikast andmete importimisel.

```php
use Merql\Snapshot\Snapshotter;
use Merql\Snapshot\TableSnapshotData;
use Merql\Schema\TableSchema;

$schema = new TableSchema('posts', ['id' => 'int', 'title' => 'varchar'], ['id']);

$snapshot = Snapshotter::fromData('test', [
    'posts' => new TableSnapshotData($schema, [
        ['id' => '1', 'title' => 'Hello'],
        ['id' => '2', 'title' => 'World'],
    ], ['id']),
]);
```

---

## Hetkeseis

`Merql\Snapshot\Snapshot` on kirjutuskaitstud väärtusobjekt, mis esitab täielikku andmebaasi olekut.

```php
$snapshot->name;                    // string: snapshot identifier
$snapshot->tables;                  // array<string, TableSnapshot>
$snapshot->tableNames();            // list<string>
$snapshot->hasTable('posts');       // bool
$snapshot->getTable('posts');       // ?TableSnapshot
```

---

## TableSnapshot

`Merql\Snapshot\TableSnapshot` sisaldab ühe tabeli ridu, sõrmejälgi ja skeemi.

```php
$table = $snapshot->getTable('posts');

$table->schema;                    // TableSchema
$table->identityColumns;           // list<string>: columns used for row identity
$table->fingerprints;              // array<string, string>: row key to hash
$table->rows;                      // array<string, array<string, mixed>>

$table->rowKeys();                 // list<string>
$table->rowCount();                // int
$table->hasRow('42');              // bool
$table->getRow('42');              // ?array<string, mixed>
$table->getFingerprint('42');      // ?string
```

---

## TableSnapshotData

`Merql\Snapshot\TableSnapshotData` on sisendandmed objektile `Snapshotter::fromData()`.

```php
use Merql\Snapshot\TableSnapshotData;
use Merql\Schema\TableSchema;

$data = new TableSnapshotData(
    schema: new TableSchema('posts', ['id' => 'int', 'title' => 'varchar'], ['id']),
    rows: [
        ['id' => '1', 'title' => 'First Post'],
    ],
    identityColumns: ['id'],
);
```

---

## IdentityRule

`Merql\Identity\IdentityRule` määrab reapõhiste võtmete loomiseks kasutatavad veerud.

```php
use Merql\Identity\IdentityRule;

$primary = IdentityRule::primary(['id']);
$natural = IdentityRule::natural(['option_name']);
$composite = IdentityRule::composite(['object_id', 'term_taxonomy_id']);
$content = IdentityRule::content(['name', 'value']);

$key = $natural->key(['option_name' => 'siteurl']);
// "siteurl"
```

### `forSchema(TableSchema $schema): IdentityRule` (staatiline)

Lahenda skeemi põhjal vaikeidentiteedireegel: primaarvõti, esimene kordumatu võti ja seejärel sisupõhine varuvariant.

### `toArray(): array`

Serialiseeri reegel kujul `['type' => string, 'columns' => list<string>]`.

### `fromArray(array $data): IdentityRule` (staatiline)

Loo reegel serialiseeritud andmete põhjal.

---

## IdentityRuleSet

`Merql\Identity\IdentityRuleSet` salvestab tabelipõhised identiteedi ülekirjutused.

```php
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;

$rules = new IdentityRuleSet([
    'wp_options' => IdentityRule::natural(['option_name']),
]);

$rule = $rules->ruleFor($schema);
```

### `with(string $table, IdentityRule $rule): IdentityRuleSet`

Tagasta uus reeglistik koos ühe tabeli ülekirjutusega.

### `conflictsFor(string $table, IdentityRule $rule, array $rows): array`

Tagasta `IdentityConflict` kirjed, kui mitu rida annavad ühe reegli korral sama võtme.

### `toArray(): array`

Serialiseeri tabelireeglid massiivina, mis on JSON-iga ühilduv.

### `fromArray(array $data): IdentityRuleSet` (staatiline)

Loo reeglistik serialiseeritud andmete põhjal.

---

## SnapshotStore

`Merql\Snapshot\SnapshotStore` salvestab ja laadib hetkeseise JSON-failidena.

### `setDirectory(string $directory): void`

Määra salvestuskataloog. Vaikimisi on `.merql/snapshots`.

### `save(Snapshot $snapshot): void`

Kirjuta hetkeseis kettale.

### `load(string $name): Snapshot`

Laadi hetkeseis nime järgi. Kui seda ei leita, tekitab erindi `SnapshotException`.

### `exists(string $name): bool`

Kontrolli, kas hetkeseisufail on olemas.

### `delete(string $name): void`

Eemalda hetkeseisufail.

---

## Differ

`Merql\Diff\Differ` võrdleb kahte hetkeseisu ja koostab muudatuste kogumi.

### `diff(Snapshot $base, Snapshot $current): Changeset`

```php
use Merql\Diff\Differ;

$differ = new Differ();
$changeset = $differ->diff($baseSnapshot, $currentSnapshot);
```

### `valuesEqual(mixed $a, mixed $b): bool` (staatiline)

Võrdle kahte väärtust stringiks teisendades. NULL-i käsitletakse eraldi väärtusena: `NULL === NULL` on tõene, `NULL === ''` on väär.

---

## Muudatuste kogum

`Merql\Diff\Changeset` on kirjutuskaitstud reapõhiste toimingute kogu.

```php
$changeset->inserts();             // list<RowInsert>
$changeset->updates();             // list<RowUpdate>
$changeset->deletes();             // list<RowDelete>
$changeset->isEmpty();             // bool
$changeset->count();               // int: total operations
$changeset->forTable('posts');     // Changeset: filtered to one table
```

---

## RowInsert, RowUpdate, RowDelete

Kirjutuskaitstud väärtusobjektid, mis esindavad üksikuid reamuudatusi.

### RowInsert

```php
$insert->table;                    // string
$insert->rowKey;                   // string
$insert->values;                   // array<string, mixed>
```

### RowUpdate

```php
$update->table;                    // string
$update->rowKey;                   // string
$update->columnDiffs;              // list<ColumnDiff>
$update->fullRow;                  // array<string, mixed>: complete current row
$update->columnDiffMap();          // array<string, ColumnDiff>: keyed by column name
```

### RowDelete

```php
$delete->table;                    // string
$delete->rowKey;                   // string
$delete->oldValues;                // array<string, mixed>: values before deletion
```

---

## ColumnDiff

`Merql\Diff\ColumnDiff` esindab üht veerumuudatust rea uuendamise käigus.

```php
$diff->column;                     // string
$diff->oldValue;                   // mixed
$diff->newValue;                   // mixed
```

---

## ThreeWayMerge

`Merql\Merge\ThreeWayMerge` on ühendamise põhialgoritm.

### `__construct(?CellMergeConfig $cellMergeConfig = null)`

Lahtritasemel ühendamise lubamiseks edasta `CellMergeConfig` TEXT- ja JSON-veergude jaoks.

```php
use Merql\Merge\ThreeWayMerge;
use Merql\CellMerge\CellMergeConfig;

// Default: column-level merge only.
$merge = new ThreeWayMerge();

// With cell-level merge for TEXT and JSON columns.
$merge = new ThreeWayMerge(CellMergeConfig::auto());
```

### `merge(Snapshot $base, Snapshot $ours, Snapshot $theirs): MergeResult`

Tee kolmepoolne ühendamine. Arvutab muudatuste kogumid sisemiselt (algolekust meie omani ja algolekust nende omani) ning ühendab need.

```php
$result = $merge->merge($baseSnapshot, $oursSnapshot, $theirsSnapshot);
```

### `patch(Snapshot $base, Snapshot $changes): MergeResult`

Kahepoolse ühendamise otsetee. Võrdub toiminguga `merge($base, $base, $changes)`.

### `schemaMismatches(): array`

Tagastab `SchemaException[]` viimase ühendamise käigus tuvastatud skeemierinevuste kohta (hetkeseisude vahel lisatud või eemaldatud veerud).

---

## MergeResult

`Merql\Merge\MergeResult` on kirjutuskaitstud väärtusobjekt, mis sisaldab ühendamise tulemust.

```php
$result->isClean();                // bool: no conflicts
$result->operations();             // list<MergeOperation>
$result->conflicts();              // list<Conflict>
$result->operationCount();         // int
$result->conflictCount();          // int
$result->baseSnapshot();           // ?Snapshot
$result->schemaMismatches();       // list<SchemaException>
$result->hasSchemaMismatches();    // bool
```

---

## MergePlan

`Merql\Plan\MergePlan` on serialiseeritav ühendamise ülevaatemudel.

```php
$plan->id;                        // string
$plan->baseSnapshot;              // string
$plan->oursSnapshot;              // string
$plan->theirsSnapshot;            // string
$plan->summary;                   // MergePlanSummary
$plan->changeGroups;              // list<MergePlanChangeGroup>
$plan->operations;                // list<MergePlanOperation>
$plan->conflicts;                 // list<MergePlanConflict>
$plan->schemaMismatches;          // list<string>
$plan->hash;                      // string
$plan->metadata;                  // array<string, mixed>
```

Kasuta meetodeid `MergePlanSerializer::toJson()` ja `::fromJson()` stabiilseks JSON edasi-tagasi teisendamiseks.

## Valikud

`ChangeGroupSelection` salvestab lavastatud muudatuste rühmade ID-d. Teisenda see objektiks `OperationSelection` valitud ühendamistulemuste või tagasivõtmisplaanide koostamisel.

```php
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;

$selection = ChangeGroupSelection::fromIds([$groupId]);
$operationSelection = $selection->toOperationSelection($plan);

$selected = (new SelectedMergeResultFactory())
    ->fromOperationSelection($plan, $operationSelection);
```

## RollbackPlan

`Merql\Rollback\RollbackPlan` salvestab valitud rakenduse jaoks pöördtoimingud ja kõrvalekalde ootused.

```php
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Rollback\RollbackPlanSerializer;

$rollback = (new RollbackPlanBuilder())->build(
    'rollback-1',
    $plan,
    $operationSelection,
    $liveBeforeRows,
);

$json = RollbackPlanSerializer::toJson($rollback);
```

Kasuta enne tagasivõtmise rakendamist meetodit `RollbackDrift` ja seejärel pöördtoimingute käivitamiseks meetodit `RollbackPlanApplier`.

---

## MergeOperation

`Merql\Merge\MergeOperation` on üks lahendatud ühendamistoiming.

```php
$op->type;                         // string: 'insert' | 'update' | 'delete'
$op->table;                        // string
$op->rowKey;                       // string
$op->values;                       // array<string, mixed>
$op->source;                       // string: 'ours' | 'theirs' | 'merged'
```

Tüübi konstandid:

```php
MergeOperation::TYPE_INSERT;       // 'insert'
MergeOperation::TYPE_UPDATE;       // 'update'
MergeOperation::TYPE_DELETE;       // 'delete'
```

---

## Konflikt

`Merql\Merge\Conflict` esindab lahendamata ühendamiskonflikti.

```php
$conflict->table();                // string
$conflict->rowKey();               // string
$conflict->type();                 // string: 'update_update' | 'update_delete' | 'delete_update' | 'insert_insert'
$conflict->column();               // ?string (null for structural conflicts)
$conflict->oursValue();            // mixed
$conflict->theirsValue();          // mixed
$conflict->baseValue();            // mixed
$conflict->primaryKey(['id']);     // array<string, string>: decoded from rowKey
```

### Konfliktitüübid

| Tüüp | Tähendus |
|---|---|
| `update_update` | Mõlemad pooled muutsid sama veeru väärtuse erinevaks |
| `update_delete` | Meie pool uuendas rida, mille nende pool kustutas |
| `delete_update` | Meie pool kustutas rea, mida nende pool uuendas |
| `insert_insert` | Mõlemad pooled lisasid sama primaarvõtmega rea |

---

## ConflictResolver

`Merql\Merge\ConflictResolver` rakendab ühendamistulemuse kõigile konfliktidele lahenduspoliitika.

### `resolve(MergeResult $result, ConflictPolicy $policy): MergeResult` (staatiline)

Tagastab uue `MergeResult`-i, mille konfliktid on poliitika järgi lahendatud.

```php
use Merql\Merge\ConflictResolver;
use Merql\Merge\ConflictPolicy;

// Accept all "theirs" values when conflicts arise.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);

// Accept all "ours" values.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::OursWins);

// Return unchanged (for manual inspection).
$resolved = ConflictResolver::resolve($result, ConflictPolicy::Manual);
```

---

## ConflictPolicy

`Merql\Merge\ConflictPolicy` on kolme juhuga toetatud enum.

```php
use Merql\Merge\ConflictPolicy;

ConflictPolicy::OursWins;          // Resolve all conflicts in favor of "ours"
ConflictPolicy::TheirsWins;        // Resolve all conflicts in favor of "theirs"
ConflictPolicy::Manual;            // Leave conflicts unresolved for manual handling
```

---

## ColumnMerge

`Merql\Merge\ColumnMerge` teeb ühe rea veerupõhise ühendamisloogika. Seda kasutab sisemiselt `ThreeWayMerge`.

### `merge(string $table, string $rowKey, array $base, array $ours, array $theirs, ?CellMergeConfig $cellMergeConfig = null, array $columnTypes = []): array` (staatiline)

Tagastab `['values' => array, 'conflicts' => list<Conflict>]`.

```php
use Merql\Merge\ColumnMerge;

$result = ColumnMerge::merge(
    'posts',
    '42',
    ['title' => 'Hello', 'status' => 'draft'],     // base
    ['title' => 'Hello', 'status' => 'published'],  // ours
    ['title' => 'New Title', 'status' => 'draft'],   // theirs
);

// $result['values'] = ['title' => 'New Title', 'status' => 'published']
// $result['conflicts'] = [] (clean merge)
```

---

## Rakendaja

`Merql\Apply\Applier` rakendab ühendamistulemuse andmebaasi suhtes.

### `__construct(DatabaseConnection $connection, ?Driver $driver = null)`

### `apply(MergeResult $result, ?Snapshot $base = null): ApplyResult`

Käivitab kõik toimingud ühes tehingus. Mis tahes vea korral pöörab tehingu tagasi ja lisab vea `ApplyResult::errors()`-i, selle asemel et erindi tekitada. Kui tulemuses on lahendamata konflikte, tekitab erindi `ConflictException`.

```php
use Merql\Apply\Applier;

$applier = new Applier($connection);
$applied = $applier->apply($result);

echo "Rows affected: {$applied->rowsAffected()}\n";
if ($applied->hasErrors()) {
    print_r($applied->errors());
}
```

Võõrvõtmete järjestus lahendatakse automaatselt: lisamised sorditakse sõltuvuste järjekorda ja kustutamised sõltuvuste pöördjärjekorda.

---

## ApplyResult

`Merql\Apply\ApplyResult` on kirjutuskaitstud väärtusobjekt, mille rakendaja tagastab.

```php
$applied->rowsAffected();         // int
$applied->errors();               // list<string>
$applied->hasErrors();            // bool
```

Pärast tagasi pööratud rakendamist loeb `rowsAffected()` endiselt enne tõrget käivitatud laused kokku ([#4](https://github.com/inline0/merql/issues/4)). Enne loenduse usaldamist kontrolli väärtust `hasErrors()`.

---

## DryRun

`Merql\Apply\DryRun` loob inimloetavad SQL-id ilma neid käivitamata.

### `generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array` (staatiline)

Tagastab loendi SQL-stringidest, millesse väärtused on kuvamise eesmärgil sisse kirjutatud.

```php
use Merql\Apply\DryRun;

$statements = DryRun::generate($result);

foreach ($statements as $sql) {
    echo "{$sql};\n";
}

// Output:
// INSERT INTO `posts` (`id`, `title`) VALUES ('10', 'New Post');
// UPDATE `posts` SET `title` = 'Updated' WHERE `id` = '5';
// DELETE FROM `comments` WHERE `id` = '3';
```

---

## SqlGenerator

`Merql\Apply\SqlGenerator` loob parameetritega SQL-lauseid. Seda kasutavad sisemiselt nii `Applier` kui ka `DryRun`.

### `generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array` (staatiline)

Tagastab `list<array{sql: string, params: list<scalar|null>}>`.

```php
use Merql\Apply\SqlGenerator;

$statements = SqlGenerator::generate($result);

foreach ($statements as $stmt) {
    $connection->execute($stmt['sql'], $stmt['params']);
}
```

---

## CellMergeConfig

`Merql\CellMerge\CellMergeConfig` seadistab kindlate veergude või veerutüüpide jaoks lahtritaseme ühendamisstrateegiad.

### `auto(): self` (staatiline)

Mugavusfunktsioon, mis määrab tüübi `TextCellMerger` veergudele TEXT/LONGTEXT ja tüübi `JsonCellMerger` veergudele JSON.

```php
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();
```

### `forColumn(string $column, CellMerger $merger): self`

Määra ühendaja kindlale veerule. Kasuta täielikult kvalifitseeritud nimede jaoks `table.column` või kõigi tabelite jaoks lihtsalt `column`.

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\TextCellMerger;

$config = (new CellMergeConfig())
    ->forColumn('posts.content', new TextCellMerger())
    ->forColumn('description', new TextCellMerger());
```

### `forType(string $typePattern, CellMerger $merger): self`

Määra ühendaja kõigile veergudele, mis vastavad tüübi mustrile (tõstutundetu alamstringi vaste).

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;

$config = (new CellMergeConfig())
    ->forType('json', new JsonCellMerger());
```

### `getMerger(string $table, string $column, string $columnType = ''): CellMerger`

Leia ühendaja tabeli, veeru ja tüübi järgi. Järjekord: täielikult kvalifitseeritud veeru nimi, kvalifitseerimata veeru nimi, tüübi muster, vaikeväärtus (läbipaistmatu).

---

## CellMerger (liides)

`Merql\CellMerge\CellMerger` on lahtritaseme ühendamisstrateegiate liides.

```php
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;

interface CellMerger
{
    public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult;
}
```

Saadaval on kolm sisseehitatud teostust.

### TextCellMerger

`Merql\CellMerge\TextCellMerger` liidab mitmerealise teksti kolmesuunalise ridade kaupa võrdlusega (sama algoritm, mida git kasutab failide sisu jaoks). Kui pooled muudavad erinevaid ridu, on liitmine puhas. Kui mõlemad muudavad sama rida erinevalt, annab see konfliktist teada.

```php
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();
$result = $merger->merge(
    "line 1\nline 2\nline 3",
    "line 1\nline 2 modified\nline 3",
    "line 1\nline 2\nline 3 modified",
);
// $result->clean === true
// $result->value === "line 1\nline 2 modified\nline 3 modified"
```

### JsonCellMerger

`Merql\CellMerge\JsonCellMerger` ühendab JSON väärtusi, võrreldes tipptaseme võtmeid ükshaaval. Iga võti ühendatakse kolmepoolse loogika abil. Pesastatud objekte võrreldakse läbipaistmatute JSON-stringidena (rekursiivset ühendamist ei toimu).

```php
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();
$result = $merger->merge(
    '{"a": 1, "b": 2}',
    '{"a": 10, "b": 2}',        // changed "a"
    '{"a": 1, "b": 20}',         // changed "b"
);
// $result->clean === true
// $result->value === '{"a":10,"b":20}'
```

### OpaqueCellMerger

`Merql\CellMerge\OpaqueCellMerger` on vaikeühendaja. See käsitleb väärtusi läbipaistmatute stringidena ja teatab erinevuse korral alati konfliktist.

---

## CellMergeResult

`Merql\CellMerge\CellMergeResult` on kõigi lahtriühendajate tagastustüüp.

```php
$result->clean;                    // bool: true if merge succeeded
$result->value;                    // mixed: merged value (or ours on conflict)
$result->conflicts;                // int: number of conflicts

// Factory methods.
CellMergeResult::resolved($value);           // clean merge
CellMergeResult::conflict($oursValue, $n);   // conflict with count
```

---

## TableSchema

`Merql\Schema\TableSchema` on tabeli struktuuri kirjutuskaitstud esitus.

```php
use Merql\Schema\TableSchema;

$schema = new TableSchema(
    name: 'posts',
    columns: ['id' => 'int', 'title' => 'varchar(255)', 'content' => 'text'],
    primaryKey: ['id'],
    uniqueKeys: [['slug']],
);

$schema->name;                     // string
$schema->columns;                  // array<string, string>: name to type
$schema->primaryKey;               // list<string>
$schema->uniqueKeys;               // list<list<string>>
$schema->hasPrimaryKey();          // bool
$schema->hasUniqueKeys();          // bool
$schema->columnNames();            // list<string>
```

---

## Draiverite süsteem

merql kasutab andmebaasipõhiste toimingute abstraheerimiseks laiendatavat draiverite süsteemi. Draiverid tuvastatakse ühenduse draiveriidentiteedi põhjal automaatselt.

### Driver (liides)

`Merql\Driver\Driver` määrab lepingu, mida kõik andmebaasidraiverid järgivad.

```php
interface Driver
{
    public function quoteIdentifier(string $name): string;
    public function listTables(DatabaseConnection $connection): array;
    public function readSchema(DatabaseConnection $connection, string $table): TableSchema;
    public function readForeignKeys(DatabaseConnection $connection): array;
    public function selectAll(string $table): string;
}
```

Sisseehitatud teostused: `MysqlDriver` ja `SqliteDriver`.

### DriverFactory

`Merql\Driver\DriverFactory` tuvastab draiveri ühenduse põhjal automaatselt.

```php
use Merql\Driver\DriverFactory;

$driver = DriverFactory::create($connection);
```

Kohandatud draiveri registreerimine teiste andmebaaside jaoks:

```php
DriverFactory::register('pgsql', MyPostgresDriver::class);
```

---

## Filtrid

### TableFilter

`Merql\Filter\TableFilter` kaasab või jätab tabelid välja glob-mustrite abil.

```php
use Merql\Filter\TableFilter;

$filter = TableFilter::exclude(['cache_*', 'sessions', 'temp_*']);
$filter = TableFilter::include(['posts', 'users', 'comments']);
```

### ColumnFilter

`Merql\Filter\ColumnFilter` eemaldab hetkeseisudest kindlad veerud.

```php
use Merql\Filter\ColumnFilter;

$filter = ColumnFilter::ignore(['updated_at', 'created_at', 'modified_date']);
```

### RowFilter

`Merql\Filter\RowFilter` filtreerib ridu predikaatfunktsiooni abil.

```php
use Merql\Filter\RowFilter;

$filter = RowFilter::create(function (string $table, array $row): bool {
    // Exclude trashed posts.
    if ($table === 'posts' && ($row['status'] ?? '') === 'trash') {
        return false;
    }
    return true;
});
```

---

## Erandid

### SnapshotException

`Merql\Exceptions\SnapshotException` tekitatakse, kui hetkeseisu ei leita või selle nimi on sobimatu.

```php
SnapshotException::notFound('baseline', '/path/to/baseline.json');
```

### MergeException

`Merql\Exceptions\MergeException` tekitatakse, kui ühendamiseks vajalik hetkeseis puudub.

```php
MergeException::snapshotRequired('base');
```

### ConflictException

`Merql\Exceptions\ConflictException` tekitatakse, kui proovitakse rakendada ühendamistulemust, milles on lahendamata konflikte.

```php
ConflictException::unresolved(3);
// Message: "Cannot apply merge with 3 unresolved conflict(s)"
```

### SchemaException

`Merql\Exceptions\SchemaException` tekitatakse (või kogutakse), kui hetkeseisude skeemid erinevad.

```php
SchemaException::mismatch('posts', 'column "tags" exists in current but not in base');
```

Skeemivastuolud ei peata ühendamist. Need kogutakse kokku ja neid saab kontrollida meetodi `$result->schemaMismatches()` kaudu.
