From b3453c9f32c1f3980dafb47e94d3c408ad9a451d Mon Sep 17 00:00:00 2001 From: morre Date: Fri, 1 Mar 2024 18:03:53 +0100 Subject: [PATCH] fix: database migration (#980) --- .gitignore | 5 +-- .pre-commit-config.yaml | 3 +- main.go | 2 +- pkg/controllers/healthz/healthz_test.go | 3 +- pkg/controllers/v4/test_suite_test.go | 3 +- pkg/importer/parser/ynab4/parse_test.go | 7 ++-- pkg/models/database.go | 29 +++++++++++++--- pkg/models/database_test.go | 31 ++++++++++++++++-- pkg/models/test_suite_test.go | 3 +- .../{overspend-handling.db => v4-v5.db} | Bin 167936 -> 167936 bytes 10 files changed, 67 insertions(+), 19 deletions(-) rename testdata/migrations/{overspend-handling.db => v4-v5.db} (62%) diff --git a/.gitignore b/.gitignore index ccced3e9..5c3e8d76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ tmp -gorm.db -gorm.db-journal coverage.out /backend dist/ @@ -17,3 +15,6 @@ package.json # Debugging binaries __debug_bin* + +# Database +/data/** diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 031b1053..faa6f708 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,8 @@ default_stages: [commit] repos: - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook - rev: v9.12.0 + # Waiting for new release, see https://github.com/alessandrojcm/commitlint-pre-commit-hook/issues/152 + rev: 46ad8d10517771202384ef846ec4a5aa17e6ad26 hooks: - id: commitlint stages: [commit-msg] diff --git a/main.go b/main.go index 839ad008..a7c69b3b 100644 --- a/main.go +++ b/main.go @@ -60,7 +60,7 @@ func main() { log.Fatal().Err(err).Msg("Failed to create database directory") } - err = models.Connect("data/gorm.db?_pragma=foreign_keys(1)") + err = models.Connect("data/gorm.db") if err != nil { log.Fatal().Msg(err.Error()) } diff --git a/pkg/controllers/healthz/healthz_test.go b/pkg/controllers/healthz/healthz_test.go index 02ec5084..e2adaab2 100644 --- a/pkg/controllers/healthz/healthz_test.go +++ b/pkg/controllers/healthz/healthz_test.go @@ -1,7 +1,6 @@ package healthz_test import ( - "fmt" "net/http" "net/http/httptest" "testing" @@ -31,7 +30,7 @@ func TestOptions(t *testing.T) { } func TestGet(t *testing.T) { - require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", test.TmpFile(t)))) + require.Nil(t, models.Connect(test.TmpFile(t))) t.Parallel() recorder := httptest.NewRecorder() diff --git a/pkg/controllers/v4/test_suite_test.go b/pkg/controllers/v4/test_suite_test.go index 14b281e1..5d15a9b7 100644 --- a/pkg/controllers/v4/test_suite_test.go +++ b/pkg/controllers/v4/test_suite_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/envelope-zero/backend/v5/pkg/models" + "github.com/envelope-zero/backend/v5/test" "github.com/stretchr/testify/suite" ) @@ -35,7 +36,7 @@ func (suite *TestSuiteStandard) TearDownTest() { // SetupTest is called before each test in the suite. func (suite *TestSuiteStandard) SetupTest() { - err := models.Connect(":memory:?_pragma=foreign_keys(1)") + err := models.Connect(test.TmpFile(suite.T())) if err != nil { log.Fatalf("Database initialization failed with: %#v", err) } diff --git a/pkg/importer/parser/ynab4/parse_test.go b/pkg/importer/parser/ynab4/parse_test.go index 37619f70..5612c06e 100644 --- a/pkg/importer/parser/ynab4/parse_test.go +++ b/pkg/importer/parser/ynab4/parse_test.go @@ -15,6 +15,7 @@ import ( "github.com/envelope-zero/backend/v5/pkg/importer" "github.com/envelope-zero/backend/v5/pkg/importer/parser/ynab4" "github.com/envelope-zero/backend/v5/pkg/models" + "github.com/envelope-zero/backend/v5/test" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -28,9 +29,9 @@ func date(year int, month time.Month, day int) time.Time { } // testDB returns an in-memory test database and a function to close it. -func testDB() (*gorm.DB, func() error) { +func testDB(t *testing.T) (*gorm.DB, func() error) { // Connect a database - err := models.Connect(":memory:?_pragma=foreign_keys(1)") + err := models.Connect(test.TmpFile(t)) if err != nil { log.Fatalf("Database connection failed with: %#v", err) } @@ -88,7 +89,7 @@ func TestParse(t *testing.T) { require.Nil(t, err, "Parsing failed", err) // Create test database and import - db, closeDb := testDB() + db, closeDb := testDB(t) defer closeDb() b, err := importer.Create(db, r) diff --git a/pkg/models/database.go b/pkg/models/database.go index a43b5b7d..63ae82d6 100644 --- a/pkg/models/database.go +++ b/pkg/models/database.go @@ -29,15 +29,39 @@ func Connect(dsn string) error { Logger: gorm_zerolog.New(), } + // Migration with foreign keys disabled since we're dropping tables + // during migration + // + // sqlite does not support ALTER COLUMN, so tables are copied to a temporary table, + // then the table is dropped and recreated db, err := gorm.Open(sqlite.Open(dsn), config) if err != nil { return fmt.Errorf("failed to connect to database: %w", err) } + err = migrate(db) + if err != nil { + return err + } + + // Close the connection sqlDB, err := db.DB() if err != nil { return fmt.Errorf("failed to get database object: %w", err) } + sqlDB.Close() + + // Now, reconnect with foreign keys enabled + dsn = fmt.Sprintf("%s?_pragma=foreign_keys(1)", dsn) + db, err = gorm.Open(sqlite.Open(dsn), config) + if err != nil { + return fmt.Errorf("failed to connect to database: %w", err) + } + + sqlDB, err = db.DB() + if err != nil { + return fmt.Errorf("failed to get database object: %w", err) + } // Get new connections after one hour sqlDB.SetConnMaxLifetime(time.Hour) @@ -47,11 +71,6 @@ func Connect(dsn string) error { sqlDB.SetMaxIdleConns(1) sqlDB.SetMaxOpenConns(1) - err = migrate(db) - if err != nil { - return err - } - // Query callbacks err = db.Callback().Query().After("*").Register("envelope_zero:after_query", queryCallback) if err != nil { diff --git a/pkg/models/database_test.go b/pkg/models/database_test.go index e1c88ad3..0a856cd2 100644 --- a/pkg/models/database_test.go +++ b/pkg/models/database_test.go @@ -1,7 +1,7 @@ package models_test import ( - "fmt" + "os" "testing" "github.com/envelope-zero/backend/v5/pkg/models" @@ -13,7 +13,7 @@ func TestMigrateWithExistingDB(t *testing.T) { testDB := test.TmpFile(t) // Migrate the database once - require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", testDB))) + require.Nil(t, models.Connect(testDB)) // Close the connection sqlDB, err := models.DB.DB() @@ -21,5 +21,30 @@ func TestMigrateWithExistingDB(t *testing.T) { sqlDB.Close() // Migrate it again - require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", testDB))) + require.Nil(t, models.Connect(testDB)) +} + +// TestV4V5Migration tests the migration from v4 to v5 +func TestV4V5Migration(t *testing.T) { + dbFile := test.TmpFile(t) + + input, err := os.ReadFile("../../testdata/migrations/v4-v5.db") + if err != nil { + t.Error("Could not read test database") + } + err = os.WriteFile(dbFile, input, 0o644) + if err != nil { + t.Error("Could not create temporary copy for database") + } + + // Connect to the database + require.Nil(t, models.Connect(dbFile)) + + // Close the connection + sqlDB, err := models.DB.DB() + require.Nil(t, err) + sqlDB.Close() + + // Reconnect + require.Nil(t, models.Connect(dbFile)) } diff --git a/pkg/models/test_suite_test.go b/pkg/models/test_suite_test.go index f7347ad3..861eebe7 100644 --- a/pkg/models/test_suite_test.go +++ b/pkg/models/test_suite_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/envelope-zero/backend/v5/pkg/models" + "github.com/envelope-zero/backend/v5/test" "github.com/google/uuid" "github.com/stretchr/testify/suite" ) @@ -32,7 +33,7 @@ func (suite *TestSuiteStandard) TearDownTest() { // SetupTest is called before each test in the suite. func (suite *TestSuiteStandard) SetupTest() { - err := models.Connect(":memory:?_pragma=foreign_keys(1)") + err := models.Connect(test.TmpFile(suite.T())) if err != nil { log.Fatalf("Database connection failed with: %#v", err) } diff --git a/testdata/migrations/overspend-handling.db b/testdata/migrations/v4-v5.db similarity index 62% rename from testdata/migrations/overspend-handling.db rename to testdata/migrations/v4-v5.db index 4d8c6620528ae6483c689d0fe56225414a9ff606..b8a8c5d06915a7394827398ecaad1e0eefc66813 100644 GIT binary patch literal 167936 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 V|2MGr_x5{Ouzo!4|DFB+{(q5aZ+id$ literal 167936 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 WYmC)GyhOfRqF9b8+;BOr=l>rNFdcOO