Přejít k obsahu

Referenční dokumentace PHP API

Úplná referenční dokumentace všech veřejných tříd a metod v merql.

Merql (fasáda)

Merql\Merql je statickým vstupním bodem pro běžné operace. Zastřešuje nízkoúrovňové třídy a automaticky spravuje trvalé ukládání snímků.

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

Inicializujte fasádu připojením k databázi. Je nutné ji zavolat před snapshot(), apply() nebo applyGuarded(); zavolejte ji znovu při přepnutí databáze, například při pořizování snímků naší a jejich kopie ze dvou různých kopií. Bez $driver zavolá DriverFactory::create(), který vyvolá výjimku pro jiné databázové stroje než MySQL a SQLite, pokud není zaregistrován ovladač. Předejte ovladač, chcete-li přepsat automatickou detekci, nebo sadu pravidel identity, chcete-li při pořizování snímku přepsat identitu řádků pro jednotlivé tabulky.

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

Zachyťte aktuální stav databáze a uložte ho na disk. Předejte pole názvů tabulek, chcete-li pořídit snímek konkrétních tabulek; vynecháte-li ho, zahrnou se všechny tabulky.

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

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

Načte dva pojmenované snímky a vypočítá mezi nimi sadu změn. init() není potřeba, protože se pracuje s uloženými snímky.

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

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

Třístranné sloučení tří pojmenovaných snímků. Vrátí výsledek obsahující čisté operace a případné konflikty. Sloučení probíhá na úrovni sloupců: fasáda vytvoří ThreeWayMerge bez CellMergeConfig, takže se sloučení na úrovni buněk neprovede. Pro toto použijte přímo ThreeWayMerge.

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

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

Dvoustranné sloučení: použije změny na základ. Odpovídá merge($base, $base, $changes). Výsledek je vždy čistý, protože nedochází k souběžným úpravám. Stejně jako merge() probíhá pouze na úrovni sloupců.

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

apply(MergeResult $result): ApplyResult

Provede čistý výsledek sloučení nad databází předanou do init(). Vyžaduje init(). Pokud zůstanou nevyřešené konflikty, vyvolá ConflictException.

Provedou se všechny operace ve výsledku, takže celý výsledek merge() lze čistě použít pouze v databázi, která stále obsahuje základní stav. Pokud databáze již obsahuje jednu stranu, použijte výběr operací, které v ní chybí; viz Řízené použití.

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

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

Vytvoří plán sloučení připravený pro UI ze tří pojmenovaných snímků. Plán obsahuje stabilní ID operací, ID skupin změn, kontext operací, konflikty, neshody schématu, souhrn, metadata a hash plánu. Sloučení probíhá na úrovni sloupců stejně jako v merge(); pro sloučení na úrovni buněk předejte výsledek sloučení buněk do MergePlanBuilder::build().

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

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

Použije čistý výsledek sloučení s optimistickými předpoklady pro aktuální řádky. U aktualizací a mazání musí aktuální živé řádky odpovídat $expectedLive; u vkládání nesmí cílová identita již existovat. $expectedLive je snímek cílové databáze (jejich strany, pokud se naše změny přenášejí do databáze, z níž byl pořízen jejich snímek). Každý příkaz, který neovlivní žádné řádky, vrátí transakci zpět.

PHP
use Merql\Snapshot\SnapshotStore;

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

reset(): void

Vymaže interní instance připojení a nástroje Snapshotter. Používá se hlavně v testech k resetování stavu mezi běhy.


Připojení

Merql\Connection vytváří adaptéry připojení s rozumným výchozím nastavením. Připojení PDO používají při chybě výjimky, asociativní režim načítání, žádné emulované připravené dotazy a načtené hodnoty převádějí na řetězce. Adaptér mysqli normalizuje načtené hodnoty do stejného tvaru řetězec nebo null.

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

Vytvoří připojení SQLite. Automaticky zapne cizí klíče prostřednictvím PRAGMA foreign_keys = ON.

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

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

Připojte se pomocí libovolného řetězce DSN pro PDO. merql obsahuje ovladače pouze pro mysql a sqlite; ostatní DSN připojení otevřou, ale Merql::init(), Snapshotter a aplikátory vyvolají Unsupported database driver, pokud není ovladač zaregistrován pomocí DriverFactory::register().

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

fromPdo(PDO $pdo): PdoDatabaseConnection

Obalí existující instanci PDO.

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

Obalí existující instanci mysqli.

Kontrakt adaptéru

Všechny adaptéry implementují 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() a scalar() přijímají poziční parametry list<scalar|null> pro zástupné symboly ?. query() vrací list<array<string, scalar|null>>; hodnoty se normalizují do stejného tvaru řetězec nebo null u adaptérů PDO i mysqli.


Snapshotter

Merql\Snapshot\Snapshotter zachycuje stav databáze. Na rozdíl od fasády vám dává plnou kontrolu nad filtry a neukládá automaticky výsledek.

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

Ovladač se automaticky rozpozná podle identity připojení, pokud jej nezadáte. Předejte IdentityRuleSet, chcete-li přepsat výchozí nastavení schématu pro identitu řádků v konkrétních tabulkách.

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

Zachytí aktuální stav. Předejte názvy tabulek a omezte tak rozsah. Předejte objekty filtrů a vylučte tabulky, sloupce nebo řádky.

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

Zachytí fyzické tabulky pod kanonickými názvy tabulek. Použijte to, když má stejná logická tabulka v různých prostředích odlišné fyzické názvy.

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

Výsledný snímek ukládá kanonické názvy tabulek a zároveň zachovává schéma fyzických tabulek, nakonfigurované sloupce identity, klíče řádků a filtry.

fromData(string $name, array $tableData): Snapshot (statická metoda)

Vytvoří snímek z nezpracovaných dat bez připojení k databázi. Hodí se pro testování nebo import dat z jiného zdroje.

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']),
]);

Snímek

Merql\Snapshot\Snapshot je objekt pouze pro čtení, který reprezentuje úplný stav databáze.

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 obsahuje řádky, otisky a schéma jedné tabulky.

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 představuje vstupní data pro 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 definuje sloupce použité k vytvoření klíčů řádků.

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 (statická metoda)

Vyřeší výchozí pravidlo identity ze schématu: primární klíč, první jedinečný klíč, pak náhradní řešení podle obsahu.

toArray(): array

Serializuje pravidlo jako ['type' => string, 'columns' => list<string>].

fromArray(array $data): IdentityRule (statická metoda)

Načte pravidlo ze serializovaných dat.


IdentityRuleSet

Merql\Identity\IdentityRuleSet ukládá přepsání identity pro jednotlivé tabulky.

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

Vrátí novou sadu pravidel s přidaným přepsáním pro jednu tabulku.

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

Vrátí položky IdentityConflict, pokud více řádků vytvoří pro určité pravidlo stejný klíč.

toArray(): array

Serializuje pravidla tabulek do pole bezpečného pro JSON.

fromArray(array $data): IdentityRuleSet (statická metoda)

Načte sadu pravidel ze serializovaných dat.


SnapshotStore

Merql\Snapshot\SnapshotStore ukládá snímky jako soubory JSON a načítá je z nich.

setDirectory(string $directory): void

Nastaví adresář úložiště. Výchozí hodnota je .merql/snapshots.

save(Snapshot $snapshot): void

Zapíše snímek na disk.

load(string $name): Snapshot

Načte snímek podle názvu. Pokud jej nenajde, vyvolá SnapshotException.

exists(string $name): bool

Ověří, zda soubor se snímkem existuje.

delete(string $name): void

Odstraní soubor se snímkem.


Nástroj pro zjišťování rozdílů

Merql\Diff\Differ porovná dva snímky a vytvoří sadu změn.

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 (statická metoda)

Porovná dvě hodnoty po převedení na řetězec. NULL se považuje za samostatnou hodnotu: NULL === NULL platí, NULL === '' neplatí.


Sada změn

Merql\Diff\Changeset je kolekce operací na úrovni řádků pouze pro čtení.

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

Objekty pouze pro čtení představující jednotlivé změny řádků.

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 představuje změnu jednoho sloupce v rámci aktualizace řádku.

PHP
$diff->column;                     // string
$diff->oldValue;                   // mixed
$diff->newValue;                   // mixed

ThreeWayMerge

Merql\Merge\ThreeWayMerge je základním algoritmem sloučení.

__construct(?CellMergeConfig $cellMergeConfig = null)

Předejte CellMergeConfig a povolte sloučení buněk pro sloupce TEXT a JSON.

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

Provede třístranné sloučení. Interně vypočítá sady změn (od základu k naší straně a od základu k jejich straně) a sloučí je.

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

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

Zkratka pro dvoustranné sloučení. Odpovídá merge($base, $base, $changes).

schemaMismatches(): array

Vrátí SchemaException[] pro všechny rozdíly schématu zjištěné při posledním sloučení (sloupce přidané nebo odebrané mezi snímky).


MergeResult

Merql\Merge\MergeResult je objekt pouze pro čtení obsahující výsledek sloučení.

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 je serializovatelný model sloučení určený ke kontrole.

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>

Pro stabilní průběhy JSON použijte MergePlanSerializer::toJson() a ::fromJson().

Výběry

ChangeGroupSelection ukládá ID připravených skupin změn. Převeďte jej na OperationSelection při vytváření vybraných výsledků sloučení nebo plánů vrácení změn.

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 ukládá inverzní operace a očekávané odchylky pro vybrané použití změn.

PHP
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Rollback\RollbackPlanSerializer;

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

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

Před vrácením změn použijte RollbackDrift a pak spusťte inverzní operace pomocí RollbackPlanApplier.


MergeOperation

Merql\Merge\MergeOperation je jedna vyřešená operace ze sloučení.

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

Konstanty typů:

PHP
MergeOperation::TYPE_INSERT;       // 'insert'
MergeOperation::TYPE_UPDATE;       // 'update'
MergeOperation::TYPE_DELETE;       // 'delete'

Konflikt

Merql\Merge\Conflict představuje nevyřešený konflikt sloučení.

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

Typy konfliktů

Typ Význam
update_update Obě strany změnily stejný sloupec na různé hodnoty
update_delete Naše strana aktualizovala řádek, který jejich strana smazala
delete_update Naše strana smazala řádek, který jejich strana aktualizovala
insert_insert Obě strany vložily řádek se stejným primárním klíčem

ConflictResolver

Merql\Merge\ConflictResolver použije zásadu řešení na všechny konflikty ve výsledku sloučení.

resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (statická metoda)

Vrátí nové MergeResult s konflikty vyřešenými podle zásady.

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 je výčtový typ se třemi případy.

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 provádí logiku sloučení jednotlivých sloupců jednoho řádku. Interně jej používá ThreeWayMerge.

merge(string $table, string $rowKey, array $base, array $ours, array $theirs, ?CellMergeConfig $cellMergeConfig = null, array $columnTypes = []): array (statická metoda)

Vrátí ['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)

Aplikátor

Merql\Apply\Applier provede výsledek sloučení nad databází.

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

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

Provede všechny operace v jediné transakci. Při jakékoli chybě transakci vrátí zpět a nahlásí ji v ApplyResult::errors(), místo aby vyvolal výjimku. Pokud výsledek obsahuje nevyřešené konflikty, vyvolá 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());
}

Pořadí cizích klíčů se řeší automaticky: vkládání se řadí podle závislostí a mazání v opačném pořadí závislostí.


ApplyResult

Merql\Apply\ApplyResult je objekt pouze pro čtení, který vrací aplikátor.

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

Po vrácení transakce zpět stále rowsAffected() počítá příkazy spuštěné před selháním (#4). Než začnete počtu důvěřovat, zkontrolujte hasErrors().


DryRun

Merql\Apply\DryRun vytváří čitelné SQL, aniž cokoli provede.

generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statická metoda)

Vrátí seznam řetězců SQL s vloženými hodnotami (pouze pro zobrazení).

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 vytváří parametrizované příkazy SQL. Interně je používají jak Applier, tak DryRun.

generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statická metoda)

Vrátí 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 konfiguruje strategie sloučení buněk pro konkrétní sloupce nebo typy sloupců.

auto(): self (statická metoda)

Pomocná tovární metoda, která přiřadí TextCellMerger sloupcům TEXT/LONGTEXT a JsonCellMerger sloupcům JSON.

PHP
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();

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

Přiřadí slučovač konkrétnímu sloupci. Pro kvalifikované názvy použijte table.column, případně column pro všechny tabulky.

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

Přiřadí slučovač všem sloupcům odpovídajícím vzoru typu (rozlišování podřetězce bez ohledu na velikost písmen).

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;

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

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

Vyhledá slučovač pro zadanou tabulku, sloupec a typ. Priorita: kvalifikovaný název sloupce, nekvalifikovaný název sloupce, vzor typu, výchozí hodnota (opaque).


CellMerger (rozhraní)

Merql\CellMerge\CellMerger je rozhraní pro strategie sloučení na úrovni buněk.

PHP
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;

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

K dispozici jsou tři vestavěné implementace.

TextCellMerger

Merql\CellMerge\TextCellMerger slučuje víceřádkový text pomocí třícestného diffu řádek po řádku (stejný algoritmus, jaký git používá pro obsah souborů). Když obě strany upraví různé řádky, sloučení proběhne bez konfliktu. Když obě strany různě upraví stejný řádek, oznámí konflikt.

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 slučuje hodnoty JSON nezávislým porovnáním klíčů nejvyšší úrovně. Každý klíč se sloučí pomocí třístranné logiky. Vnořené objekty se porovnávají jako neprůhledné řetězce JSON (neprovádí se rekurzivní sloučení).

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 je výchozí možnost. S hodnotami zachází jako s neprůhlednými řetězci a při každém rozdílu vždy nahlásí konflikt.


CellMergeResult

Merql\CellMerge\CellMergeResult je návratovým typem všech slučovačů buněk.

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 je reprezentace struktury tabulky pouze pro čtení.

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>

Systém ovladačů

merql používá rozšiřitelný systém ovladačů, který abstrahuje operace specifické pro jednotlivé databáze. Ovladače se automaticky rozpoznávají podle identity ovladače připojení.

Driver (rozhraní)

Merql\Driver\Driver definuje kontrakt, který implementují všechny databázové ovladače.

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

Vestavěné implementace: MysqlDriver a SqliteDriver.

DriverFactory

Merql\Driver\DriverFactory automaticky rozpozná ovladač podle připojení.

PHP
use Merql\Driver\DriverFactory;

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

Zaregistrujte vlastní ovladač pro jiné databáze:

PHP
DriverFactory::register('pgsql', MyPostgresDriver::class);

Filtry

TableFilter

Merql\Filter\TableFilter zahrnuje nebo vylučuje tabulky pomocí vzorů glob.

PHP
use Merql\Filter\TableFilter;

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

ColumnFilter

Merql\Filter\ColumnFilter odstraňuje konkrétní sloupce ze snímků.

PHP
use Merql\Filter\ColumnFilter;

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

RowFilter

Merql\Filter\RowFilter filtruje řádky pomocí predikátové funkce.

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;
});

Výjimky

SnapshotException

Merql\Exceptions\SnapshotException se vyvolá, když snímek nelze najít nebo má neplatný název.

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

MergeException

Merql\Exceptions\MergeException se vyvolá, když pro sloučení chybí požadovaný snímek.

PHP
MergeException::snapshotRequired('base');

ConflictException

Merql\Exceptions\ConflictException se vyvolá při pokusu použít výsledek sloučení, který obsahuje nevyřešené konflikty.

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

SchemaException

Merql\Exceptions\SchemaException se vyvolá (nebo zachytí), když se schémata mezi snímky liší.

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

Neshody schémat sloučení nezastaví. Shromáždí se a lze je zkontrolovat pomocí $result->schemaMismatches().