fix: rename 000.sql to 000_migration.sql and wrap legacy conversion in transaction
All checks were successful
Check / check (pull_request) Successful in 3m14s
All checks were successful
Check / check (pull_request) Successful in 3m14s
- Rename bootstrap migration from 000.sql to 000_migration.sql per REPO_POLICIES.md naming convention (NNN_description.sql pattern) - Update all hardcoded references in migrations.go - Wrap rebuildMigrationsTable() DROP/CREATE/INSERT sequence in a single transaction for crash safety - Update test case filename to match renamed file
This commit is contained in:
@@ -83,8 +83,9 @@ func collectMigrations() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bootstrapMigrationsTable ensures the schema_migrations table exists by
|
// bootstrapMigrationsTable ensures the schema_migrations table exists by
|
||||||
// applying 000.sql if the table is missing. For databases with a legacy
|
// applying 000_migration.sql if the table is missing. For databases with a
|
||||||
// TEXT-based schema_migrations table, it converts to the new INTEGER format.
|
// legacy TEXT-based schema_migrations table, it converts to the new INTEGER
|
||||||
|
// format.
|
||||||
func bootstrapMigrationsTable(ctx context.Context, db *sql.DB, log *slog.Logger) error {
|
func bootstrapMigrationsTable(ctx context.Context, db *sql.DB, log *slog.Logger) error {
|
||||||
var tableExists int
|
var tableExists int
|
||||||
|
|
||||||
@@ -103,12 +104,12 @@ func bootstrapMigrationsTable(ctx context.Context, db *sql.DB, log *slog.Logger)
|
|||||||
return convertLegacyMigrations(ctx, db, log)
|
return convertLegacyMigrations(ctx, db, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyBootstrapMigration reads and executes 000.sql to create the
|
// applyBootstrapMigration reads and executes 000_migration.sql to create the
|
||||||
// schema_migrations table on a fresh database.
|
// schema_migrations table on a fresh database.
|
||||||
func applyBootstrapMigration(ctx context.Context, db *sql.DB, log *slog.Logger) error {
|
func applyBootstrapMigration(ctx context.Context, db *sql.DB, log *slog.Logger) error {
|
||||||
content, err := migrationsFS.ReadFile("migrations/000.sql")
|
content, err := migrationsFS.ReadFile("migrations/000_migration.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read bootstrap migration 000.sql: %w", err)
|
return fmt.Errorf("failed to read bootstrap migration 000_migration.sql: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if log != nil {
|
if log != nil {
|
||||||
@@ -211,31 +212,48 @@ func readLegacyVersions(ctx context.Context, db *sql.DB) ([]int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rebuildMigrationsTable drops the old schema_migrations table, recreates it
|
// rebuildMigrationsTable drops the old schema_migrations table, recreates it
|
||||||
// via 000.sql, and re-inserts the given integer versions.
|
// via 000_migration.sql, and re-inserts the given integer versions. The entire
|
||||||
|
// operation runs in a single transaction so a crash cannot lose migration data.
|
||||||
func rebuildMigrationsTable(ctx context.Context, db *sql.DB, versions []int) error {
|
func rebuildMigrationsTable(ctx context.Context, db *sql.DB, versions []int) error {
|
||||||
_, err := db.ExecContext(ctx, "DROP TABLE schema_migrations")
|
content, err := migrationsFS.ReadFile("migrations/000_migration.sql")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read bootstrap migration 000_migration.sql: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to begin transaction for legacy conversion: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = tx.ExecContext(ctx, "DROP TABLE schema_migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to drop legacy migrations table: %w", err)
|
return fmt.Errorf("failed to drop legacy migrations table: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := migrationsFS.ReadFile("migrations/000.sql")
|
_, err = tx.ExecContext(ctx, string(content))
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read bootstrap migration 000.sql: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.ExecContext(ctx, string(content))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create new migrations table: %w", err)
|
return fmt.Errorf("failed to create new migrations table: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range versions {
|
for _, v := range versions {
|
||||||
_, insErr := db.ExecContext(ctx,
|
_, err = tx.ExecContext(ctx,
|
||||||
"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)", v)
|
"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)", v)
|
||||||
if insErr != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to insert converted version %d: %w", v, insErr)
|
return fmt.Errorf("failed to insert converted version %d: %w", v, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to commit legacy conversion: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func TestParseMigrationVersion(t *testing.T) {
|
|||||||
wantVersion int
|
wantVersion int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{filename: "000.sql", wantVersion: 0},
|
{filename: "000_migration.sql", wantVersion: 0},
|
||||||
{filename: "001_initial.sql", wantVersion: 1},
|
{filename: "001_initial.sql", wantVersion: 1},
|
||||||
{filename: "002_remove_container_id.sql", wantVersion: 2},
|
{filename: "002_remove_container_id.sql", wantVersion: 2},
|
||||||
{filename: "007_add_resource_limits.sql", wantVersion: 7},
|
{filename: "007_add_resource_limits.sql", wantVersion: 7},
|
||||||
|
|||||||
Reference in New Issue
Block a user