feat(store): versioned migrations for handler-owned tables (#33) - #48
Merged
Conversation
The framework versioned its own schema (subdex_block via MIGRATOR/_sqlx_migrations) but handler entity tables were ad-hoc CREATE TABLE IF NOT EXISTS in init() — which can't express an evolution (a new column/index on an already-deployed DB), so a fresh DB and an upgraded one could silently diverge. - PgStore::run_handler_migrations(&Migrator, name): runs a handler's own embedded sqlx::migrate! set, tracked in a PER-HANDLER table (via dangerous_set_table_name) — isolated from the framework's _sqlx_migrations, so handlers never collide with each other or the framework. Applied once, in order, recorded; re-running is idempotent. - handler_migrations_table(name): pure sanitizer -> safe unquoted identifier ([a-z0-9_], fallback ). 3 unit tests. - Re-export sqlx's Migrator from subdex-store so handlers don't depend on sqlx directly. Note: sqlx's Migrator isn't Clone and the caller's is &'static, so we build an owned copy (all fields are Cow/bool) and point THAT at the handler's table, leaving the caller's untouched. Dogfood: multi-pallet AssetsHandler now owns migrations/assets/ (0001 create, 0002 add index) and applies them via the helper in init; BalancesHandler keeps the ad-hoc pattern for contrast. 2 new PG integration tests, VERIFIED LIVE (9/9 pass): applies once in order, recorded in its own table, framework's table untouched, re-run applies nothing new; two handlers get separate tables. Docs: architecture gains a 'Schema ownership: who migrates what' section; example README updated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #33.
Problem
The framework versions its own schema (
subdex_blockviaMIGRATOR, tracked in_sqlx_migrations), but handler entity tables were created ad-hoc withCREATE TABLE IF NOT EXISTSininit(). That pattern cannot express an evolution — adding a column or an index to an already-deployed database — so a fresh DB and an upgraded one could silently diverge, and users were on their own.Fix
PgStore::run_handler_migrations(&Migrator, name)— a handler embeds its own versioned set withsqlx::migrate!("./migrations/<name>")and runs it frominit:_sqlx_migrations_<name>, via sqlx'sdangerous_set_table_name) — isolated from the framework's_sqlx_migrations, so handlers never collide with each other or with the framework.initapplies nothing new; a fresh DB and an already-migrated one converge.handler_migrations_table(name)sanitizes to a safe unquoted identifier ([a-z0-9_], fallbackhandler) — 3 unit tests.Migratoris re-exported fromsubdex-storeso handlers don't depend onsqlxdirectly.Dogfood
The multi-pallet
AssetsHandlernow ownsmigrations/assets/(0001create table,0002add an index — exactly the evolution the old pattern couldn't do) and applies them via the helper.BalancesHandlerkeeps the ad-hocCREATE TABLE IF NOT EXISTSfor contrast.Acceptance criteria — verified live against real Postgres (9/9 pass)
handler_migrations_apply_once_in_order_and_are_idempotentasserts the table exists (0001), the v2 column exists (0002), and 2 rows are recorded in_sqlx_migrations_widgets.initis idempotent; partially-migrated DBs converge — the re-run applies nothing new (still 2).Also asserted: the framework's
_sqlx_migrationsis untouched (still 1 row) by handler migrations, and two handlers get separate tracking tables.Verification
fmt/clippy -D warnings/test/docall clean (default +--all-features); PG integration tests run live (9/9).