PHP API Dokumentacja referencyjna
Pełna dokumentacja wszystkich publicznych klas i metod w merql.
Merql (fasada)
Merql\Merql to statyczny punkt wejścia do typowych operacji. Opakowuje klasy niższego poziomu i automatycznie zarządza trwałym zapisem migawek.
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
Zainicjuj fasadę, przekazując połączenie z bazą danych. Należy wywołać tę metodę przed
snapshot(), apply() lub applyGuarded(); wywołaj ją ponownie, aby przełączyć bazy danych,
na przykład w celu utworzenia migawek naszej i ich strony z dwóch różnych kopii. Bez
$driver metoda wywołuje DriverFactory::create(), które zgłasza wyjątek dla silników innych
niż MySQL i SQLite, chyba że zarejestrowano sterownik. Przekaż sterownik, aby zastąpić automatyczne wykrywanie, albo zestaw reguł tożsamości, aby zastąpić tożsamość wierszy dla poszczególnych tabel podczas przechwytywania migawki.
snapshot(string $name, array $tables = []): Snapshot
Przechwyć bieżący stan bazy danych i zapisz go na dysku. Przekaż tablicę nazw tabel, aby utworzyć migawki wybranych tabel, albo pomiń ten argument, aby uwzględnić wszystkie tabele.
$snapshot = Merql::snapshot('baseline');
$snapshot = Merql::snapshot('baseline', ['posts', 'users']);
diff(string $base, string $current): Changeset
Wczytaj dwie nazwane migawki i oblicz między nimi zestaw zmian. Nie wymaga init(), ponieważ korzysta z zapisanych migawek.
$changeset = Merql::diff('before', 'after');
merge(string $base, string $ours, string $theirs): MergeResult
Scal trzy nazwane migawki. Zwraca wynik zawierający czyste operacje i ewentualne konflikty. Scala na poziomie kolumn: fasada tworzy ThreeWayMerge bez CellMergeConfig, więc scalanie na poziomie komórek nie jest stosowane. W tym celu użyj bezpośrednio ThreeWayMerge.
$result = Merql::merge('base', 'ours', 'theirs');
patch(string $base, string $changes): MergeResult
Scalanie dwukierunkowe: zastosuj zmiany do bazy. Równoważne merge($base, $base, $changes). Zawsze daje czysty wynik, ponieważ nie ma równoczesnych edycji. Tylko na poziomie kolumn, podobnie jak merge().
$result = Merql::patch('base', 'changes');
apply(MergeResult $result): ApplyResult
Wykonaj czysty wynik scalania na bazie danych przekazanej do init(). Wymaga init(). Zgłasza ConflictException, jeśli pozostają nierozwiązane konflikty.
Wykonywana jest każda operacja z wyniku, więc pełny wynik merge() można zastosować bez konfliktów tylko do bazy danych, która nadal zawiera stan bazowy. Jeśli baza zawiera już stan jednej ze stron, zastosuj wybrane operacje, których jej brakuje; zobacz Guarded Apply.
$applied = Merql::apply($result);
echo $applied->rowsAffected();
plan(string $id, string $base, string $ours, string $theirs, array $metadata = []): MergePlan
Utwórz plan scalania gotowy do UI na podstawie trzech nazwanych migawek. Plan obejmuje stabilne
identyfikatory operacji, identyfikatory grup zmian, kontekst operacji, konflikty, niezgodności schematów,
podsumowanie, metadane i skrót planu. Scalanie odbywa się na poziomie kolumn, jak
w merge(); przekaż wynik scalony na poziomie komórek do MergePlanBuilder::build(), aby
scalić na poziomie komórek.
$plan = Merql::plan('plan-1', 'base', 'ours', 'theirs', [
'source' => 'review-ui',
]);
applyGuarded(MergeResult $result, Snapshot $expectedLive): ApplyResult
Zastosuj czysty wynik scalania z optymistycznymi warunkami wstępnymi dla aktywnych wierszy. Aktualizacje i
usunięcia wymagają, aby bieżące aktywne wiersze odpowiadały $expectedLive; w przypadku wstawień
wymagane jest, aby docelowa tożsamość jeszcze nie istniała. $expectedLive to migawka
docelowej bazy danych (ich strony, gdy przenosimy naszą stronę do bazy, z której
utworzono ich migawkę). Każda instrukcja, która zmieni zero wierszy, powoduje wycofanie transakcji.
use Merql\Snapshot\SnapshotStore;
$applied = Merql::applyGuarded($selectedResult, SnapshotStore::load('theirs'));
reset(): void
Wyczyść wewnętrzne instancje połączenia i modułu Snapshotter. Służy głównie do resetowania stanu między uruchomieniami testów.
Połączenie
Merql\Connection tworzy adaptery połączeń z rozsądnymi ustawieniami domyślnymi. Połączenia PDO zgłaszają wyjątki w razie błędu, używają asocjacyjnego trybu pobierania, wyłączają emulowane przygotowywanie zapytań i zwracają pobrane wartości jako ciągi znaków. Adapter mysqli normalizuje pobrane wartości do takiej samej postaci ciągu znaków lub 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
Tworzy połączenie SQLite. Automatycznie włącza klucze obce za pomocą PRAGMA foreign_keys = ON.
$connection = Connection::sqlite('/var/data/app.sqlite');
$connection = Connection::sqlite(':memory:');
fromDsn(string $dsn, string $username = '', string $password = ''): PdoDatabaseConnection
Nawiąż połączenie, używając dowolnego ciągu DSN PDO. merql zawiera sterowniki tylko dla mysql i sqlite; inne DSN nawiązują połączenie, ale Merql::init(), Snapshotter i moduły stosujące zmiany zgłaszają Unsupported database driver, chyba że sterownik został zarejestrowany przez DriverFactory::register().
$connection = Connection::fromDsn('mysql:host=localhost;dbname=app', 'root', 'pass');
fromPdo(PDO $pdo): PdoDatabaseConnection
Opakuj istniejącą instancję PDO.
fromMysqli(mysqli $mysqli, string $charset = 'utf8mb4'): MysqliDatabaseConnection
Opakuj istniejącą instancję mysqli.
Kontrakt adaptera
Wszystkie adaptery 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() i scalar() przyjmują pozycyjne parametry list<scalar|null>
dla symboli zastępczych ?. query() zwraca
list<array<string, scalar|null>>; wartości są normalizowane do takiej samej
postaci ciągu znaków lub null przez adaptery PDO i mysqli.
Snapshotter
Merql\Snapshot\Snapshotter przechwytuje stan bazy danych. W przeciwieństwie do fasady daje pełną kontrolę nad filtrami i nie zapisuje danych automatycznie.
__construct(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null)
Jeśli nie podano sterownika, jest on automatycznie wykrywany na podstawie tożsamości połączenia. Przekaż
IdentityRuleSet, gdy tożsamość wierszy dla poszczególnych tabel ma zastępować domyślne ustawienia schematu.
capture(string $name, array $tables = [], array $filters = []): Snapshot
Przechwyć bieżący stan. Podaj nazwy tabel, aby ograniczyć zakres. Przekaż obiekty filtrów, aby wykluczyć tabele, kolumny lub wiersze.
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
Przechwytuj tabele fizyczne pod kanonicznymi nazwami tabel. Użyj tego, gdy ta sama tabela logiczna ma różne nazwy fizyczne w poszczególnych środowiskach.
$snapshot = $snapshotter->captureAliased('sandbox', [
'wp_onumia_abcd_posts' => 'wp_posts',
'wp_onumia_abcd_postmeta' => 'wp_postmeta',
]);
Wynikowa migawka przechowuje kanoniczne nazwy tabel, zachowując schemat fizycznej tabeli, skonfigurowane kolumny tożsamości, klucze wierszy i filtry.
fromData(string $name, array $tableData): Snapshot (statyczna)
Utwórz migawkę z surowych danych bez połączenia z bazą danych. Przydatne do testów lub importowania danych z innego źródła.
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']),
]);
Migawka
Merql\Snapshot\Snapshot to obiekt wartości tylko do odczytu, reprezentujący kompletny stan bazy danych.
$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 zawiera wiersze, odciski palców i schemat jednej tabeli.
$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 to dane wejściowe dla 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 określa kolumny używane do budowania kluczy wierszy.
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 (statyczna)
Rozpoznaj domyślną regułę tożsamości ze schematu: klucz główny, pierwszy klucz unikatowy, a następnie zapasowo zawartość.
toArray(): array
Serializuj regułę jako ['type' => string, 'columns' => list<string>].
fromArray(array $data): IdentityRule (statyczna)
Odtwórz regułę z zserializowanych danych.
IdentityRuleSet
Merql\Identity\IdentityRuleSet przechowuje zastąpienia tożsamości dla poszczególnych tabel.
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
Zwróć nowy zestaw reguł z dodanym zastąpieniem dla jednej tabeli.
conflictsFor(string $table, IdentityRule $rule, array $rows): array
Zwraca wpisy IdentityConflict, gdy wiele wierszy dla danej reguły daje ten sam klucz.
toArray(): array
Serializuj reguły tabel jako tablicę bezpieczną dla JSON.
fromArray(array $data): IdentityRuleSet (statyczna)
Odtwórz zestaw reguł z zserializowanych danych.
SnapshotStore
Merql\Snapshot\SnapshotStore zapisuje i wczytuje migawki jako pliki JSON.
setDirectory(string $directory): void
Ustaw katalog przechowywania. Domyślnie jest to .merql/snapshots.
save(Snapshot $snapshot): void
Zapisz migawkę na dysku.
load(string $name): Snapshot
Wczytaj migawkę według nazwy. Zgłasza SnapshotException, jeśli nie znaleziono pliku.
exists(string $name): bool
Sprawdź, czy plik migawki istnieje.
delete(string $name): void
Usuń plik migawki.
Differ
Merql\Diff\Differ porównuje dwie migawki i tworzy zestaw zmian.
diff(Snapshot $base, Snapshot $current): Changeset
use Merql\Diff\Differ;
$differ = new Differ();
$changeset = $differ->diff($baseSnapshot, $currentSnapshot);
valuesEqual(mixed $a, mixed $b): bool (statyczna)
Porównaj dwie wartości po konwersji do ciągu znaków. NULL jest traktowane jako odrębna wartość: NULL === NULL to prawda, NULL === '' to fałsz.
Zestaw zmian
Merql\Diff\Changeset to kolekcja operacji na poziomie wierszy, tylko do odczytu.
$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
Obiekty wartości tylko do odczytu reprezentujące pojedyncze zmiany wierszy.
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 reprezentuje pojedynczą zmianę kolumny w ramach aktualizacji wiersza.
$diff->column; // string
$diff->oldValue; // mixed
$diff->newValue; // mixed
ThreeWayMerge
Merql\Merge\ThreeWayMerge to główny algorytm scalania.
__construct(?CellMergeConfig $cellMergeConfig = null)
Przekaż CellMergeConfig, aby włączyć scalanie na poziomie komórek dla kolumn TEXT i 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
Wykonaj scalanie trójstronne. Wewnętrznie oblicza zestawy zmian (od stanu bazowego do naszej strony i od stanu bazowego do ich strony), a następnie je scala.
$result = $merge->merge($baseSnapshot, $oursSnapshot, $theirsSnapshot);
patch(Snapshot $base, Snapshot $changes): MergeResult
Skrót do scalania dwukierunkowego. Równoważne merge($base, $base, $changes).
schemaMismatches(): array
Zwraca SchemaException[] dla wszelkich różnic schematu wykrytych podczas ostatniego scalania (kolumn dodanych lub usuniętych między migawkami).
MergeResult
Merql\Merge\MergeResult to obiekt wartości tylko do odczytu zawierający wynik scalania.
$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 to serializowalny model przeglądu scalania.
$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>
Użyj MergePlanSerializer::toJson() i ::fromJson(), aby zapewnić stabilną obsługę konwersji JSON w obie strony.
Wybory
ChangeGroupSelection przechowuje identyfikatory przygotowanych grup zmian. Przekształć go w
OperationSelection podczas tworzenia wybranych wyników scalania lub planów wycofania.
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 przechowuje operacje odwrotne i oczekiwania dotyczące rozbieżności
przy wybranym zastosowaniu zmian.
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Rollback\RollbackPlanSerializer;
$rollback = (new RollbackPlanBuilder())->build(
'rollback-1',
$plan,
$operationSelection,
$liveBeforeRows,
);
$json = RollbackPlanSerializer::toJson($rollback);
Użyj RollbackDrift przed zastosowaniem wycofania, a następnie RollbackPlanApplier, aby uruchomić
operacje odwrotne.
MergeOperation
Merql\Merge\MergeOperation to pojedyncza, rozstrzygnięta operacja scalania.
$op->type; // string: 'insert' | 'update' | 'delete'
$op->table; // string
$op->rowKey; // string
$op->values; // array<string, mixed>
$op->source; // string: 'ours' | 'theirs' | 'merged'
Stałe typów:
MergeOperation::TYPE_INSERT; // 'insert'
MergeOperation::TYPE_UPDATE; // 'update'
MergeOperation::TYPE_DELETE; // 'delete'
Konflikt
Merql\Merge\Conflict reprezentuje nierozwiązany konflikt scalania.
$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ów
| Typ | Znaczenie |
|---|---|
update_update |
Obie strony zmieniły tę samą kolumnę na różne wartości |
update_delete |
Nasza strona zaktualizowała wiersz, który ich strona usunęła |
delete_update |
Nasza strona usunęła wiersz, który ich strona zaktualizowała |
insert_insert |
Obie strony wstawiły wiersz z tym samym kluczem głównym |
ConflictResolver
Merql\Merge\ConflictResolver stosuje zasady rozstrzygania do wszystkich konfliktów w wyniku scalania.
resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (statyczna)
Zwraca nowy obiekt MergeResult z konfliktami rozwiązanymi zgodnie z przyjętą zasadą.
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 to wyliczenie bazowe z trzema przypadkami.
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 wykonuje logikę scalania dla poszczególnych kolumn w jednym wierszu. Jest wewnętrznie używany przez ThreeWayMerge.
merge(string $table, string $rowKey, array $base, array $ours, array $theirs, ?CellMergeConfig $cellMergeConfig = null, array $columnTypes = []): array (statyczna)
Zwraca ['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)
Applier
Merql\Apply\Applier wykonuje wynik scalania na bazie danych.
__construct(DatabaseConnection $connection, ?Driver $driver = null)
apply(MergeResult $result, ?Snapshot $base = null): ApplyResult
Wykonuje wszystkie operacje w ramach jednej transakcji. W razie błędu wycofuje transakcję i zgłasza go w ApplyResult::errors() zamiast rzucać wyjątek. Zgłasza ConflictException, jeśli wynik zawiera nierozwiązane konflikty.
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());
}
Kolejność kluczy obcych jest obsługiwana automatycznie: wstawienia są sortowane według zależności, a usunięcia w odwrotnej kolejności zależności.
ApplyResult
Merql\Apply\ApplyResult to obiekt wartości tylko do odczytu zwracany przez moduł stosujący zmiany.
$applied->rowsAffected(); // int
$applied->errors(); // list<string>
$applied->hasErrors(); // bool
Po wycofaniu zastosowania zmian rowsAffected() nadal zlicza instrukcje wykonane przed błędem (#4). Przed uznaniem tej liczby za wiarygodną sprawdź hasErrors().
DryRun
Merql\Apply\DryRun generuje czytelne dla człowieka instrukcje SQL bez wykonywania czegokolwiek.
generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statyczna)
Zwraca listę ciągów SQL z wstawionymi wartościami (wyłącznie do wyświetlania).
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 generuje parametryzowane instrukcje SQL. Jest wewnętrznie używany zarówno przez Applier, jak i DryRun.
generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (statyczna)
Zwraca 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 scalania komórek dla określonych kolumn lub typów kolumn.
auto(): self (statyczna)
Fabryka ułatwiająca przypisanie TextCellMerger do kolumn TEXT/LONGTEXT oraz JsonCellMerger do kolumn JSON.
use Merql\CellMerge\CellMergeConfig;
$config = CellMergeConfig::auto();
forColumn(string $column, CellMerger $merger): self
Przypisz moduł scalający do konkretnej kolumny. Użyj table.column dla nazw kwalifikowanych albo samego column dla wszystkich tabel.
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
Przypisz mechanizm scalania do wszystkich kolumn pasujących do wzorca typu (dopasowanie podciągu bez rozróżniania wielkości liter).
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
$config = (new CellMergeConfig())
->forType('json', new JsonCellMerger());
getMerger(string $table, string $column, string $columnType = ''): CellMerger
Znajdź mechanizm scalania dla podanej tabeli, kolumny i typu. Priorytet: kwalifikowana nazwa kolumny, niekwalifikowana nazwa kolumny, wzorzec typu, wartość domyślna (nieprzezroczysta).
CellMerger (interfejs)
Merql\CellMerge\CellMerger to interfejs strategii scalania na poziomie komórek.
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;
interface CellMerger
{
public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult;
}
Dostępne są trzy wbudowane implementacje.
TextCellMerger
Merql\CellMerge\TextCellMerger scala tekst wielowierszowy za pomocą trójstronnego porównania wiersz po wierszu (tego samego algorytmu, którego git używa do zawartości plików). Gdy obie strony edytują różne wiersze, scalanie przebiega bez konfliktów. Gdy obie strony różnie edytują ten sam wiersz, zgłaszany jest 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 scala wartości JSON, porównując niezależnie klucze najwyższego poziomu. Każdy klucz jest scalany z użyciem logiki trójstronnej. Zagnieżdżone obiekty są porównywane jako nieprzezroczyste ciągi JSON (bez rekurencyjnego scalania).
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 jest wartością domyślną. Traktuje wartości jako nieprzezroczyste ciągi i zawsze zgłasza konflikt, gdy się różnią.
CellMergeResult
Merql\CellMerge\CellMergeResult to typ zwracany przez wszystkie mechanizmy scalania komórek.
$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 to reprezentacja struktury tabeli tylko do odczytu.
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>
System sterowników
merql używa rozszerzalnego systemu sterowników do abstrakcji operacji specyficznych dla baz danych. Sterowniki są wykrywane automatycznie na podstawie tożsamości sterownika połączenia.
Driver (interfejs)
Merql\Driver\Driver określa kontrakt, który implementują wszystkie sterowniki baz danych.
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;
}
Wbudowane implementacje: MysqlDriver i SqliteDriver.
DriverFactory
Merql\Driver\DriverFactory automatycznie wykrywa sterownik na podstawie połączenia.
use Merql\Driver\DriverFactory;
$driver = DriverFactory::create($connection);
Zarejestruj niestandardowy sterownik dla innych baz danych:
DriverFactory::register('pgsql', MyPostgresDriver::class);
Filtry
TableFilter
Merql\Filter\TableFilter uwzględnia tabele lub je wyklucza za pomocą wzorców glob.
use Merql\Filter\TableFilter;
$filter = TableFilter::exclude(['cache_*', 'sessions', 'temp_*']);
$filter = TableFilter::include(['posts', 'users', 'comments']);
ColumnFilter
Merql\Filter\ColumnFilter usuwa określone kolumny ze zrzutów.
use Merql\Filter\ColumnFilter;
$filter = ColumnFilter::ignore(['updated_at', 'created_at', 'modified_date']);
RowFilter
Merql\Filter\RowFilter filtruje wiersze za pomocą funkcji predykatu.
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;
});
Wyjątki
SnapshotException
Merql\Exceptions\SnapshotException jest zgłaszany, gdy nie można znaleźć zrzutu lub ma on nieprawidłową nazwę.
SnapshotException::notFound('baseline', '/path/to/baseline.json');
MergeException
Merql\Exceptions\MergeException jest zgłaszany, gdy do scalania brakuje wymaganego zrzutu.
MergeException::snapshotRequired('base');
ConflictException
Merql\Exceptions\ConflictException jest zgłaszany przy próbie zastosowania wyniku scalania z nierozwiązanymi konfliktami.
ConflictException::unresolved(3);
// Message: "Cannot apply merge with 3 unresolved conflict(s)"
SchemaException
Merql\Exceptions\SchemaException jest zgłaszany (lub gromadzony), gdy schematy różnią się między zrzutami.
SchemaException::mismatch('posts', 'column "tags" exists in current but not in base');
Niezgodności schematów nie zatrzymują scalania. Są gromadzone i dostępne do wglądu za pomocą $result->schemaMismatches().