Sorazonosság
A sorazonosság határozza meg, hogyan párosítja a merql a sorokat a pillanatfelvételek között. Amikor a base és az ours állapotot hasonlítja össze, tudnia kell, hogy a X sor a base-ben logikailag megegyezik az ours Y sorával akkor is, ha egyes oszlopértékek megváltoztak. Az azonosítási szabály határozza meg, mely oszlopok alkotják a sor kulcsát.
use Merql\Identity\PrimaryKeyIdentity;
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
A RowIdentity interfész
Minden azonosítási stratégia két metódust valósít meg:
interface RowIdentity
{
public function key(array $row): string;
public function columns(): array;
}
A key() egyedi szöveges azonosítót állít elő a sor adataiból. A columns() visszaadja az azonosításhoz használt oszlopneveket.
PrimaryKeyIdentity
Az alapértelmezett stratégia. Az elsődleges kulcs oszlopai alapján párosítja a sorokat.
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)
Ezt használja alapértelmezés szerint a merql, ha a táblához tartozik elsődleges kulcs a sémában.
NaturalKeyIdentity
Az elsődleges kulcs automatikus növelése nélküli tábláknál az egyedi megszorítás oszlopai alapján párosítja a sorokat. Hasznos, ha a PK UUID, vagy ha a tábla összetett egyedi megszorítást használ logikai azonosítóként.
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
Visszaesési megoldás olyan táblákhoz, amelyeknek nincs elsődleges kulcsuk vagy egyedi megszorításuk. Kiszámítja az összes oszlopérték SHA-256 hashét. Két sor akkor azonos, ha minden oszlopuk egyezik.
use Merql\Identity\ContentHashIdentity;
$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)
A tartalomhash-alapú azonosításnak van egy korlátja: ha megváltozik egy sor tartalma, a hash is megváltozik, ezért a sor a régi hash törléseként és az új hash beszúrásaként jelenik meg, nem frissítésként. Ez elkerülhetetlen kompromisszum, ha nincsenek stabil azonosítóoszlopok.
IdentityRule
A IdentityRule a pillanatfelvétel készítése és a merge-tervek által használt szerializálható azonosítási konfiguráció.
use Merql\Identity\IdentityRule;
$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"
Szabálytípusok:
| Típus | Jelentés |
|---|---|
primary |
Adatbázis elsődleges kulcs oszlopai |
natural |
Stabil, egyedi üzleti oszlopok |
composite |
Összetett logikai azonosító oszlopai |
content |
Tartalomhash-alapú visszaesési megoldás |
A IdentityRule::forSchema($schema) feloldja az alapértelmezett szabályt:
- Ha a táblának van elsődleges kulcsa, az elsődleges kulcs oszlopait használja.
- Ha vannak egyedi kulcsok, az elsőként meghatározott egyedi kulcs oszlopait használja.
- Ha egyik sem áll rendelkezésre, minden oszlopot felhasznál (tartalomhash-alapú visszaesés).
IdentityRuleSet
Akkor használja a IdentityRuleSet megoldást, ha a hostalkalmazás a séma alapértelmezettjénél jobb azonosítási szabályt ismer.
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']);
A Snapshotter minden rögzített táblához felold egy IdentityRule értéket. A kiválasztott oszlopok a TableSnapshot::identityColumns értékben tárolódnak, és minden további diff-, merge-, terv-, SQL- és visszaállítási művelet során felhasználásra kerülnek.
A statikus facade használatakor a Merql::init() ugyanazt a szabálykészletet kaphatja meg:
use Merql\Merql;
Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);
A szabálykészletek tömbként stabilan szerializálhatók:
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);
Kétértelmű azonosítás
Ha két rögzített sorhoz ugyanaz az azonosítókulcs tartozik, a rögzítés sikertelen lesz, ahelyett hogy az egyik sor felülírná a másikat.
use Merql\Exceptions\SnapshotException;
try {
$snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
// The configured identity rule matched multiple rows.
}
A hostalkalmazások a nyers sorokat a IdentityRuleSet::conflictsFor() segítségével előzetesen ellenőrizhetik, ha már a rögzítés előtt jelezni szeretnék a kétértelműséget:
$conflicts = $rules->conflictsFor(
'wp_postmeta',
IdentityRule::natural(['post_id', 'meta_key']),
$rows,
);
A WordPress meta tábláknál általában hasznos a post_id + meta_key csoportosításhoz és megjelenítéshez, de sorkulcsként nem biztonságos, mert az ismétlődő meta kulcsok megengedettek. A sorazonossághoz használja a tábla elsődleges kulcsát, kivéve, ha a hostalkalmazás igazolni tudja, hogy a természetes kulcs egyedi.
Sorkulcs kódolása
A sorkulcsok kódolt szöveges értékek, amelyek több oszlop értékét választókarakterrel (\x1F) kapcsolják össze. Az ütközések elkerülése érdekében a választókaraktert vagy százalékjelet tartalmazó értékeket escape-eljük:
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-szabályok:
| Eredeti | Escape-elt |
|---|---|
% |
%25 |
\x1F (választókarakter) |
%1F |
Ez biztosítja, hogy a \x1F értéket tartalmazó érték ne essen szét több kulcsrészre. A kódolás determinisztikus és visszafordítható.
Automatikus növelésű azonosítók eltérése
Ha mindkét oldal új sorokat szúr be, az automatikusan növekvő azonosítók eltérnek az egyes ágakban. Az ours #100 sora lehet, hogy teljesen más rekord, mint a theirs #100 sora.
A merql ezt az elsődleges kulcs alapján kezeli. Ha mindkét oldal azonos, automatikusan növekvő azonosítóval szúrt be egy sort, akkor az insert_insert ütközésként jelenik meg. Ennek elkerüléséhez használjon természetes kulcsokat (az ágak között stabil egyedi oszlopokat) azoknál a tábláknál, amelyekbe várhatóan egyszerre történik beszúrás.
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);
Azonosítók a pillanatfelvételekben
A rögzítéskor kiválasztott azonosítóoszlopok minden egyes TableSnapshot mellett tárolódnak:
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']
A SqlGenerator ezeket az oszlopokat használja az UPDATE és DELETE utasítások WHERE záradékainak összeállításához. A merge-tervek emellett dekódolt azonosítóértékeket tesznek elérhetővé áttekintéshez, kiválasztáshoz, ellenőrzött alkalmazáshoz és visszaállításhoz.