Pular para o conteúdo

Referência de PHP API

Referência completa de todas as classes e métodos públicos em merql.

Merql (fachada)

Merql\Merql é o ponto de entrada estático para operações comuns. Ele encapsula as classes de nível inferior e gerencia automaticamente a persistência dos snapshots.

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

Inicializa a fachada com uma conexão de banco de dados. Deve ser chamado antes de snapshot(), apply() ou applyGuarded(); chame-o novamente para trocar de banco, por exemplo, para criar snapshots de ours e theirs a partir de duas cópias diferentes. Sem um $driver, ele chama DriverFactory::create(), que gera uma exceção para mecanismos diferentes de MySQL e SQLite, a menos que um driver esteja registrado. Passe um driver para substituir a detecção automática, ou um conjunto de regras de identidade para substituir a identidade de linha por tabela durante a captura do snapshot.

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

Captura o estado atual do banco de dados e o salva em disco. Passe um array de nomes de tabelas para criar snapshots de tabelas específicas ou omita-o para incluir todas as tabelas.

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

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

Carrega dois snapshots nomeados e calcula o conjunto de alterações entre eles. Não requer init(), pois opera com snapshots persistidos.

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

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

Mesclagem em três vias de três snapshots nomeados. Retorna um resultado com operações sem conflitos e eventuais conflitos. Mescla no nível de coluna: a fachada constrói ThreeWayMerge sem CellMergeConfig, portanto a mesclagem no nível da célula não é aplicada. Para isso, use diretamente ThreeWayMerge.

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

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

Mesclagem em duas vias: aplica alterações sobre a base. Equivale a merge($base, $base, $changes). Sempre gera um resultado sem conflitos, pois não há edições simultâneas. Somente no nível de coluna, como em merge().

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

apply(MergeResult $result): ApplyResult

Executa um resultado de mesclagem sem conflitos no banco de dados passado para init(). Requer init(). Gera ConflictException se ainda houver conflitos não resolvidos.

Todas as operações do resultado são executadas; por isso, o resultado completo de merge() só se aplica corretamente a um banco de dados que ainda contenha o estado base. Para um banco de dados que já contenha um dos lados, aplique uma seleção das operações que lhe faltam; consulte Aplicação protegida.

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

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

Cria um plano de mesclagem pronto para UI a partir de três snapshots nomeados. O plano inclui IDs estáveis de operação, IDs de grupos de alterações, contexto da operação, conflitos, incompatibilidades de esquema, um resumo, metadados e um hash do plano. A mesclagem ocorre no nível de coluna, como em merge(); passe um resultado mesclado por célula para MergePlanBuilder::build() para fazer a mesclagem nesse nível.

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

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

Aplica um resultado de mesclagem sem conflitos com pré-condições otimistas nas linhas ativas. As atualizações e exclusões exigem que as linhas ativas atuais correspondam a $expectedLive; as inserções exigem que a identidade de destino ainda não exista. $expectedLive é um snapshot do banco de dados de destino (theirs, ao promover ours para o banco de dados de onde theirs foi obtido). Qualquer instrução que afete zero linhas reverte a transação.

PHP
use Merql\Snapshot\SnapshotStore;

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

reset(): void

Limpa as instâncias internas de conexão e Snapshotter. Usado principalmente em testes para redefinir o estado entre execuções.


Conexão

Merql\Connection cria adaptadores de conexão com padrões sensatos. As conexões PDO usam exceções em caso de erro, modo de busca associativo, sem prepared statements emulados e valores buscados convertidos em strings. O adaptador mysqli normaliza os valores buscados para o mesmo formato de string ou 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

Cria uma conexão SQLite. Ativa automaticamente as chaves estrangeiras por meio de PRAGMA foreign_keys = ON.

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

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

Conecte-se usando qualquer string DSN do PDO. merql inclui drivers apenas para mysql e sqlite; outros DSNs abrem uma conexão, mas Merql::init(), Snapshotter e os aplicadores lançam Unsupported database driver, a menos que um driver seja registrado com DriverFactory::register().

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

fromPdo(PDO $pdo): PdoDatabaseConnection

Envolve uma instância PDO existente.

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

Envolve uma instância mysqli existente.

Contrato do adaptador

Todos os adaptadores implementam 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() aceitam parâmetros posicionais list<scalar|null> para placeholders ?. query() retorna list<array<string, scalar|null>>; os valores são normalizados para o mesmo formato de string ou null nos adaptadores PDO e mysqli.


Capturador de snapshots

Merql\Snapshot\Snapshotter captura o estado do banco de dados. Ao contrário da fachada, oferece controle total sobre os filtros e não persiste os dados automaticamente.

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

O driver é detectado automaticamente pela identidade da conexão, caso não seja informado. Passe um IdentityRuleSet quando a identidade da linha específica da tabela precisar substituir os padrões do esquema.

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

Capture o estado atual. Passe nomes de tabelas para limitar o escopo. Passe objetos de filtro para excluir tabelas, colunas ou linhas.

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

Capture tabelas físicas usando nomes canônicos de tabela. Use isso quando a mesma tabela lógica tiver nomes físicos diferentes entre ambientes.

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

O snapshot resultante armazena nomes canônicos de tabela e preserva o esquema físico da tabela, as colunas de identidade configuradas, as chaves de linha e os filtros.

fromData(string $name, array $tableData): Snapshot (estático)

Crie um snapshot a partir de dados brutos, sem conexão com o banco de dados. Útil para testes ou para importar dados de outra fonte.

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 é um objeto de valor somente leitura que representa um estado completo do banco de dados.

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 contém as linhas, as impressões digitais e o esquema de uma tabela.

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 são dados de entrada para 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 define as colunas usadas para criar chaves de linha.

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 (estático)

Resolve a regra de identidade padrão a partir do esquema: chave primária, primeira chave exclusiva e, em seguida, alternativa baseada no conteúdo.

toArray(): array

Serializa a regra como ['type' => string, 'columns' => list<string>].

fromArray(array $data): IdentityRule (estático)

Hidrata uma regra a partir de dados serializados.


IdentityRuleSet

Merql\Identity\IdentityRuleSet armazena substituições de identidade específicas de cada tabela.

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

Retorna um novo conjunto de regras com uma substituição de tabela adicionada.

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

Retorna entradas de IdentityConflict quando várias linhas geram a mesma chave para uma regra.

toArray(): array

Serializa as regras de tabela como um array seguro para JSON.

fromArray(array $data): IdentityRuleSet (estático)

Hidrata um conjunto de regras a partir de dados serializados.


SnapshotStore

Merql\Snapshot\SnapshotStore persiste e carrega snapshots como arquivos JSON.

setDirectory(string $directory): void

Define o diretório de armazenamento. O padrão é .merql/snapshots.

save(Snapshot $snapshot): void

Grava um snapshot no disco.

load(string $name): Snapshot

Carrega um snapshot pelo nome. Lança SnapshotException se não for encontrado.

exists(string $name): bool

Verifica se um arquivo de snapshot existe.

delete(string $name): void

Remove um arquivo de snapshot.


Comparador

Merql\Diff\Differ compara dois snapshots e produz um conjunto de alterações.

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 (estático)

Compara dois valores convertendo-os em strings. NULL é tratado como um valor distinto: NULL === NULL é verdadeiro, NULL === '' é falso.


Conjunto de alterações

Merql\Diff\Changeset é uma coleção somente leitura de operações no nível da linha.

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

Objetos de valor somente leitura que representam alterações individuais em linhas.

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 representa uma única alteração de coluna em uma atualização de linha.

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

ThreeWayMerge

Merql\Merge\ThreeWayMerge é o algoritmo central de mesclagem.

__construct(?CellMergeConfig $cellMergeConfig = null)

Passe um CellMergeConfig para ativar a mesclagem no nível da célula para colunas 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

Realiza uma mesclagem de três vias. Calcula internamente os conjuntos de alterações (da base para o nosso lado e da base para o lado deles) e os mescla.

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

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

Atalho para mesclagem de duas vias. Equivalente a merge($base, $base, $changes).

schemaMismatches(): array

Retorna SchemaException[] para quaisquer diferenças de esquema detectadas durante a última mesclagem (colunas adicionadas ou removidas entre snapshots).


MergeResult

Merql\Merge\MergeResult é um objeto de valor somente leitura que contém o resultado da mesclagem.

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 é um modelo de revisão serializável para uma mesclagem.

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>

Use MergePlanSerializer::toJson() e ::fromJson() para garantir roundtrips estáveis de JSON.

Seleções

ChangeGroupSelection armazena IDs de grupos de alterações preparados. Converta-o em um OperationSelection ao criar resultados de mesclagem selecionados ou planos de reversão.

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 armazena operações inversas e expectativas de divergência para uma aplicação selecionada.

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

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

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

Use RollbackDrift antes de aplicar a reversão e, em seguida, RollbackPlanApplier para executar as operações inversas.


MergeOperation

Merql\Merge\MergeOperation é uma única operação resolvida da mesclagem.

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

Constantes de tipo:

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

Conflito

Merql\Merge\Conflict representa um conflito de mesclagem não resolvido.

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

Tipos de conflito

Tipo Significado
update_update Ambos os lados alteraram a mesma coluna para valores diferentes
update_delete Nosso lado atualizou uma linha que o lado deles excluiu
delete_update Nosso lado excluiu uma linha que o lado deles atualizou
insert_insert Ambos os lados inseriram uma linha com a mesma chave primária

ConflictResolver

Merql\Merge\ConflictResolver aplica uma política de resolução a todos os conflitos no resultado da mesclagem.

resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (estático)

Retorna um novo MergeResult com os conflitos resolvidos de acordo com a política.

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 é um enum baseado com três casos.

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 executa a lógica de mesclagem por coluna para uma única linha. Usado internamente por ThreeWayMerge.

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

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

Aplicador

Merql\Apply\Applier executa um resultado de mesclagem em um banco de dados.

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

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

Executa todas as operações em uma única transação. Reverte a transação em caso de erro e o informa em ApplyResult::errors() em vez de lançar uma exceção. Lança ConflictException se o resultado tiver conflitos não resolvidos.

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

A ordem das chaves estrangeiras é gerenciada automaticamente: as inserções são ordenadas conforme as dependências, e as exclusões, na ordem inversa das dependências.


ApplyResult

Merql\Apply\ApplyResult é um objeto de valor somente leitura retornado pelo aplicador.

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

Após uma aplicação revertida, rowsAffected() ainda contabiliza as instruções executadas antes da falha (#4). Confira hasErrors() antes de confiar na contagem.


DryRun

Merql\Apply\DryRun gera SQL legível por humanos sem executar nada.

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

Retorna uma lista de strings SQL com os valores inseridos diretamente (apenas para exibição).

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 gera instruções SQL parametrizadas. É usado internamente tanto por Applier quanto por DryRun.

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

Retorna 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 estratégias de mesclagem no nível da célula para colunas ou tipos de coluna específicos.

auto(): self (estático)

Fábrica de conveniência que atribui TextCellMerger a colunas TEXT/LONGTEXT e JsonCellMerger a colunas JSON.

PHP
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();

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

Atribui um mesclador a uma coluna específica. Use table.column para nomes qualificados ou apenas column para todas as tabelas.

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

Atribui um mesclador a todas as colunas que correspondem a um padrão de tipo (correspondência de substring sem distinção entre maiúsculas e minúsculas).

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

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

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

Busca o mesclador para uma determinada tabela, coluna e tipo. Prioridade: nome de coluna qualificado, nome de coluna não qualificado, padrão de tipo, padrão (opaco).


CellMerger (interface)

Merql\CellMerge\CellMerger é a interface para estratégias de mesclagem no nível da célula.

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

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

São fornecidas três implementações integradas.

TextCellMerger

Merql\CellMerge\TextCellMerger mescla textos com várias linhas usando uma comparação de três vias, linha por linha (o mesmo algoritmo que git usa para o conteúdo de arquivos). Quando os dois lados editam linhas diferentes, a mesclagem é limpa. Quando os dois lados editam a mesma linha de maneiras diferentes, é informado um conflito.

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 mescla valores JSON comparando as chaves de nível superior de forma independente. Cada chave é mesclada usando a lógica de três vias. Objetos aninhados são comparados como strings JSON opacas (não são mesclados recursivamente).

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 é o padrão. Trata os valores como strings opacas e sempre informa um conflito quando são diferentes.


CellMergeResult

Merql\CellMerge\CellMergeResult é o tipo de retorno de todos os mescladores de células.

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 é uma representação somente leitura da estrutura da tabela.

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 de drivers

merql usa um sistema de drivers plugável para abstrair operações específicas de cada banco de dados. Os drivers são detectados automaticamente pela identidade do driver da conexão.

Driver (interface)

Merql\Driver\Driver define o contrato que todos os drivers de banco de dados implementam.

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

Implementações integradas: MysqlDriver e SqliteDriver.

DriverFactory

Merql\Driver\DriverFactory detecta automaticamente o driver a partir de uma conexão.

PHP
use Merql\Driver\DriverFactory;

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

Registre um driver personalizado para outros bancos de dados:

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

Filtros

TableFilter

Merql\Filter\TableFilter inclui ou exclui tabelas usando padrões glob.

PHP
use Merql\Filter\TableFilter;

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

ColumnFilter

Merql\Filter\ColumnFilter remove colunas específicas dos snapshots.

PHP
use Merql\Filter\ColumnFilter;

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

RowFilter

Merql\Filter\RowFilter filtra linhas usando uma função predicado.

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

Exceções

SnapshotException

Merql\Exceptions\SnapshotException é lançado quando um snapshot não pode ser encontrado ou tem um nome inválido.

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

MergeException

Merql\Exceptions\MergeException é lançado quando falta um snapshot necessário para uma mesclagem.

PHP
MergeException::snapshotRequired('base');

ConflictException

Merql\Exceptions\ConflictException é lançado ao tentar aplicar um resultado de mesclagem com conflitos não resolvidos.

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

SchemaException

Merql\Exceptions\SchemaException é lançado (ou coletado) quando os esquemas diferem entre snapshots.

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

Incompatibilidades de esquema não interrompem a mesclagem. Elas são coletadas e ficam disponíveis em $result->schemaMismatches() para inspeção.