Referentie voor PHP API
Volledige referentie voor alle openbare klassen en methoden in merql.
Merql (facade)
Merql\Merql is het statische toegangspunt voor veelgebruikte bewerkingen. Het vormt een laag om de onderliggende klassen en beheert het opslaan van snapshots automatisch.
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
Initialiseer de facade met een databaseverbinding. Dit moet gebeuren voordat u snapshot(), apply() of applyGuarded() aanroept; roep deze functie opnieuw aan om van database te wisselen, bijvoorbeeld om ours en theirs uit twee verschillende kopieën als snapshot op te slaan. Zonder $driver roept de functie DriverFactory::create() aan. Deze geeft een fout voor engines anders dan MySQL en SQLite, tenzij er een driver is geregistreerd. Geef een driver mee om automatische detectie te overschrijven, of een set identiteitsregels om de rij-identiteit per tabel tijdens het vastleggen van een snapshot te overschrijven.
snapshot(string $name, array $tables = []): Snapshot
Leg de huidige databasestatus vast en sla deze op schijf op. Geef een array met tabelnamen mee om een snapshot van specifieke tabellen te maken, of laat deze weg voor alle tabellen.
$snapshot = Merql::snapshot('baseline');
$snapshot = Merql::snapshot('baseline', ['posts', 'users']);
diff(string $base, string $current): Changeset
Laad twee snapshots op naam en bereken de wijzigingen tussen deze snapshots. init() is niet vereist, omdat de functie met opgeslagen snapshots werkt.
$changeset = Merql::diff('before', 'after');
merge(string $base, string $ours, string $theirs): MergeResult
Voert een three-way merge uit van drie snapshots op naam. Geeft een resultaat met conflictvrije bewerkingen en eventuele conflicten. De merge wordt op kolomniveau uitgevoerd: de facade bouwt ThreeWayMerge zonder CellMergeConfig, dus er wordt geen merge op celniveau toegepast. Gebruik hiervoor rechtstreeks ThreeWayMerge.
$result = Merql::merge('base', 'ours', 'theirs');
patch(string $base, string $changes): MergeResult
Two-way merge: pas wijzigingen toe op de basis. Gelijk aan merge($base, $base, $changes). Levert altijd een conflictvrij resultaat op, omdat er geen gelijktijdige bewerkingen zijn. Alleen op kolomniveau, net als merge().
$result = Merql::patch('base', 'changes');
apply(MergeResult $result): ApplyResult
Voer een conflictvrij mergeresultaat uit op de database die aan init() is doorgegeven. init() is vereist. Geeft ConflictException als er onopgeloste conflicten zijn.
Elke bewerking in het resultaat wordt uitgevoerd. Daarom wordt het volledige resultaat van merge() alleen correct toegepast op een database die nog de basisstatus bevat. Als een database al een van beide zijden bevat, pas dan een selectie toe van de bewerkingen die daarin ontbreken; zie Selectief toepassen.
$applied = Merql::apply($result);
echo $applied->rowsAffected();
plan(string $id, string $base, string $ours, string $theirs, array $metadata = []): MergePlan
Bouw een mergeplan dat klaar is voor UI op basis van drie snapshots op naam. Het plan bevat stabiele bewerkings-ID's, wijzigingsgroep-ID's, bewerkingscontext, conflicten, schemamismatches, een samenvatting, metagegevens en een planhash. De merge wordt op kolomniveau uitgevoerd, net als bij merge(); geef een resultaat dat op celniveau is samengevoegd door aan MergePlanBuilder::build() voor een merge op celniveau.
$plan = Merql::plan('plan-1', 'base', 'ours', 'theirs', [
'source' => 'review-ui',
]);
applyGuarded(MergeResult $result, Snapshot $expectedLive): ApplyResult
Pas een conflictvrij mergeresultaat toe met optimistische voorwaarden voor live rijen. Voor updates en verwijderingen moeten de huidige live rijen overeenkomen met $expectedLive; bij invoegingen mag de doelidentiteit nog niet bestaan. $expectedLive is een snapshot van de doeldatabase (theirs, wanneer ours wordt gepromoveerd naar de database waarvan theirs afkomstig is). Elke instructie die nul rijen beïnvloedt, maakt de transactie ongedaan.
use Merql\Snapshot\SnapshotStore;
$applied = Merql::applyGuarded($selectedResult, SnapshotStore::load('theirs'));
reset(): void
Wis de interne verbinding en de Snapshotter-instanties. Dit wordt voornamelijk gebruikt in tests om de status tussen uitvoeringen opnieuw in te stellen.
Verbinding
Merql\Connection bouwt verbindingsadapters met verstandige standaardinstellingen. PDO-verbindingen gebruiken uitzonderingen bij fouten, een associatieve ophaalmodus, geen geëmuleerde voorbereide instructies en opgehaalde waarden als tekenreeksen. De mysqli-adapter normaliseert opgehaalde waarden naar dezelfde vorm van tekenreeks of 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
Maakt een verbinding met SQLite. Schakelt automatisch foreign keys in via PRAGMA foreign_keys = ON.
$connection = Connection::sqlite('/var/data/app.sqlite');
$connection = Connection::sqlite(':memory:');
fromDsn(string $dsn, string $username = '', string $password = ''): PdoDatabaseConnection
Maak verbinding met een PDO DSN-tekenreeks. merql bevat alleen drivers voor mysql en sqlite; andere DSN's openen wel een verbinding, maar Merql::init(), Snapshotter en de appliers geven Unsupported database driver, tenzij er een driver is geregistreerd met DriverFactory::register().
$connection = Connection::fromDsn('mysql:host=localhost;dbname=app', 'root', 'pass');
fromPdo(PDO $pdo): PdoDatabaseConnection
Wikkel een bestaande PDO-instantie in.
fromMysqli(mysqli $mysqli, string $charset = 'utf8mb4'): MysqliDatabaseConnection
Wikkel een bestaande mysqli-instantie in.
Adaptercontract
Alle adapters implementeren 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() en scalar() accepteren positionele list<scalar|null>-parameters voor ?-placeholders. query() geeft list<array<string, scalar|null>> terug; waarden worden in PDO- en mysqli-adapters genormaliseerd naar dezelfde vorm van tekenreeks of null.
Snapshotter
Merql\Snapshot\Snapshotter legt de databasestatus vast. In tegenstelling tot de facade geeft deze u volledige controle over filters en slaat hij niets automatisch op.
__construct(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null)
Als de driver niet is opgegeven, wordt deze automatisch gedetecteerd op basis van de verbindingsidentiteit. Geef een IdentityRuleSet mee als de rij-identiteit per tabel de schemastandaarden moet overschrijven.
capture(string $name, array $tables = [], array $filters = []): Snapshot
Leg de huidige status vast. Geef tabelnamen mee om het bereik te beperken. Geef filterobjecten mee om tabellen, kolommen of rijen uit te sluiten.
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
Leg fysieke tabellen vast onder canonieke tabelnamen. Gebruik dit wanneer dezelfde logische tabel in verschillende omgevingen andere fysieke namen heeft.
$snapshot = $snapshotter->captureAliased('sandbox', [
'wp_onumia_abcd_posts' => 'wp_posts',
'wp_onumia_abcd_postmeta' => 'wp_postmeta',
]);
De resulterende snapshot slaat canonieke tabelnamen op en behoudt tegelijk het fysieke tabelschema, de geconfigureerde identiteitskolommen, rijsleutels en filters.
fromData(string $name, array $tableData): Snapshot (statisch)
Bouw een snapshot op basis van ruwe gegevens zonder databaseverbinding. Handig voor tests of bij het importeren van gegevens uit een andere bron.
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']),
]);
Snapshot
Merql\Snapshot\Snapshot is een alleen-lezen waardeobject dat een volledige databasestatus vertegenwoordigt.
$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 bevat de rijen, fingerprints en het schema van één tabel.
$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 is invoergegevens voor 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 definieert de kolommen waarmee rijsleutels worden opgebouwd.
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 (statisch)
Bepaal de standaardidentiteitsregel op basis van het schema: primaire sleutel, eerste unieke sleutel, daarna terugval op inhoud.
toArray(): array
Serialiseer de regel als ['type' => string, 'columns' => list<string>].
fromArray(array $data): IdentityRule (statisch)
Herstel een regel vanuit geserialiseerde gegevens.
IdentityRuleSet
Merql\Identity\IdentityRuleSet slaat identiteitsoverschrijvingen per tabel op.
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
Geeft een nieuwe regelset terug met een toegevoegde tabeloverschrijving.
conflictsFor(string $table, IdentityRule $rule, array $rows): array
Geef IdentityConflict-items terug als meerdere rijen voor een regel dezelfde sleutel opleveren.
toArray(): array
Serialiseer tabelregels als een JSON-veilige array.
fromArray(array $data): IdentityRuleSet (statisch)
Herstel een regelset vanuit geserialiseerde gegevens.
SnapshotStore
Merql\Snapshot\SnapshotStore slaat snapshots op en laadt ze als JSON-bestanden.
setDirectory(string $directory): void
Stel de opslagmap in. De standaard is .merql/snapshots.
save(Snapshot $snapshot): void
Schrijf een snapshot naar schijf.
load(string $name): Snapshot
Laad een snapshot op naam. Geeft SnapshotException als deze niet is gevonden.
exists(string $name): bool
Controleer of een snapshotbestand bestaat.
delete(string $name): void
Verwijder een snapshotbestand.
Differ
Merql\Diff\Differ vergelijkt twee snapshots en maakt een wijzigingsset.
diff(Snapshot $base, Snapshot $current): Changeset
use Merql\Diff\Differ;
$differ = new Differ();
$changeset = $differ->diff($baseSnapshot, $currentSnapshot);
valuesEqual(mixed $a, mixed $b): bool (statisch)
Vergelijk twee waarden door ze naar tekenreeksen om te zetten. NULL wordt als een afzonderlijke waarde behandeld: NULL === NULL is waar, NULL === '' is onwaar.
Wijzigingsset
Merql\Diff\Changeset is een alleen-lezen verzameling bewerkingen op rijniveau.
$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
Alleen-lezen waardeobjecten die afzonderlijke rijwijzigingen vertegenwoordigen.
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 vertegenwoordigt één kolomwijziging binnen een rij-update.
$diff->column; // string
$diff->oldValue; // mixed
$diff->newValue; // mixed
ThreeWayMerge
Merql\Merge\ThreeWayMerge is het kernalgoritme voor samenvoegen.
__construct(?CellMergeConfig $cellMergeConfig = null)
Geef een CellMergeConfig mee om samenvoegen op celniveau in te schakelen voor TEXT- en JSON-kolommen.
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
Voer een three-way merge uit. Berekent intern wijzigingssets (van basis naar ours en van basis naar theirs) en voegt deze samen.
$result = $merge->merge($baseSnapshot, $oursSnapshot, $theirsSnapshot);
patch(Snapshot $base, Snapshot $changes): MergeResult
Snelkoppeling voor two-way merge. Gelijk aan merge($base, $base, $changes).
schemaMismatches(): array
Geeft SchemaException[] terug voor schemawijzigingen die tijdens de laatste merge zijn gevonden (kolommen die tussen snapshots zijn toegevoegd of verwijderd).
MergeResult
Merql\Merge\MergeResult is een alleen-lezen waardeobject met de uitkomst van de merge.
$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 is een serialiseerbaar reviewmodel voor een merge.
$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>
Gebruik MergePlanSerializer::toJson() en ::fromJson() voor stabiele JSON-roundtrips.
Selecties
ChangeGroupSelection slaat gefaseerde wijzigingsgroep-ID's op. Zet deze om in een OperationSelection bij het bouwen van geselecteerde mergeresultaten of terugdraaiplannen.
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 slaat inverse bewerkingen en verwachtingen voor afwijkingen op voor een geselecteerde toepassing.
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Rollback\RollbackPlanSerializer;
$rollback = (new RollbackPlanBuilder())->build(
'rollback-1',
$plan,
$operationSelection,
$liveBeforeRows,
);
$json = RollbackPlanSerializer::toJson($rollback);
Gebruik RollbackDrift voordat u een terugdraaiing toepast en vervolgens RollbackPlanApplier om de inverse bewerkingen uit te voeren.
MergeOperation
Merql\Merge\MergeOperation is één opgeloste bewerking uit de merge.
$op->type; // string: 'insert' | 'update' | 'delete'
$op->table; // string
$op->rowKey; // string
$op->values; // array<string, mixed>
$op->source; // string: 'ours' | 'theirs' | 'merged'
Typeconstanten:
MergeOperation::TYPE_INSERT; // 'insert'
MergeOperation::TYPE_UPDATE; // 'update'
MergeOperation::TYPE_DELETE; // 'delete'
Conflict
Merql\Merge\Conflict vertegenwoordigt een onopgelost mergeconflict.
$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
Conflicttypen
| Type | Betekenis |
|---|---|
update_update |
Beide zijden hebben dezelfde kolom gewijzigd in verschillende waarden |
update_delete |
Ours heeft een rij bijgewerkt die door theirs is verwijderd |
delete_update |
Ours heeft een rij verwijderd die door theirs is bijgewerkt |
insert_insert |
Beide zijden hebben een rij ingevoegd met dezelfde primaire sleutel |
ConflictResolver
Merql\Merge\ConflictResolver past een oplossingsbeleid toe op alle conflicten in een mergeresultaat.
resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (statisch)
Geeft een nieuwe MergeResult terug waarin conflicten volgens het beleid zijn opgelost.
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 is een backed enum met drie gevallen.
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 voert merge-logica per kolom uit voor één rij. Wordt intern gebruikt door ThreeWayMerge.
merge(string $table, string $rowKey, array $base, array $ours, array $theirs, ?CellMergeConfig $cellMergeConfig = null, array $columnTypes = []): array (statisch)
Geeft ['values' => array, 'conflicts' => list<Conflict>] terug.
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)
Applier
Merql\Apply\Applier voert een mergeresultaat uit op een database.
__construct(DatabaseConnection $connection, ?Driver $driver = null)
apply(MergeResult $result, ?Snapshot $base = null): ApplyResult
Voert alle bewerkingen uit in één transactie. Maakt de transactie bij elke fout ongedaan en rapporteert de fout in ApplyResult::errors() in plaats van deze op te werpen. Geeft ConflictException als het resultaat onopgeloste conflicten bevat.
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());
}
De volgorde op basis van foreign keys wordt automatisch afgehandeld: invoegingen worden gesorteerd op afhankelijkheden en verwijderingen in omgekeerde volgorde van afhankelijkheden.
ApplyResult
Merql\Apply\ApplyResult is een alleen-lezen waardeobject dat door de applier wordt teruggegeven.
$applied->rowsAffected(); // int
$applied->errors(); // list<string>
$applied->hasErrors(); // bool
Na een teruggedraaide toepassing telt rowsAffected() nog steeds de instructies die vóór de fout zijn uitgevoerd (#4). Controleer hasErrors() voordat u op het aantal vertrouwt.
DryRun
Merql\Apply\DryRun genereert leesbare SQL zonder iets uit te voeren.
generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statisch)
Geeft een lijst met tekenreeksen van SQL terug, met ingesloten waarden (alleen voor weergave).
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 genereert geparametriseerde SQL-instructies. Wordt intern gebruikt door zowel Applier als DryRun.
generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statisch)
Geeft list<array{sql: string, params: list<scalar|null>}> terug.
use Merql\Apply\SqlGenerator;
$statements = SqlGenerator::generate($result);
foreach ($statements as $stmt) {
$connection->execute($stmt['sql'], $stmt['params']);
}
CellMergeConfig
Merql\CellMerge\CellMergeConfig configureert samenvoegstrategieën op celniveau voor specifieke kolommen of kolomtypen.
auto(): self (statisch)
Handige factory die TextCellMerger toewijst aan TEXT/LONGTEXT-kolommen en JsonCellMerger aan JSON-kolommen.
use Merql\CellMerge\CellMergeConfig;
$config = CellMergeConfig::auto();
forColumn(string $column, CellMerger $merger): self
Wijs een merger toe aan een specifieke kolom. Gebruik table.column voor gekwalificeerde namen of alleen column voor alle tabellen.
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
Wijs een merger toe aan alle kolommen die overeenkomen met een typepatroon (niet-hoofdlettergevoelige overeenkomst op basis van een substring).
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
$config = (new CellMergeConfig())
->forType('json', new JsonCellMerger());
getMerger(string $table, string $column, string $columnType = ''): CellMerger
Zoek de merger op voor een tabel, kolom en type. Prioriteit: gekwalificeerde kolomnaam, niet-gekwalificeerde kolomnaam, typepatroon, standaard (ondoorzichtig).
CellMerger (interface)
Merql\CellMerge\CellMerger is de interface voor samenvoegstrategieën op celniveau.
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;
interface CellMerger
{
public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult;
}
Er zijn drie ingebouwde implementaties beschikbaar.
TextCellMerger
Merql\CellMerge\TextCellMerger voegt tekst over meerdere regels samen met een driewegvergelijking per regel (hetzelfde algoritme dat git gebruikt voor bestandsinhoud). Als beide kanten verschillende regels bewerken, verloopt het samenvoegen probleemloos. Als beide kanten dezelfde regel op verschillende manieren bewerken, wordt een conflict gemeld.
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 voegt JSON-waarden samen door de hoofdsleutels afzonderlijk te vergelijken. Elke sleutel wordt samengevoegd met three-way-logica. Geneste objecten worden als ondoorzichtige JSON-tekenreeksen vergeleken (ze worden niet recursief samengevoegd).
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 is de standaard. Deze behandelt waarden als ondoorzichtige tekenreeksen en meldt altijd een conflict als ze verschillen.
CellMergeResult
Merql\CellMerge\CellMergeResult is het retourtype van alle celmergers.
$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 is een alleen-lezen weergave van de tabelstructuur.
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>
Driversysteem
merql gebruikt een uitbreidbaar driversysteem om databasespecifieke bewerkingen te abstraheren. Drivers worden automatisch gedetecteerd op basis van de driveridentiteit van de verbinding.
Driver (interface)
Merql\Driver\Driver definieert het contract dat alle databasestuurprogramma's implementeren.
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;
}
Ingebouwde implementaties: MysqlDriver en SqliteDriver.
DriverFactory
Merql\Driver\DriverFactory detecteert de driver automatisch op basis van een verbinding.
use Merql\Driver\DriverFactory;
$driver = DriverFactory::create($connection);
Registreer een aangepaste driver voor andere databases:
DriverFactory::register('pgsql', MyPostgresDriver::class);
Filters
TableFilter
Merql\Filter\TableFilter voegt tabellen toe of sluit ze uit met glob-patronen.
use Merql\Filter\TableFilter;
$filter = TableFilter::exclude(['cache_*', 'sessions', 'temp_*']);
$filter = TableFilter::include(['posts', 'users', 'comments']);
ColumnFilter
Merql\Filter\ColumnFilter verwijdert specifieke kolommen uit snapshots.
use Merql\Filter\ColumnFilter;
$filter = ColumnFilter::ignore(['updated_at', 'created_at', 'modified_date']);
RowFilter
Merql\Filter\RowFilter filtert rijen met een predicaatfunctie.
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;
});
Uitzonderingen
SnapshotException
Merql\Exceptions\SnapshotException wordt opgegooid wanneer een snapshot niet kan worden gevonden of een ongeldige naam heeft.
SnapshotException::notFound('baseline', '/path/to/baseline.json');
MergeException
Merql\Exceptions\MergeException wordt opgegooid wanneer voor een merge een vereiste snapshot ontbreekt.
MergeException::snapshotRequired('base');
ConflictException
Merql\Exceptions\ConflictException wordt opgegooid wanneer een mergeresultaat met onopgeloste conflicten wordt toegepast.
ConflictException::unresolved(3);
// Message: "Cannot apply merge with 3 unresolved conflict(s)"
SchemaException
Merql\Exceptions\SchemaException wordt opgegooid (of verzameld) wanneer schema's tussen snapshots verschillen.
SchemaException::mismatch('posts', 'column "tags" exists in current but not in base');
Schemamismatches stoppen de merge niet. Ze worden verzameld en zijn beschikbaar via $result->schemaMismatches() ter inspectie.