Lewati ke konten

Referensi PHP API

Referensi lengkap untuk semua kelas dan metode publik di merql.

Merql (facade)

Merql\Merql adalah titik masuk statis untuk operasi umum. Komponen ini membungkus kelas tingkat rendah dan mengelola persistensi snapshot secara otomatis.

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

Inisialisasi facade dengan koneksi basis data. Harus dipanggil sebelum snapshot(), apply(), atau applyGuarded(); panggil lagi untuk berpindah basis data, misalnya untuk membuat snapshot sisi kita dan sisi mereka dari dua salinan berbeda. Tanpa $driver, komponen ini memanggil DriverFactory::create(), yang menghasilkan exception untuk mesin selain MySQL dan SQLite, kecuali driver telah didaftarkan. Berikan driver untuk mengganti deteksi otomatis, atau kumpulan aturan identitas untuk mengganti identitas baris per tabel saat pengambilan snapshot.

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

Ambil keadaan basis data saat ini dan simpan ke disk. Berikan array nama tabel untuk membuat snapshot tabel tertentu, atau abaikan parameter ini untuk menyertakan semua tabel.

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

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

Muat dua snapshot bernama dan hitung set perubahan di antara keduanya. init() tidak diperlukan karena operasi ini menggunakan snapshot yang telah disimpan.

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

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

Merge tiga arah atas tiga snapshot bernama. Mengembalikan hasil yang berisi operasi tanpa konflik dan konflik yang ditemukan. Merge dilakukan pada tingkat kolom: facade menyusun ThreeWayMerge tanpa CellMergeConfig, sehingga merge tingkat sel tidak diterapkan. Untuk itu, gunakan ThreeWayMerge secara langsung.

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

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

Merge dua arah: terapkan perubahan ke base. Setara dengan merge($base, $base, $changes). Hasilnya selalu bersih karena tidak ada pengeditan bersamaan. Hanya pada tingkat kolom, seperti merge().

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

apply(MergeResult $result): ApplyResult

Jalankan hasil merge tanpa konflik pada basis data yang diberikan ke init(). Memerlukan init(). Menghasilkan exception ConflictException jika masih ada konflik yang belum terselesaikan.

Setiap operasi dalam hasil akan dijalankan, sehingga seluruh hasil merge() hanya dapat diterapkan dengan bersih pada basis data yang masih berada dalam keadaan base. Untuk basis data yang sudah berisi salah satu sisi, terapkan pilihan operasi yang belum dimilikinya; lihat Penerapan dengan Pengamanan.

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

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

Bangun rencana merge siap untuk UI dari tiga snapshot bernama. Rencana ini mencakup ID operasi yang stabil, ID grup perubahan, konteks operasi, konflik, ketidakcocokan skema, ringkasan, metadata, dan hash rencana. Merge dilakukan pada tingkat kolom, seperti di merge(); berikan hasil merge tingkat sel ke MergePlanBuilder::build() untuk merge tingkat sel.

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

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

Terapkan hasil merge tanpa konflik dengan prasyarat optimistis pada baris aktif. Untuk pembaruan dan penghapusan, baris aktif saat ini harus cocok dengan $expectedLive; untuk penyisipan, identitas target tidak boleh sudah ada. $expectedLive adalah snapshot basis data target (sisi mereka, saat mempromosikan sisi kita ke basis data tempat snapshot sisi mereka dibuat). Pernyataan apa pun yang tidak mengubah baris akan me-rollback transaksi.

PHP
use Merql\Snapshot\SnapshotStore;

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

reset(): void

Hapus koneksi internal dan instance Snapshotter. Utamanya digunakan dalam pengujian untuk mengatur ulang status di antara proses.


Koneksi

Merql\Connection membangun adapter koneksi dengan default yang sesuai. Koneksi PDO menggunakan exception saat terjadi kesalahan, mode pengambilan asosiatif, prepared statement tanpa emulasi, dan hasil fetch dalam bentuk string. Adapter mysqli menormalkan nilai yang diambil ke bentuk string atau null yang sama.

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

Membuat koneksi SQLite. Mengaktifkan foreign key secara otomatis melalui PRAGMA foreign_keys = ON.

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

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

Hubungkan menggunakan string DSN PDO apa pun. merql menyediakan driver hanya untuk mysql dan sqlite; DSN lain dapat membuka koneksi, tetapi Merql::init(), Snapshotter, dan applier akan menghasilkan exception Unsupported database driver kecuali driver didaftarkan dengan DriverFactory::register().

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

fromPdo(PDO $pdo): PdoDatabaseConnection

Bungkus instance PDO yang sudah ada.

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

Bungkus instance mysqli yang sudah ada.

Kontrak adapter

Semua adapter mengimplementasikan 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(), dan scalar() menerima parameter posisi list<scalar|null> untuk placeholder ?. query() mengembalikan list<array<string, scalar|null>>; nilai dinormalisasi ke bentuk string atau null yang sama di seluruh adapter PDO dan mysqli.


Snapshotter

Merql\Snapshot\Snapshotter mengambil keadaan basis data. Berbeda dari facade, komponen ini memberi Anda kendali penuh atas filter dan tidak menyimpan data secara otomatis.

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

Driver dideteksi otomatis dari identitas koneksi jika tidak diberikan. Berikan IdentityRuleSet jika identitas baris khusus tabel perlu mengganti default skema.

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

Ambil keadaan saat ini. Berikan nama tabel untuk membatasi cakupan. Berikan objek filter untuk mengecualikan tabel, kolom, atau baris.

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

Ambil tabel fisik menggunakan nama tabel kanonis. Gunakan ini ketika tabel logis yang sama memiliki nama fisik berbeda di berbagai lingkungan.

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

Snapshot yang dihasilkan menyimpan nama tabel kanonis sekaligus mempertahankan skema tabel fisik, kolom identitas yang dikonfigurasi, kunci baris, dan filter.

fromData(string $name, array $tableData): Snapshot (statis)

Buat snapshot dari data mentah tanpa koneksi database. Berguna untuk pengujian atau saat mengimpor data dari sumber lain.

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

Snapshot

Merql\Snapshot\Snapshot adalah objek nilai hanya-baca yang merepresentasikan seluruh keadaan database.

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 menyimpan baris, sidik jari, dan skema dari satu tabel.

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 adalah data masukan untuk 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 menentukan kolom yang digunakan untuk membuat kunci baris.

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 (statis)

Menentukan aturan identitas default dari skema: kunci utama, kunci unik pertama, lalu fallback konten.

toArray(): array

Menyerialkan aturan sebagai ['type' => string, 'columns' => list<string>].

fromArray(array $data): IdentityRule (statis)

Memuat aturan dari data yang diserialkan.


IdentityRuleSet

Merql\Identity\IdentityRuleSet menyimpan penggantian identitas khusus tabel.

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

Mengembalikan kumpulan aturan baru dengan satu penggantian tabel yang ditambahkan.

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

Mengembalikan entri IdentityConflict ketika beberapa baris menghasilkan kunci yang sama untuk suatu aturan.

toArray(): array

Menyerialkan aturan tabel sebagai array yang aman untuk JSON.

fromArray(array $data): IdentityRuleSet (statis)

Memuat kumpulan aturan dari data yang diserialkan.


SnapshotStore

Merql\Snapshot\SnapshotStore menyimpan dan memuat snapshot sebagai file JSON.

setDirectory(string $directory): void

Atur direktori penyimpanan. Default-nya adalah .merql/snapshots.

save(Snapshot $snapshot): void

Tulis snapshot ke disk.

load(string $name): Snapshot

Muat snapshot berdasarkan nama. Melempar SnapshotException jika tidak ditemukan.

exists(string $name): bool

Periksa apakah file snapshot ada.

delete(string $name): void

Hapus file snapshot.


Differ

Merql\Diff\Differ membandingkan dua snapshot dan menghasilkan kumpulan perubahan.

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 (statis)

Bandingkan dua nilai dengan mengubahnya menjadi string. NULL diperlakukan sebagai nilai tersendiri: NULL === NULL bernilai true, NULL === '' bernilai false.


Changeset

Merql\Diff\Changeset adalah koleksi operasi tingkat baris yang hanya-baca.

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

Objek nilai hanya-baca yang merepresentasikan perubahan pada masing-masing baris.

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 merepresentasikan satu perubahan kolom dalam pembaruan baris.

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

ThreeWayMerge

Merql\Merge\ThreeWayMerge adalah algoritme penggabungan inti.

__construct(?CellMergeConfig $cellMergeConfig = null)

Teruskan CellMergeConfig untuk mengaktifkan penggabungan tingkat sel bagi kolom TEXT dan 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

Lakukan penggabungan tiga arah. Menghitung kumpulan perubahan secara internal (base ke milik kita, base ke milik mereka), lalu menggabungkannya.

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

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

Pintasan penggabungan dua arah. Setara dengan merge($base, $base, $changes).

schemaMismatches(): array

Mengembalikan SchemaException[] untuk setiap perbedaan skema yang terdeteksi selama penggabungan terakhir (kolom yang ditambahkan atau dihapus di antara snapshot).


MergeResult

Merql\Merge\MergeResult adalah objek nilai hanya-baca yang berisi hasil penggabungan.

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 adalah model tinjauan penggabungan yang dapat diserialkan.

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>

Gunakan MergePlanSerializer::toJson() dan ::fromJson() untuk roundtrip JSON yang stabil.

Selections

ChangeGroupSelection menyimpan ID grup perubahan yang dipentaskan. Ubah menjadi OperationSelection saat membuat hasil penggabungan terpilih atau rencana rollback.

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 menyimpan operasi invers dan ekspektasi penyimpangan untuk penerapan yang dipilih.

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

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

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

Gunakan RollbackDrift sebelum menerapkan rollback, lalu RollbackPlanApplier untuk menjalankan operasi invers.


MergeOperation

Merql\Merge\MergeOperation adalah satu operasi hasil resolusi dari penggabungan.

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

Konstanta tipe:

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

Conflict

Merql\Merge\Conflict merepresentasikan konflik penggabungan yang belum terselesaikan.

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

Jenis konflik

Jenis Makna
update_update Kedua sisi mengubah kolom yang sama menjadi nilai berbeda
update_delete Sisi kita memperbarui baris yang dihapus oleh sisi mereka
delete_update Sisi kita menghapus baris yang diperbarui oleh sisi mereka
insert_insert Kedua sisi menyisipkan baris dengan kunci utama yang sama

ConflictResolver

Merql\Merge\ConflictResolver menerapkan kebijakan resolusi ke semua konflik dalam hasil penggabungan.

resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (statis)

Mengembalikan MergeResult baru dengan konflik yang diselesaikan sesuai kebijakan.

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 adalah enum berbasis dengan tiga kasus.

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 menjalankan logika penggabungan per kolom untuk satu baris. Digunakan secara internal oleh ThreeWayMerge.

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

Mengembalikan ['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)

Applier

Merql\Apply\Applier menjalankan hasil penggabungan pada database.

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

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

Menjalankan semua operasi dalam satu transaksi. Melakukan rollback jika terjadi kesalahan dan melaporkannya di ApplyResult::errors() alih-alih melemparnya. Melempar ConflictException jika hasilnya memiliki konflik yang belum terselesaikan.

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

Urutan kunci asing ditangani secara otomatis: penyisipan diurutkan berdasarkan dependensi, penghapusan diurutkan menurut urutan dependensi terbalik.


ApplyResult

Merql\Apply\ApplyResult adalah objek nilai hanya-baca yang dikembalikan oleh applier.

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

Setelah penerapan yang di-rollback, rowsAffected() tetap menghitung pernyataan yang dijalankan sebelum kegagalan (#4). Periksa hasErrors() sebelum mengandalkan hitungan tersebut.


DryRun

Merql\Apply\DryRun menghasilkan SQL yang dapat dibaca manusia tanpa menjalankan apa pun.

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

Mengembalikan daftar string SQL dengan nilai yang disisipkan langsung (hanya untuk ditampilkan).

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 menghasilkan pernyataan SQL berparameter. Digunakan secara internal oleh Applier dan DryRun.

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

Mengembalikan 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 mengonfigurasi strategi penggabungan tingkat sel untuk kolom atau jenis kolom tertentu.

auto(): self (statis)

Fungsi pembuat praktis yang menetapkan TextCellMerger untuk kolom TEXT/LONGTEXT dan JsonCellMerger untuk kolom JSON.

PHP
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();

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

Tetapkan merger ke kolom tertentu. Gunakan table.column untuk nama berkualifikasi atau cukup column untuk semua tabel.

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

Tetapkan merger ke semua kolom yang cocok dengan pola jenis (pencocokan substring tanpa membedakan huruf besar-kecil).

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

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

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

Cari merger untuk tabel, kolom, dan jenis tertentu. Prioritas: nama kolom berkualifikasi, nama kolom tanpa kualifikasi, pola jenis, default (opaque).


CellMerger (antarmuka)

Merql\CellMerge\CellMerger adalah antarmuka untuk strategi penggabungan tingkat sel.

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

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

Tersedia tiga implementasi bawaan.

TextCellMerger

Merql\CellMerge\TextCellMerger menggabungkan teks multi-baris menggunakan diff tiga arah baris demi baris (algoritme yang sama dengan yang digunakan git untuk konten file). Jika kedua sisi mengedit baris yang berbeda, penggabungan berhasil tanpa konflik. Jika kedua sisi mengedit baris yang sama secara berbeda, konflik akan dilaporkan.

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 menggabungkan nilai JSON dengan membandingkan kunci tingkat atas secara terpisah. Setiap kunci digabungkan menggunakan logika tiga arah. Objek bertingkat dibandingkan sebagai string JSON opaque (tidak digabungkan secara rekursif).

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 adalah default. Nilai diperlakukan sebagai string opaque dan konflik selalu dilaporkan jika nilainya berbeda.


CellMergeResult

Merql\CellMerge\CellMergeResult adalah jenis nilai kembalian semua merger sel.

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 adalah representasi struktur tabel yang hanya-baca.

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>

Sistem driver

merql menggunakan sistem driver yang dapat dipasang untuk mengabstraksikan operasi khusus database. Driver dideteksi otomatis dari identitas driver koneksi.

Driver (antarmuka)

Merql\Driver\Driver menentukan kontrak yang diterapkan semua driver database.

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

Implementasi bawaan: MysqlDriver dan SqliteDriver.

DriverFactory

Merql\Driver\DriverFactory mendeteksi driver secara otomatis dari koneksi.

PHP
use Merql\Driver\DriverFactory;

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

Daftarkan driver khusus untuk database lain:

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

Filter

TableFilter

Merql\Filter\TableFilter menyertakan atau mengecualikan tabel menggunakan pola glob.

PHP
use Merql\Filter\TableFilter;

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

ColumnFilter

Merql\Filter\ColumnFilter menghapus kolom tertentu dari snapshot.

PHP
use Merql\Filter\ColumnFilter;

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

RowFilter

Merql\Filter\RowFilter memfilter baris menggunakan fungsi predikat.

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

Exception

SnapshotException

Merql\Exceptions\SnapshotException dilempar jika snapshot tidak dapat ditemukan atau namanya tidak valid.

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

MergeException

Merql\Exceptions\MergeException dilempar jika snapshot yang diperlukan untuk penggabungan tidak tersedia.

PHP
MergeException::snapshotRequired('base');

ConflictException

Merql\Exceptions\ConflictException dilempar saat mencoba menerapkan hasil penggabungan yang memiliki konflik belum terselesaikan.

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

SchemaException

Merql\Exceptions\SchemaException dilempar (atau dikumpulkan) jika skema berbeda di antara snapshot.

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

Ketidakcocokan skema tidak menghentikan penggabungan. Ketidakcocokan dikumpulkan dan dapat diperiksa melalui $result->schemaMismatches().