Eilučių tapatybė
Eilutės tapatybė nustato, kaip merql susieja eilutes skirtingose momentinėse kopijose. Lyginant base su ours, reikia nustatyti, kad eilutė X base yra ta pati loginė eilutė kaip Y eilutė ours, net jei pasikeitė kai kurios stulpelių reikšmės. Tapatybės taisyklė nurodo, kurie stulpeliai sudaro eilutės raktą.
use Merql\Identity\PrimaryKeyIdentity;
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
RowIdentity sąsaja
Visos tapatybės strategijos įgyvendina du metodus:
interface RowIdentity
{
public function key(array $row): string;
public function columns(): array;
}
key() sukuria unikalų eilutės duomenų identifikatorių, o columns() grąžina tapatybei naudojamų stulpelių pavadinimus.
PrimaryKeyIdentity
Numatytoji strategija. Eilutės susiejamos pagal pirminio rakto stulpelius.
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)
Tai merql naudoja pagal numatytuosius nustatymus, kai lentelės schemoje apibrėžtas pirminis raktas.
NaturalKeyIdentity
Jei lentelė neturi automatiškai didinamo pirminio rakto, eilutės susiejamos pagal unikalaus apribojimo stulpelius. Tinka, kai PK yra UUID arba kai lentelei kaip loginei tapatybei naudojamas sudėtinis unikalus apribojimas.
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
Atsarginė parinktis lentelėms be pirminio rakto ir unikalių apribojimų. Apskaičiuoja SHA-256 maišą iš visų stulpelių reikšmių. Dvi eilutės laikomos vienodomis, jei sutampa visi jų stulpeliai.
use Merql\Identity\ContentHashIdentity;
$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)
Turinio maiša pagrįsta tapatybė turi trūkumą: pasikeitus eilutės turiniui, pasikeičia ir jos maiša, todėl eilutė atrodo kaip seno įrašo ištrynimas ir naujo įterpimas, o ne atnaujinimas. Tai neišvengiamas kompromisas, kai nėra stabilių tapatybės stulpelių.
IdentityRule
IdentityRule yra nuosekliai serializuojama tapatybės konfigūracija, naudojama fiksuojant momentinę kopiją
ir sudarant sujungimo planus.
use Merql\Identity\IdentityRule;
$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"
Taisyklių tipai:
| Tipas | Reikšmė |
|---|---|
primary |
Duomenų bazės pirminio rakto stulpeliai |
natural |
Stabilūs unikalūs verslo stulpeliai |
composite |
Sudėtiniai loginės tapatybės stulpeliai |
content |
Atsarginė turinio maišos parinktis |
IdentityRule::forSchema($schema) parenka numatytąją taisyklę:
- Jei lentelė turi pirminį raktą, naudojami jo stulpeliai.
- Jei lentelė turi unikalių raktų, naudojami pirmojo unikalaus rakto stulpeliai.
- Jei nėra nė vieno iš jų, naudojami visi stulpeliai (atsarginė turinio maišos parinktis).
IdentityRuleSet
Naudokite IdentityRuleSet, kai pagrindinė programa žino geresnę tapatybės taisyklę nei numatytoji schemos taisyklė.
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 kiekvienai užfiksuotai lentelei parenka IdentityRule. Pasirinkti stulpeliai įrašomi į TableSnapshot::identityColumns ir naudojami visoms vėlesnėms diff, merge, plan, SQL ir rollback operacijoms.
Naudojant statinę sąsają, Merql::init() galima perduoti tą patį taisyklių rinkinį:
use Merql\Merql;
Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);
Taisyklių rinkiniai serializuojami į stabilų masyvą:
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);
Dviprasmė tapatybė
Jei dvi užfiksuotos eilutės sukuria tą patį tapatybės raktą, fiksavimas nepavyksta, o viena eilutė neperrašo kitos.
use Merql\Exceptions\SnapshotException;
try {
$snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
// The configured identity rule matched multiple rows.
}
Pagrindinės programos gali iš anksto patikrinti neapdorotas eilutes naudodamos IdentityRuleSet::conflictsFor(),
kad apie dviprasmybę praneštų dar prieš fiksavimą:
$conflicts = $rules->conflictsFor(
'wp_postmeta',
IdentityRule::natural(['post_id', 'meta_key']),
$rows,
);
WordPress metaduomenų lentelėse post_id + meta_key paprastai naudinga grupavimui
ir rodymui, tačiau netinka kaip eilutės tapatybė, nes pasikartojantys metaduomenų raktai yra galimi.
Eilučių tapatybei naudokite lentelės pirminį raktą, nebent pagrindinė programa gali
įrodyti, kad natūralusis raktas yra unikalus.
Eilučių raktų kodavimas
Eilučių raktai yra koduotos eilutės, kuriose kelios stulpelių reikšmės sujungiamos skyrikliu (\x1F). Reikšmės, kuriose yra skyriklis arba procento ženklas, užkoduojamos, kad būtų išvengta susidūrimų:
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']
Kodavimo taisyklės:
| Pradinė reikšmė | Užkoduota reikšmė |
|---|---|
% |
%25 |
\x1F (skyriklis) |
%1F |
Taip užtikrinama, kad reikšmė su \x1F nebūtų suskaidyta į kelias rakto dalis. Kodavimas yra deterministinis ir grįžtamasis.
Automatinio didinimo neatitikimai
Kai abi pusės įterpia naujas eilutes, automatiškai didinami ID skirtingose šakose nesutampa. Eilutė #100 pusėje ours gali būti visiškai kitoks įrašas nei eilutė #100 pusėje theirs.
merql eilutes susieja pagal pirminį raktą. Jei abi pusės įterpia eilutę su tuo pačiu automatiškai didinamu ID, tai pažymima kaip insert_insert konfliktas. Kad to išvengtumėte, lentelėse, kuriose tikėtini vienalaikiai įterpimai, naudokite natūraliuosius raktus (unikalius, skirtingose šakose stabilius stulpelius).
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);
Tapatybė momentinėse kopijose
Fiksuojant pasirinktų tapatybės stulpelių reikšmės išsaugomos su kiekviena TableSnapshot:
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']
SqlGenerator naudoja šiuos stulpelius UPDATE ir DELETE sakinių WHERE sąlygoms sudaryti, o sujungimo planai – dekoduotoms tapatybės reikšmėms pateikti peržiūrai, pasirinkimui, apsaugotam pritaikymui ir grąžinimui.