Preskočiť na obsah

Identita riadka

Identita riadka určuje, ako merql páruje riadky naprieč snímkami. Pri porovnávaní základu s našou verziou musí vedieť, že riadok X v základe je ten istý logický riadok ako riadok Y v našej verzii, aj keď sa hodnoty niektorých stĺpcov zmenili. Pravidlo identity určuje, ktoré stĺpce tvoria kľúč riadka.

PHP
use Merql\Identity\PrimaryKeyIdentity;

$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"

Rozhranie RowIdentity

Všetky stratégie identity implementujú dve metódy:

PHP
interface RowIdentity
{
    public function key(array $row): string;
    public function columns(): array;
}

key() vytvorí z údajov riadka jedinečný textový identifikátor. columns() vráti názvy stĺpcov použitých na určenie identity.

PrimaryKeyIdentity

Predvolená stratégia. Páruje riadky podľa stĺpcov ich primárneho kľúča.

PHP
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)

Túto stratégiu používa merql predvolene, ak má tabuľka v schéme definovaný primárny kľúč.

NaturalKeyIdentity

V tabuľkách bez primárneho kľúča s automatickým zvyšovaním páruje riadky podľa stĺpcov s obmedzením jedinečnosti. Hodí sa, keď je PK UUID alebo keď tabuľka používa zložené obmedzenie jedinečnosti ako svoju logickú identitu.

PHP
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

Náhradné riešenie pre tabuľky bez primárneho kľúča a obmedzení jedinečnosti. Vypočíta hash SHA-256 všetkých hodnôt stĺpcov. Dva riadky sú rovnaké, ak sa zhodujú všetky stĺpce.

PHP
use Merql\Identity\ContentHashIdentity;

$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)

Identita založená na hashi obsahu má obmedzenie: ak sa obsah riadka zmení, zmení sa aj jeho hash, takže riadok sa namiesto aktualizácie javí ako odstránenie starého hashu a vloženie nového. Ide o nevyhnutný kompromis, keď nie sú k dispozícii stabilné identifikačné stĺpce.

IdentityRule

IdentityRule je serializovateľná konfigurácia identity používaná pri zachytávaní snímok a v plánoch zlúčenia.

PHP
use Merql\Identity\IdentityRule;

$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"

Typy pravidiel:

Typ Význam
primary Stĺpce primárneho kľúča databázy
natural Stabilné jedinečné obchodné stĺpce
composite Stĺpce zloženého logického identifikátora
content Záložná možnosť: hash obsahu

IdentityRule::forSchema($schema) určuje predvolené pravidlo:

  1. Ak má tabuľka primárny kľúč, použijú sa jeho stĺpce.
  2. Ak má tabuľka jedinečné kľúče, použijú sa stĺpce prvého z nich.
  3. Ak neexistuje ani jeden, použijú sa všetky stĺpce (záložná možnosť: hash obsahu).

IdentityRuleSet

Použite IdentityRuleSet, keď hostiteľská aplikácia pozná vhodnejšie pravidlo identity než predvolené pravidlo schémy.

PHP
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 určuje IdentityRule pre každú zachytenú tabuľku. Vybrané stĺpce sa ukladajú do TableSnapshot::identityColumns a používajú sa pri všetkých nasledujúcich operáciách porovnávania rozdielov, zlúčenia, plánovania, SQL a návratu zmien.

Merql::init() môže pri použití statického rozhrania dostať rovnakú množinu pravidiel:

PHP
use Merql\Merql;

Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);

Množiny pravidiel majú stabilnú serializáciu polí:

PHP
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);

Nejednoznačná identita

Ak dva zachytené riadky vytvoria rovnaký identifikačný kľúč, zachytenie zlyhá namiesto toho, aby jeden riadok prepísalo druhým.

PHP
use Merql\Exceptions\SnapshotException;

try {
    $snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
    // The configured identity rule matched multiple rows.
}

Hostiteľské aplikácie môžu pred zachytením overiť nespracované riadky pomocou IdentityRuleSet::conflictsFor(), ak chcú nejednoznačnosť oznámiť vopred:

PHP
$conflicts = $rules->conflictsFor(
    'wp_postmeta',
    IdentityRule::natural(['post_id', 'meta_key']),
    $rows,
);

V prípade metatabuliek WordPress je post_id + meta_key zvyčajne užitočné na zoskupovanie a zobrazenie, ale nie je bezpečné ako identita riadka, pretože duplicitné kľúče metaúdajov sú platné. Na identifikáciu riadka použite primárny kľúč tabuľky, pokiaľ hostiteľská aplikácia nedokáže, že prirodzený kľúč je jedinečný.

Kódovanie kľúča riadka

Kľúče riadkov sú zakódované reťazce, ktoré spájajú hodnoty viacerých stĺpcov oddeľovačom jednotiek (\x1F). Hodnoty obsahujúce oddeľovač alebo znak percenta sa escapujú, aby sa predišlo kolíziám:

PHP
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']

Pravidlá escapovania:

Pôvodná hodnota Escapovaná hodnota
% %25
\x1F (oddeľovač jednotiek) %1F

Tým sa zabezpečí, že hodnota obsahujúca \x1F sa nerozdelí na viacero častí kľúča. Kódovanie je deterministické a reverzibilné.

Rozdiely v automatickom inkrementovaní

Keď obe strany vložia nové riadky, automaticky inkrementované ID sa budú medzi vetvami líšiť. Riadok #100 u nás môže byť úplne iný záznam než riadok #100 u nich.

merql to rieši párovaním podľa primárneho kľúča. Ak obe strany vložia riadok s rovnakým automaticky inkrementovaným ID, označí sa to ako konflikt insert_insert. Aby ste tomu predišli, v tabuľkách, kde sa očakávajú súbežné vkladania, používajte prirodzené kľúče (jedinečné stĺpce, ktoré sú stabilné naprieč vetvami).

PHP
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);

Identita v snímkach

Stĺpce identity vybrané pri zachytávaní sa ukladajú spolu s každým TableSnapshot:

PHP
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']

Pomocou týchto stĺpcov vytvára SqlGenerator klauzuly WHERE pre príkazy UPDATE a DELETE a plány zlúčenia z nich poskytujú dekódované hodnoty identity na kontrolu, výber, podmienené vykonanie a návrat zmien.