fix: add idempotency check to migration 028 (tombstone_closed_at)
Migration 028 lacked an idempotency check, causing it to fail on databases where the migration had already been applied. The migration would attempt to copy data from issues to issues_new, but both tables had the same CHECK constraint, causing the insert to fail. Added check for "status = 'tombstone'" in the table schema to detect if the migration has already been applied and skip if so. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package migrations
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MigrateTombstoneClosedAt updates the closed_at constraint to allow tombstones
|
// MigrateTombstoneClosedAt updates the closed_at constraint to allow tombstones
|
||||||
@@ -22,8 +23,20 @@ func MigrateTombstoneClosedAt(db *sql.DB) error {
|
|||||||
// SQLite doesn't support ALTER TABLE to modify CHECK constraints
|
// SQLite doesn't support ALTER TABLE to modify CHECK constraints
|
||||||
// We must recreate the table with the new constraint
|
// We must recreate the table with the new constraint
|
||||||
|
|
||||||
|
// Idempotency check: see if the new CHECK constraint already exists
|
||||||
|
// The new constraint contains "status = 'tombstone'" which the old one didn't
|
||||||
|
var tableSql string
|
||||||
|
err := db.QueryRow(`SELECT sql FROM sqlite_master WHERE type='table' AND name='issues'`).Scan(&tableSql)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get issues table schema: %w", err)
|
||||||
|
}
|
||||||
|
// If the schema already has the tombstone clause, migration is already applied
|
||||||
|
if strings.Contains(tableSql, "status = 'tombstone'") || strings.Contains(tableSql, `status = "tombstone"`) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Step 0: Drop views that depend on the issues table
|
// Step 0: Drop views that depend on the issues table
|
||||||
_, err := db.Exec(`DROP VIEW IF EXISTS ready_issues`)
|
_, err = db.Exec(`DROP VIEW IF EXISTS ready_issues`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to drop ready_issues view: %w", err)
|
return fmt.Errorf("failed to drop ready_issues view: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user