Vai al contenuto

Riferimento PHP API

Riferimento completo per tutte le classi e i metodi pubblici di merql.

Merql (facade)

Merql\Merql è il punto di accesso statico per le operazioni comuni. Avvolge le classi di livello inferiore e gestisce automaticamente la persistenza degli snapshot.

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

Inizializza la facade con una connessione al database. Deve essere chiamata prima di snapshot(), apply() o applyGuarded(); chiamala di nuovo per passare da un database all'altro, per esempio per acquisire snapshot di ours e theirs da due copie diverse. Senza una $driver, chiama DriverFactory::create(), che genera un'eccezione per motori diversi da MySQL e SQLite, a meno che non sia registrato un driver. Passa un driver per ignorare il rilevamento automatico oppure un insieme di regole di identità per specificare l'identità delle righe per tabella durante l'acquisizione dello snapshot.

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

Acquisisce lo stato attuale del database e lo salva su disco. Passa un array di nomi di tabella per acquisire snapshot di tabelle specifiche, oppure omettilo per includerle tutte.

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

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

Carica due snapshot con nome e calcola il changeset tra loro. Non richiede init() perché opera sugli snapshot salvati.

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

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

Fusione a tre vie di tre snapshot con nome. Restituisce un risultato con operazioni senza conflitti ed eventuali conflitti. Esegue la fusione a livello di colonna: la facade crea ThreeWayMerge senza CellMergeConfig, quindi non viene applicata la fusione a livello di cella. Per questo, usate direttamente ThreeWayMerge.

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

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

Unione a due vie: applica le modifiche alla base. Equivalente a merge($base, $base, $changes). Produce sempre un risultato pulito perché non ci sono modifiche concorrenti. Solo a livello di colonna, come merge().

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

apply(MergeResult $result): ApplyResult

Esegue un risultato di unione pulito sul database passato a init(). Richiede init(). Genera ConflictException se restano conflitti irrisolti.

Viene eseguita ogni operazione del risultato, quindi il risultato completo di merge() si applica correttamente solo a un database che conserva ancora lo stato di base. Se il database contiene già uno dei due lati, applicate una selezione delle operazioni che gli mancano; consultate Applicazione protetta.

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

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

Crea un piano di unione pronto per UI a partire da tre snapshot con nome. Il piano include ID operazione stabili, ID dei gruppi di modifiche, contesto delle operazioni, conflitti, incompatibilità dello schema, un riepilogo, metadati e un hash del piano. L'unione è a livello di colonna, come in merge(); passa un risultato unito a livello di cella a MergePlanBuilder::build() per un'unione a livello di cella.

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

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

Applica un risultato di unione pulito con precondizioni ottimistiche sulle righe correnti. Gli aggiornamenti e le eliminazioni richiedono che le righe correnti corrispondano a $expectedLive; per gli inserimenti è necessario che l'identità di destinazione non esista già. $expectedLive è uno snapshot del database di destinazione (quello di theirs, quando si promuove ours nel database da cui è stato acquisito theirs). Qualsiasi istruzione che non modifica righe provoca il rollback della transazione.

PHP
use Merql\Snapshot\SnapshotStore;

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

reset(): void

Azzera le istanze interne di connessione e Snapshotter. Viene usato principalmente nei test per ripristinare lo stato tra un'esecuzione e l'altra.


Connessione

Merql\Connection crea adattatori di connessione con impostazioni predefinite sensate. Le connessioni PDO usano eccezioni in caso di errore, modalità di fetch associativa, prepared statement non simulati e valori recuperati convertiti in stringhe. L'adattatore mysqli normalizza i valori recuperati allo stesso formato stringa o null.

mysql(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): PdoDatabaseConnection

PHP
use Merql\Connection;

$connection = Connection::mysql('127.0.0.1', 'my_app', 'root', 'secret');

mysqli(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): MysqliDatabaseConnection

PHP
$connection = Connection::mysqli('127.0.0.1', 'my_app', 'root', 'secret');

sqlite(string $path = ':memory:'): PdoDatabaseConnection

Crea una connessione SQLite. Abilita automaticamente le chiavi esterne tramite PRAGMA foreign_keys = ON.

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

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

Connettiti usando qualsiasi stringa DSN PDO. merql include driver solo per mysql e sqlite; gli altri DSN aprono una connessione, ma Merql::init(), Snapshotter e gli applier generano Unsupported database driver, a meno che non venga registrato un driver con DriverFactory::register().

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

fromPdo(PDO $pdo): PdoDatabaseConnection

Avvolge un'istanza PDO esistente.

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

Avvolge un'istanza mysqli esistente.

Contratto dell'adattatore

Tutti gli adattatori implementano 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() e scalar() accettano parametri list<scalar|null> posizionali per i segnaposto ?. query() restituisce list<array<string, scalar|null>>; i valori vengono normalizzati allo stesso formato stringa o null negli adattatori PDO e mysqli.


Snapshotter

Merql\Snapshot\Snapshotter acquisisce lo stato del database. A differenza della facciata, offre il pieno controllo sui filtri e non salva automaticamente.

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

Il driver viene rilevato automaticamente dall'identità della connessione, se non specificato. Passa un IdentityRuleSet quando l'identità di riga specifica della tabella deve prevalere sui valori predefiniti dello schema.

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

Acquisisce lo stato corrente. Passa i nomi delle tabelle per limitare l'ambito. Passa oggetti filtro per escludere tabelle, colonne o righe.

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

Acquisisce le tabelle fisiche usando i nomi canonici delle tabelle. Usalo quando la stessa tabella logica ha nomi fisici diversi tra ambienti.

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

Lo snapshot risultante memorizza i nomi canonici delle tabelle preservando lo schema fisico, le colonne d'identità configurate, le chiavi di riga e i filtri.

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

Crea uno snapshot da dati grezzi senza connessione al database. Utile per i test o quando si importano dati da un'altra origine.

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 è un oggetto valore di sola lettura che rappresenta uno stato completo del 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 contiene le righe, le impronte digitali e lo schema di una tabella.

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 è un dato di input per 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 definisce le colonne usate per creare le chiavi di riga.

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

Determina la regola d'identità predefinita dallo schema: chiave primaria, prima chiave univoca, poi fallback sul contenuto.

toArray(): array

Serializza la regola come ['type' => string, 'columns' => list<string>].

fromArray(array $data): IdentityRule (statico)

Idrata una regola da dati serializzati.


IdentityRuleSet

Merql\Identity\IdentityRuleSet memorizza sostituzioni dell'identità specifiche per tabella.

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

Restituisce un nuovo insieme di regole con una sostituzione per una tabella.

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

Restituisce le voci IdentityConflict quando più righe producono la stessa chiave per una regola.

toArray(): array

Serializza le regole delle tabelle in un array compatibile con JSON.

fromArray(array $data): IdentityRuleSet (statico)

Idrata un insieme di regole da dati serializzati.


SnapshotStore

Merql\Snapshot\SnapshotStore salva e carica snapshot come file JSON.

setDirectory(string $directory): void

Imposta la directory di archiviazione. Il valore predefinito è .merql/snapshots.

save(Snapshot $snapshot): void

Scrive uno snapshot su disco.

load(string $name): Snapshot

Carica uno snapshot per nome. Genera SnapshotException se non viene trovato.

exists(string $name): bool

Verifica se esiste un file snapshot.

delete(string $name): void

Rimuove un file snapshot.


Differ

Merql\Diff\Differ confronta due snapshot e produce un insieme di modifiche.

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

Confronta due valori convertendoli in stringhe. NULL viene trattato come valore distinto: NULL === NULL è vero, NULL === '' è falso.


Changeset

Merql\Diff\Changeset è una raccolta di sola lettura di operazioni a livello di riga.

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

Oggetti valore di sola lettura che rappresentano singole modifiche di riga.

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 rappresenta una singola modifica di colonna all'interno di un aggiornamento di riga.

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

ThreeWayMerge

Merql\Merge\ThreeWayMerge è l'algoritmo di unione principale.

__construct(?CellMergeConfig $cellMergeConfig = null)

Passa un CellMergeConfig per abilitare l'unione a livello di cella per le colonne TEXT e 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

Esegue un'unione a tre vie. Calcola internamente gli insiemi di modifiche (da base a ours, da base a theirs) e li unisce.

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

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

Scorciatoia per l'unione a due vie. Equivalente a merge($base, $base, $changes).

schemaMismatches(): array

Restituisce SchemaException[] per ogni differenza di schema rilevata durante l'ultima unione (colonne aggiunte o rimosse tra snapshot).


MergeResult

Merql\Merge\MergeResult è un oggetto valore di sola lettura che contiene l'esito dell'unione.

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 è un modello di revisione serializzabile per un'unione.

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>

Usa MergePlanSerializer::toJson() e ::fromJson() per roundtrip JSON stabili.

Selezioni

ChangeGroupSelection memorizza gli ID dei gruppi di modifiche preparati. Convertirlo in OperationSelection quando si creano risultati di unione selezionati o piani di 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 memorizza operazioni inverse e aspettative di deriva per un'applicazione selezionata.

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

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

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

Usa RollbackDrift prima di applicare il rollback, poi RollbackPlanApplier per eseguire le operazioni inverse.


MergeOperation

Merql\Merge\MergeOperation è una singola operazione risolta dell'unione.

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

Costanti di tipo:

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

Conflitto

Merql\Merge\Conflict rappresenta un conflitto di unione irrisolto.

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

Tipi di conflitto

Tipo Significato
update_update Entrambi i lati hanno modificato la stessa colonna assegnandole valori diversi
update_delete Ours ha aggiornato una riga che theirs ha eliminato
delete_update Ours ha eliminato una riga che theirs ha aggiornato
insert_insert Entrambi i lati hanno inserito una riga con la stessa chiave primaria

ConflictResolver

Merql\Merge\ConflictResolver applica una politica di risoluzione a tutti i conflitti in un risultato di unione.

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

Restituisce un nuovo MergeResult con i conflitti risolti secondo la politica.

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 è un'enum con tre casi.

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 esegue la logica di unione per colonna per una singola riga. Usato internamente da ThreeWayMerge.

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

Restituisce ['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 applica un risultato di unione a un database.

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

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

Esegue tutte le operazioni in un'unica transazione. Esegue il rollback in caso di errore e lo segnala in ApplyResult::errors() invece di generare un'eccezione. Genera ConflictException se il risultato contiene conflitti irrisolti.

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

L'ordine delle chiavi esterne viene gestito automaticamente: gli inserimenti sono ordinati in base alle dipendenze, le eliminazioni in ordine inverso.


ApplyResult

Merql\Apply\ApplyResult è un oggetto valore di sola lettura restituito dall'applier.

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

Dopo un'applicazione con rollback, rowsAffected() conta ancora le istruzioni eseguite prima dell'errore (#4). Verifica hasErrors() prima di considerare attendibile il conteggio.


DryRun

Merql\Apply\DryRun genera SQL leggibili senza eseguire alcuna operazione.

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

Restituisce un elenco di stringhe SQL con i valori interpolati (solo a scopo di visualizzazione).

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 genera istruzioni SQL parametrizzate. Usato internamente sia da Applier sia da DryRun.

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

Restituisce 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 configura strategie di unione a livello di cella per colonne specifiche o tipi di colonna.

auto(): self (statico)

Factory di utilità che assegna TextCellMerger alle colonne TEXT/LONGTEXT e JsonCellMerger alle colonne JSON.

PHP
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();

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

Assegna un merger a una colonna specifica. Usa table.column per nomi qualificati o solo column per tutte le tabelle.

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

Assegna un merger a tutte le colonne che corrispondono a un modello di tipo (corrispondenza di sottostringa senza distinzione tra maiuscole e minuscole).

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

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

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

Cerca il merger per una determinata tabella, colonna e tipo. Priorità: nome di colonna qualificato, nome di colonna non qualificato, modello di tipo, valore predefinito (opaque).


CellMerger (interfaccia)

Merql\CellMerge\CellMerger è l'interfaccia per le strategie di unione a livello di cella.

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

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

Sono fornite tre implementazioni integrate.

TextCellMerger

Merql\CellMerge\TextCellMerger unisce testo su più righe usando un diff a tre vie, riga per riga (lo stesso algoritmo che git usa per i contenuti dei file). Se i due lati modificano righe diverse, l'unione riesce senza conflitti. Se modificano la stessa riga in modo diverso, viene segnalato un conflitto.

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 unisce valori JSON confrontando le chiavi di primo livello in modo indipendente. Ogni chiave viene unita con una logica a tre vie. Gli oggetti annidati vengono confrontati come stringhe JSON opache (senza unione ricorsiva).

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 è il valore predefinito. Tratta i valori come stringhe opache e segnala sempre un conflitto quando differiscono.


CellMergeResult

Merql\CellMerge\CellMergeResult è il tipo restituito da tutti i merger di cella.

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 è una rappresentazione di sola lettura della struttura di una tabella.

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>

Sistema di driver

merql usa un sistema di driver collegabile per astrarre le operazioni specifiche del database. I driver vengono rilevati automaticamente dall'identità del driver della connessione.

Driver (interfaccia)

Merql\Driver\Driver definisce il contratto implementato da tutti i driver di 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;
}

Implementazioni integrate: MysqlDriver e SqliteDriver.

DriverFactory

Merql\Driver\DriverFactory rileva automaticamente il driver da una connessione.

PHP
use Merql\Driver\DriverFactory;

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

Registra un driver personalizzato per altri database:

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

Filtri

TableFilter

Merql\Filter\TableFilter include o esclude tabelle usando modelli glob.

PHP
use Merql\Filter\TableFilter;

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

ColumnFilter

Merql\Filter\ColumnFilter rimuove colonne specifiche dagli snapshot.

PHP
use Merql\Filter\ColumnFilter;

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

RowFilter

Merql\Filter\RowFilter filtra le righe usando una funzione predicato.

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

Eccezioni

SnapshotException

Merql\Exceptions\SnapshotException viene generata quando uno snapshot non viene trovato o ha un nome non valido.

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

MergeException

Merql\Exceptions\MergeException viene generata quando manca uno snapshot richiesto per un'unione.

PHP
MergeException::snapshotRequired('base');

ConflictException

Merql\Exceptions\ConflictException viene generata quando si tenta di applicare un risultato di unione che contiene conflitti irrisolti.

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

SchemaException

Merql\Exceptions\SchemaException viene generata (o raccolta) quando gli schemi differiscono tra snapshot.

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

Le incompatibilità dello schema non interrompono l'unione. Vengono raccolte e sono disponibili tramite $result->schemaMismatches() per l'analisi.