Samenvoeging op celniveau
Een samenvoeging op kolomniveau detecteert wanneer beide kanten dezelfde kolom hebben gewijzigd. Een samenvoeging op celniveau gaat dieper en voegt de inhoud binnen die kolom samen. Twee mensen die verschillende regels in een TEXT-veld of verschillende sleutels in een JSON-object bewerken, kunnen hun wijzigingen probleemloos samenvoegen.
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);
Samenvoeging op celniveau inschakelen
Samenvoeging op celniveau is optioneel. Deze wordt alleen uitgevoerd in een ThreeWayMerge die is samengesteld met een CellMergeConfig. Zonder zo'n configuratie levert elke kolom die beide kanten in verschillende waarden hebben gewijzigd een update_update-conflict op.
De Merql-gevel accepteert geen configuratie: Merql::merge(), Merql::patch() en Merql::plan() maken een new ThreeWayMerge() zonder configuratie, en de opdracht merge van de CLI loopt via Merql::merge(). Ze voegen altijd samen op kolomniveau (#7).
Om snapshots die zijn opgeslagen via de gevel of de CLI samen te voegen met samenvoeging op celniveau, laad je ze en roep je zelf ThreeWayMerge aan. Het resultaat is een gewone MergeResult, dus de gevel kan deze nog steeds toepassen, en MergePlanBuilder zet deze om in een samenvoegplan:
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Merql;
use Merql\Plan\MergePlanBuilder;
use Merql\Snapshot\SnapshotStore;
$base = SnapshotStore::load('base');
$ours = SnapshotStore::load('ours');
$theirs = SnapshotStore::load('theirs');
$result = (new ThreeWayMerge(CellMergeConfig::auto()))->merge($base, $ours, $theirs);
$plan = (new MergePlanBuilder())->build('plan-1', $base, $ours, $theirs, $result);
Samenvoegers voor cellen worden alleen uitgevoerd voor kolommen die beide kanten hebben gewijzigd. Als slechts één kant een kolom heeft gewijzigd, wordt de waarde ervan ongewijzigd overgenomen.
CellMergeConfig
CellMergeConfig koppelt kolommen of kolomtypen aan implementaties van samenvoegers voor cellen. De auto()-factory biedt redelijke standaardwaarden:
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
use Merql\CellMerge\TextCellMerger;
// Auto: column types containing "text" (TEXT, MEDIUMTEXT, LONGTEXT, ...) use
// TextCellMerger, column types containing "json" use JsonCellMerger.
$config = CellMergeConfig::auto();
// Custom: assign mergers to specific columns.
$config = (new CellMergeConfig())
->forColumn('posts.content', new TextCellMerger())
->forColumn('settings', new JsonCellMerger())
->forType('json', new JsonCellMerger());
Prioriteit bij het kiezen van een samenvoeger:
- Volledig gekwalificeerde kolomnaam (
table.column). - Niet-gekwalificeerde kolomnaam (
column). - Kolomtype op basis van een patroon (niet hoofdlettergevoelig
str_contains). - Standaard:
OpaqueCellMerger(meldt altijd een conflict wanneer waarden verschillen).
TextCellMerger
Voegt tekst van meerdere regels samen met Myers diff, hetzelfde algoritme dat git gebruikt voor bestandsinhoud. Elke regel wordt als een eenheid behandeld en wijzigingen aan verschillende regels worden probleemloos samengevoegd.
use Merql\CellMerge\TextCellMerger;
$merger = new TextCellMerger();
Voorbeeld: tekst probleemloos samenvoegen
Base: "line one\nline two\nline three"
Ours: "LINE ONE\nline two\nline three" // changed line 1
Theirs: "line one\nline two\nLINE THREE" // changed line 3
Er zijn verschillende regels bewerkt. De samenvoeging levert "LINE ONE\nline two\nLINE THREE" op, zonder conflict.
Voorbeeld: tekstconflict
Base: "line one\nline two"
Ours: "changed by us\nline two" // changed line 1
Theirs: "changed by them\nline two" // also changed line 1
Beide kanten hebben dezelfde regel gewijzigd in verschillende waarden. De samenvoeger retourneert een conflicteresultaat. De samengevoegde inhoud bevat conflictmarkeringen die lijken op die van git.
Werking
TextCellMerger gebruikt de ThreeWayMerge::merge() van pitmaster, die een Myers diff berekent tussen base en elke kant en vervolgens beide bewerkingsscripts combineert. Als bewerkingen elkaar overlappen in hetzelfde regelgebied, wordt een conflict gemeld.
JsonCellMerger
Voegt JSON-objecten samen door de sleutels op het hoogste niveau afzonderlijk te vergelijken. Elke sleutel wordt samengevoegd volgens de standaardregels voor drieweg-samenvoeging.
use Merql\CellMerge\JsonCellMerger;
$merger = new JsonCellMerger();
Voorbeeld: JSON probleemloos samenvoegen
// Base
{"name": "Alice", "role": "editor", "active": true}
// Ours: changed "role"
{"name": "Alice", "role": "admin", "active": true}
// Theirs: changed "name"
{"name": "Bob", "role": "editor", "active": true}
Er zijn verschillende sleutels gewijzigd. Het samengevoegde resultaat is:
{"name": "Bob", "role": "admin", "active": true}
Voorbeeld: JSON-conflict
// Base
{"color": "red"}
// Ours
{"color": "blue"}
// Theirs
{"color": "green"}
Beide kanten hebben de color-sleutel gewijzigd in verschillende waarden. Dit is een conflict. De samenvoeger kiest standaard ours en meldt één conflict.
Regels op sleutelniveau
| Basis | Ours | Theirs | Resultaat |
|---|---|---|---|
| Sleutel ongewijzigd | Sleutel ongewijzigd | Basis accepteren | |
| Sleutel ongewijzigd | Sleutel gewijzigd | Theirs accepteren | |
| Sleutel gewijzigd | Sleutel ongewijzigd | Ours accepteren | |
| Sleutel gewijzigd (zelfde) | Sleutel gewijzigd (zelfde) | Accepteren (komen overeen) | |
| Sleutel gewijzigd (anders) | Sleutel gewijzigd (anders) | Conflict (standaard: ours) | |
| Sleutel bestaat | Sleutel bestaat | Sleutel verwijderd | Verwijdering accepteren |
| Sleutel bestaat | Sleutel verwijderd | Sleutel bestaat | Verwijdering accepteren |
| Sleutel ontbreekt | Sleutel toegevoegd | Sleutel ontbreekt | Toevoeging accepteren |
| Sleutel ontbreekt | Sleutel ontbreekt | Sleutel toegevoegd | Toevoeging accepteren |
Geneste objecten worden vergeleken als ondoorzichtige JSON-strings, niet recursief. Als een genest object verschilt, wordt de volledige waarde van die sleutel vergeleken, niet de subsleutels.
Vereisten
Alle drie de waarden moeten geldige JSON-objecten of arrays zijn. Als een waarde geen geldige JSON is, of een scalaire JSON-waarde is (string, getal, boolean), valt de samenvoeger terug op een conflict.
OpaqueCellMerger
De standaardmerger wanneer er geen strategie op celniveau is ingesteld. Deze behandelt de kolomwaarde als een ondoorzichtige blob en meldt altijd een conflict wanneer beide kanten verschillen.
use Merql\CellMerge\OpaqueCellMerger;
$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs
CellMergeResult
Alle celmergers retourneren een CellMergeResult:
$result = $merger->merge($base, $ours, $theirs);
$result->clean; // bool: true if merge resolved cleanly
$result->value; // mixed: the merged value (or ours on conflict)
$result->conflicts; // int: number of conflicts within the cell
Factorymethoden:
CellMergeResult::resolved($value); // clean merge
CellMergeResult::conflict($oursValue, $n); // n conflicts, defaults to ours
Aangepaste celmergers
Implementeer de interface CellMerger om je eigen samenvoegstrategie toe te voegen:
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;
class YamlCellMerger implements CellMerger
{
public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult
{
// Parse YAML, merge keys, return result.
$merged = $this->mergeYaml($base, $ours, $theirs);
if ($merged['clean']) {
return CellMergeResult::resolved($merged['value']);
}
return CellMergeResult::conflict($ours);
}
}
$config = (new CellMergeConfig())
->forColumn('config_data', new YamlCellMerger());