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ů.
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.
$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.
$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.
$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ů.
$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í.
$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().
$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.
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
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
$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.
$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().
$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:
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.
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.
$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.
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.
$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.
$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().
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ů.
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.
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
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í.
$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
$insert->table; // string
$insert->rowKey; // string
$insert->values; // array<string, mixed>
RowUpdate
$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
$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.
$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.
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.
$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í.
$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.
$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.
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.
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í.
$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ů:
MergeOperation::TYPE_INSERT; // 'insert'
MergeOperation::TYPE_UPDATE; // 'update'
MergeOperation::TYPE_DELETE; // 'delete'
Konflikt
Merql\Merge\Conflict představuje nevyřešený konflikt sloučení.
$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.
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.
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>].
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.
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.
$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í).
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>}>.
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.
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.
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).
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.
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.
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í).
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.
$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í.
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.
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í.
use Merql\Driver\DriverFactory;
$driver = DriverFactory::create($connection);
Zaregistrujte vlastní ovladač pro jiné databáze:
DriverFactory::register('pgsql', MyPostgresDriver::class);
Filtry
TableFilter
Merql\Filter\TableFilter zahrnuje nebo vylučuje tabulky pomocí vzorů glob.
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ů.
use Merql\Filter\ColumnFilter;
$filter = ColumnFilter::ignore(['updated_at', 'created_at', 'modified_date']);
RowFilter
Merql\Filter\RowFilter filtruje řádky pomocí predikátové funkce.
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.
SnapshotException::notFound('baseline', '/path/to/baseline.json');
MergeException
Merql\Exceptions\MergeException se vyvolá, když pro sloučení chybí požadovaný snímek.
MergeException::snapshotRequired('base');
ConflictException
Merql\Exceptions\ConflictException se vyvolá při pokusu použít výsledek sloučení, který obsahuje nevyřešené konflikty.
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ší.
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().