Preskočiť na obsah

Zrkadlo SQL

SqlMirror presúva kolekcie storh do tabuliek SQLite alebo MySQL, aby ste mohli v SQL spúšťať spájanie tabuliek, zoradenie naprieč tabuľkami, vyhľadávanie podreťazcov a vytvárať reporty, pričom súbory zostávajú v kanonickom formáte. Predstavte si ho ako sekundárny index, ktorý je zároveň databázou: zrkadlo je odvodené, možno ho zahodiť a kedykoľvek znova vytvoriť. ext-pdo s ovládačom sqlite alebo mysql je potrebné iba pri jeho použití; základný balík zostáva bez závislostí.

Nastavenie

PHP
use Storh\DocStore;
use Storh\Schema;
use Storh\SqlMirror;

$schema = Schema::collection('pages')
    ->string('slug')->unique()
    ->string('kind')->index()
    ->int('publishedAt')->range();

$pages  = new DocStore($root, 'pages', schema: $schema);
$events = new Storh\SegmentedLog($root, 'events');

$mirror = new SqlMirror(new PDO('sqlite:' . $root . '/mirror.db'), 'app_');
$mirror->collection($pages, 'pages', $schema);
$mirror->collection($events, 'events');

$mirror->install();
$mirror->push();

Možno zrkadliť oba moduly: kolekcie DocStore aj streamy SegmentedLog (presúvajú sa iba živé záznamy). Odovzdanie objektu Schema je voliteľné a nezávislé od úložiska: deklarované polia string/int/float/bool sa zmenia na typované indexované stĺpce; všetko ostatné zostáva vyhľadateľné v stĺpci data JSON. Polia mixed nemožno označiť príznakom indexovania.

Pripojenia

Konštruktor prijíma objekt pripojenia PDO (ovládač sqlite alebo mysql, rozpoznaný automaticky), objekt pripojenia mysqli alebo ľubovoľnú implementáciu SqlMirrorConnection:

PHP
$mirror = new SqlMirror(new PDO('sqlite:' . $root . '/mirror.db'));
$mirror = new SqlMirror(new PDO('mysql:host=127.0.0.1;dbname=app;charset=utf8mb4', $user, $password));
$mirror = new SqlMirror(new mysqli('127.0.0.1', $user, $password, 'app'), 'wp_storh_');

Cesta mysqli funguje pri oboch režimoch hlásenia chýb mysqli, takže možno opätovne použiť existujúci objekt pripojenia z hostiteľskej aplikácie, napríklad WordPress $wpdb->dbh, bez úprav. Správanie je vo všetkých ovládačoch rovnaké; pri zlyhaní presunu sa transakcia kolekcie v každom z nich vráti späť.

Každá tabuľka obsahuje id (primárny kľúč), hash (riadi priebežné presuny), typované stĺpce a data (úplný záznam JSON).

Synchronizácia

PHP
$mirror->push();                    // reconcile: insert, update, delete as needed
$mirror->push('pages');             // reconcile a single collection
$mirror->flush('pages', $ids);      // push or remove just these ids
$mirror->pull();                    // write mirror rows back into the store
$mirror->verify();                  // report missing, stale, and orphaned rows
$mirror->rebuild();                 // clear all rows and push from scratch
$mirror->uninstall();               // drop the mirror tables

push() porovnáva kontrolné súčty záznamov so zrkadlom a zapisuje každú kolekciu v rámci jednej transakcie, takže po páde alebo zlyhaní presunu nikdy nezostane dávka spracovaná iba čiastočne. Spracovanie nezmenených záznamov stojí jedno SELECT a prechod cez záznamy. Pravidelný push() (napríklad pri každom cykle cron) udržiava zrkadlo aktuálne; ak čitatelia potrebujú vidieť vlastné zápisy v zrkadle, zavolajte flush() s ID, ktoré ste zapísali počas požiadavky.

Dotazovanie

Dotazujte zrkadlo pomocou obyčajného SQL. table() vráti názov zrkadlenej tabuľky:

PHP
$pdo->query(
    'SELECT p.slug, COUNT(*) AS sales
     FROM ' . $mirror->table('purchases') . ' o
     INNER JOIN ' . $mirror->table('products') . ' p ON p.id = o.product_id
     GROUP BY p.slug
     ORDER BY sales DESC'
);

Prenos späť do súborov

pull() číta riadky zrkadla a v poradí podľa ID ich zapisuje do registrovaného úložiska. Podporuje dva postupy:

  • Obnovenie: súbory sú preč, ale zrkadlo zostalo. Zaregistrujte nové úložisko s rovnakým názvom kolekcie a načítajte údaje.
  • Naplnenie: riadky vložené externými nástrojmi do tabuľky zrkadla sa zmenia na záznamy storh. Riadky musia obsahovať platné identifikátory UUIDv7 a objekt v stĺpci data; typované stĺpce sa pri načítaní ignorujú, pretože data predstavuje celý záznam.
PHP
$restored = new Storh\DocStore($root, 'pages');
$mirror   = new SqlMirror($pdo);
$mirror->collection($restored, 'pages');
$mirror->pull();          // ['written' => n, 'unchanged' => m]

Zápisy načítané zo zrkadla prechádzajú bežným mechanizmom úložiska, takže sa uplatňuje validácia schémy aj jedinečné indexy a každý záznam sa zapisuje trvalo. pull() nikdy neodstraňuje lokálne záznamy a záznamy, ktorých údaje sa už zhodujú s riadkom v zrkadle, preskočí. Po vložení riadkov naplnených ručne raz spustite push(): prepíše tieto riadky v kanonickom tvare, aby sa ich hashe zosúladili.

Zmluva a obmedzenia

  • Súbory sú kanonické. Zrkadlo je výstup určený len na čítanie; všetko, čo sa doň ručne zapíše, prepíše alebo odstráni nasledujúce push().
  • Jedinečné stĺpce v zrkadle slúžia ako poistka, nie ako vynucovanie pri zápise: duplicita povolená súbormi sa prejaví ako neúspešné (a úplne vrátené) odoslanie. Na vynucovanie pri zápise použite jedinečné indexy storh.
  • Zrkadlo zaostáva za súbormi až o jeden interval odosielania, s výnimkou identifikátorov, ktoré výslovne flush().
  • Zrkadlenie nepridáva transakcie do samotného storh. Atómové zápisy viacerých záznamov zostávajú úlohou pre skutočnú databázu, ktorá slúži ako zdroj pravdy.
  • Zmeny schémy sa uplatňujú odstránením a opätovnou inštaláciou zrkadla: uninstall(), install(), push().