Radidentitet
Radidentitet avgör hur merql matchar rader i olika ögonblicksbilder. När base jämförs med ours måste systemet veta att rad X i base är samma logiska rad som rad Y i ours, även om vissa kolumnvärden har ändrats. Identitetsregeln styr vilka kolumner som bildar radnyckeln.
use Merql\Identity\PrimaryKeyIdentity;
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
Gränssnittet RowIdentity
Alla identitetsstrategier implementerar två metoder:
interface RowIdentity
{
public function key(array $row): string;
public function columns(): array;
}
key() skapar en unik strängidentifierare utifrån en rads data. columns() returnerar kolumnnamnen som används för identitet.
PrimaryKeyIdentity
Standardstrategin. Matchar rader med deras primärnyckelkolumner.
use Merql\Identity\PrimaryKeyIdentity;
// Single-column PK.
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
// Composite PK.
$identity = new PrimaryKeyIdentity(['tenant_id', 'user_id']);
$key = $identity->key(['tenant_id' => 1, 'user_id' => 99, 'name' => 'Alice']);
// "1\x1F99" (unit separator between parts)
Det här är standardmetoden som merql använder när tabellens schema definierar en primärnyckel.
NaturalKeyIdentity
För tabeller utan autoinkrementerande primärnyckel matchas rader med kolumnerna i den unika begränsningen. Användbart när PK är en UUID eller när tabellen använder en sammansatt unik begränsning som logisk identitet.
use Merql\Identity\NaturalKeyIdentity;
$identity = new NaturalKeyIdentity(['email']);
$key = $identity->key(['id' => 1, 'email' => 'alice@example.com', 'name' => 'Alice']);
// "alice@example.com"
$identity = new NaturalKeyIdentity(['country', 'postal_code']);
$key = $identity->key(['country' => 'US', 'postal_code' => '90210', 'city' => 'Beverly Hills']);
// "US\x1F90210"
ContentHashIdentity
Reservlösning för tabeller utan primärnyckel eller unika begränsningar. Beräknar en SHA-256-hash av alla kolumnvärden. Två rader är samma om varje kolumn matchar.
use Merql\Identity\ContentHashIdentity;
$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)
Innehållshash som identitet har en begränsning: om en rads innehåll ändras ändras även dess hash. Raden visas då som en borttagning av den gamla hashen och en infogning av den nya, i stället för som en uppdatering. Det är en ofrånkomlig avvägning när det saknas stabila identitetskolumner.
IdentityRule
IdentityRule är den serialiserbara identitetskonfiguration som används när ögonblicksbilder tas och sammanslagningsplaner skapas.
use Merql\Identity\IdentityRule;
$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"
Regeltyper:
| Typ | Betydelse |
|---|---|
primary |
Primärnyckelkolumner i databasen |
natural |
Stabilt unika verksamhetskolumner |
composite |
Kolumner för sammansatt logisk identitet |
content |
Reservlösning med innehållshash |
IdentityRule::forSchema($schema) löser standardregeln:
- Om tabellen har en primärnyckel används dess kolumner.
- Om tabellen har unika nycklar används kolumnerna i den första unika nyckeln.
- Om inget av detta finns används alla kolumner (reservlösning med innehållshash).
IdentityRuleSet
Använd IdentityRuleSet när värdapplikationen känner till en bättre identitetsregel än den som schemat anger som standard.
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;
use Merql\Snapshot\Snapshotter;
$rules = new IdentityRuleSet([
'wp_options' => IdentityRule::natural(['option_name']),
'wp_term_relationships' => IdentityRule::composite(['object_id', 'term_taxonomy_id']),
]);
$snapshotter = new Snapshotter($connection, identityRules: $rules);
$snapshot = $snapshotter->capture('live', ['wp_options', 'wp_term_relationships']);
Snapshotter väljer en IdentityRule för varje tabell som tas med. De valda kolumnerna lagras i TableSnapshot::identityColumns och används sedan för alla diff-, merge-, plan-, SQL- och rollback-operationer.
Merql::init() kan ta emot samma regeluppsättning när den statiska fasaden används:
use Merql\Merql;
Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);
Regeluppsättningar serialiseras stabilt som arrayer:
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);
Tvetydig identitet
Om två rader i ögonblicksbilden får samma identitetsnyckel misslyckas registreringen i stället för att den ena raden skriver över den andra.
use Merql\Exceptions\SnapshotException;
try {
$snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
// The configured identity rule matched multiple rows.
}
Värdapplikationer kan kontrollera rådata med IdentityRuleSet::conflictsFor() i förväg om de vill rapportera tvetydigheter innan ögonblicksbilden tas:
$conflicts = $rules->conflictsFor(
'wp_postmeta',
IdentityRule::natural(['post_id', 'meta_key']),
$rows,
);
För WordPress-metatabeller är post_id + meta_key oftast användbar för gruppering och visning, men inte säker som radidentitet eftersom duplicerade metanycklar är tillåtna. Använd tabellens primärnyckel som radidentitet, såvida inte värdapplikationen kan bevisa att den naturliga nyckeln är unik.
Kodning av radnycklar
Radnycklar är kodade strängar där flera kolumnvärden kombineras med en enhetsavskiljare (\x1F). Värden som innehåller avskiljaren eller procenttecknet escape-kodas för att förhindra kollisioner:
use Merql\Snapshot\Snapshotter;
// Encode.
$key = Snapshotter::buildRowKey(
['tenant_id' => '1', 'user_id' => '99'],
['tenant_id', 'user_id'],
);
// "1\x1F99"
// Decode.
$parts = Snapshotter::decodeRowKey($key);
// ['1', '99']
Escape-regler:
| Ursprungligt | Escape-kodat |
|---|---|
% |
%25 |
\x1F (enhetsavskiljare) |
%1F |
Detta säkerställer att ett värde som innehåller \x1F inte delas upp i flera nyckeldelar. Kodningen är deterministisk och reversibel.
Avvikande autoinkrement
När båda sidor infogar nya rader får de olika autoinkrement-ID:n. Rad #100 i ours kan vara en helt annan post än rad #100 i theirs.
merql hanterar detta genom att matcha på primärnyckel. Om båda sidor har infogat en rad med samma autoinkrement-ID markeras det som en insert_insert-konflikt. Undvik detta genom att använda naturliga nycklar (unika kolumner som är stabila mellan grenar) för tabeller där samtidiga infogningar kan förekomma.
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);
Identitet i ögonblicksbilder
Identitetskolumnerna som valdes när ögonblicksbilden togs lagras med varje TableSnapshot:
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']
SqlGenerator använder dessa kolumner för att skapa WHERE-satser för UPDATE- och DELETE-satser. Sammanslagningsplaner använder dem för att visa avkodade identitetsvärden för granskning, val, skyddad tillämpning och återställning.