Към съдържанието

SQL Огледало

SqlMirror изпраща колекциите на storh към таблици в SQLite или MySQL, за да можете да изпълнявате съединения, сортиране между таблици, търсене на поднизове и отчети в SQL, докато файловете остават канонични. Представете си го като вторичен индекс, който се оказва база данни: огледалото е производно, може да бъде изхвърлено и може да се изгради отново по всяко време. ext-pdo с драйвера sqlite или mysql е необходим само когато го използвате; основният пакет не зависи от външни пакети.

Настройка

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();

И двете машини могат да се отразяват: колекции DocStore и потоци SegmentedLog (изпращат се само активните записи). Подаването на Schema е незадължително и независимо от хранилището: декларираните полета string/int/float/bool стават типизирани, индексирани колони; всичко останало остава достъпно за заявки в колоната data JSON. Полетата mixed не могат да бъдат маркирани за индексиране.

Връзки

Конструкторът приема манипулатор PDO (драйвер sqlite или mysql, разпознава се автоматично), манипулатор mysqli или която и да е реализация на 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_');

Пътят през mysqli работи и с двата режима за отчитане на грешки в mysqli, така че съществуващ манипулатор от хост приложението (например $wpdb->dbh на WordPress) може да се използва повторно без промени. Поведението е еднакво при всички драйвери; неуспешното изпращане отменя транзакцията на колекцията при всеки от тях.

Всяка таблица получава id (първичен ключ), hash (управлява постепенното изпращане), типизираните колони и data (пълния JSON на записа).

Синхронизиране

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() сравнява хешовете на записите с огледалото и записва всяка колекция в една транзакция, така че срив или неуспешно изпращане никога не оставя частично приложена партида. Непроменените записи изискват едно SELECT и обход на записите. Периодично push() (например при такт на cron) поддържа огледалото синхронизирано; извикайте flush() с идентификаторите, които сте записали по време на заявка, когато читателите трябва да виждат тези промени в огледалото веднага.

Изпълнение на заявки

Правете заявки към огледалото с обикновен SQL. table() връща името на отразената таблица:

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'
);

Връщане във файловете

pull() чете редовете от огледалото и ги записва в регистрираното хранилище, подредени по идентификатор. Поддържа два случая:

  • Възстановяване: файловете липсват, но огледалото е запазено. Регистрирайте ново хранилище със същото име на колекцията и извършете изтеглянето.
  • Подготовка на начални данни: редовете, заредени в таблицата на огледалото с външни инструменти, стават записи storh. Редовете трябва да съдържат валидни идентификатори UUIDv7 и обект в колоната data; типизираните колони се игнорират при изтеглянето, защото data е целият запис.
PHP
$restored = new Storh\DocStore($root, 'pages');
$mirror   = new SqlMirror($pdo);
$mirror->collection($restored, 'pages');
$mirror->pull();          // ['written' => n, 'unchanged' => m]

Записите, изтеглени обратно, преминават през обичайните механизми на хранилището, така че се прилагат проверката на схемата и уникалните индекси, а всеки запис се съхранява трайно. pull() никога не изтрива локални записи и пропуска записите, чиито данни вече съвпадат с реда в огледалото. След добавяне на редове ръчно, изпълнете push() веднъж: той ги презаписва в каноничен формат, за да се синхронизират хешовете.

Правила и ограничения

  • Файловете са канонични. Огледалото е изход само за четене; всичко, записано ръчно в него, се презаписва или изтрива при следващото push().
  • Уникалните колони в огледалото са допълнителна защита, а не проверка при запис: дубликат, допуснат от файловете, води до неуспешно (и изцяло отменено) изпращане. Използвайте уникалните индекси storh за проверка при запис.
  • Огледалото изостава от файловете с до един интервал между изпращанията, с изключение на идентификаторите, които изрично flush().
  • Отразяването не добавя транзакции към самото storh. Атомарните записи с няколко записа остават задача за реална база данни като основно хранилище.
  • Промените в схемата се прилагат чрез премахване и повторно инсталиране на огледалото: uninstall(), install(), push().