SQL Огледало
SqlMirror изпраща колекциите на storh към таблици в SQLite или MySQL, за да можете да изпълнявате съединения, сортиране между таблици, търсене на поднизове и отчети в SQL, докато файловете остават канонични. Представете си го като вторичен индекс, който се оказва база данни: огледалото е производно, може да бъде изхвърлено и може да се изгради отново по всяко време. ext-pdo с драйвера sqlite или mysql е необходим само когато го използвате; основният пакет не зависи от външни пакети.
Настройка
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:
$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 на записа).
Синхронизиране
$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() връща името на отразената таблица:
$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е целият запис.
$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().