Skip to content

1525-06: Introduce schema migrations #1719

@josecelano

Description

@josecelano

Goal

Replace the raw DDL in the async SQLite and MySQL drivers with sqlx::migrate!(), making schema evolution explicit, versioned, and aligned across all SQL backends.

Why

After subissue 1525-05 the drivers still own their schema through hand-written CREATE TABLE IF NOT EXISTS statements. That has no history, no ordering guarantees, and no safe way to apply incremental schema changes. sqlx::migrate!() provides versioned SQL files, automatic up-migration on startup, and a _sqlx_migrations tracking table — a foundation required before PostgreSQL can be added (1525-08).

Spec

The detailed implementation spec is the source of truth:

docs/issues/1525-06-introduce-schema-migrations.md

Summary

  1. Verify the three existing migration files under packages/tracker-core/migrations/{sqlite,mysql}/ match the schema produced by 1525-05.
  2. Enable sqlx's macros feature; declare a static MIGRATOR: Migrator = sqlx::migrate!("migrations/<backend>") in each driver; add Error::migration_error() wrapping sqlx::migrate::MigrateError.
  3. Add a bootstrap_legacy_schema() helper to handle pre-v4 databases without _sqlx_migrations (fake-apply the three pre-existing migrations after verifying preconditions).
  4. Wire create_database_tables() to call bootstrap_legacy_schema() then MIGRATOR.run(). Fix drop_database_tables() to also drop _sqlx_migrations and torrent_aggregate_metrics (all five drops use DROP TABLE IF EXISTS).
  5. Update packages/tracker-core/migrations/README.md to document automatic migration, file immutability, and the v4 upgrade prerequisite.
  6. Add tests for fresh-database, idempotency, drop/create cycle, legacy bootstrap, and partial-migration guard scenarios.

History-alignment pattern

All backends share the same set of migration filenames/timestamps. Migrations that are no-ops for a backend remain as comment-only files. PostgreSQL (1525-08) starts from migration 1, not a catch-up.

Acceptance Criteria

  • sqlx::migrate!() is used in both drivers; no raw DDL remains in create_database_tables().
  • bootstrap_legacy_schema() verifies migrations 2 and 3 were applied before fake-applying, returning a descriptive error otherwise.
  • drop_database_tables() drops all five tables (including _sqlx_migrations and torrent_aggregate_metrics) using DROP TABLE IF EXISTS.
  • Error::migration_error() wraps sqlx::migrate::MigrateError.
  • packages/tracker-core/migrations/README.md documents the new automatic migration behavior and v4 upgrade requirement.
  • Tests cover: fresh database, idempotency, drop/create cycle, legacy bootstrap, partial-migration guard.
  • The v4 changelog/upgrade guide documents the pre-upgrade requirement (apply all three manual migrations before upgrading).
  • cargo test --workspace --all-targets passes.
  • linter all exits with code 0.

Parent EPIC

#1525

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions