Skip to content

Commit b3453c9

Browse files
authored
fix: database migration (#980)
1 parent 48031b2 commit b3453c9

File tree

10 files changed

+67
-19
lines changed

10 files changed

+67
-19
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
tmp
2-
gorm.db
3-
gorm.db-journal
42
coverage.out
53
/backend
64
dist/
@@ -17,3 +15,6 @@ package.json
1715

1816
# Debugging binaries
1917
__debug_bin*
18+
19+
# Database
20+
/data/**

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
default_stages: [commit]
22
repos:
33
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
4-
rev: v9.12.0
4+
# Waiting for new release, see https://github.com/alessandrojcm/commitlint-pre-commit-hook/issues/152
5+
rev: 46ad8d10517771202384ef846ec4a5aa17e6ad26
56
hooks:
67
- id: commitlint
78
stages: [commit-msg]

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func main() {
6060
log.Fatal().Err(err).Msg("Failed to create database directory")
6161
}
6262

63-
err = models.Connect("data/gorm.db?_pragma=foreign_keys(1)")
63+
err = models.Connect("data/gorm.db")
6464
if err != nil {
6565
log.Fatal().Msg(err.Error())
6666
}

pkg/controllers/healthz/healthz_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package healthz_test
22

33
import (
4-
"fmt"
54
"net/http"
65
"net/http/httptest"
76
"testing"
@@ -31,7 +30,7 @@ func TestOptions(t *testing.T) {
3130
}
3231

3332
func TestGet(t *testing.T) {
34-
require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", test.TmpFile(t))))
33+
require.Nil(t, models.Connect(test.TmpFile(t)))
3534

3635
t.Parallel()
3736
recorder := httptest.NewRecorder()

pkg/controllers/v4/test_suite_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77

88
"github.com/envelope-zero/backend/v5/pkg/models"
9+
"github.com/envelope-zero/backend/v5/test"
910
"github.com/stretchr/testify/suite"
1011
)
1112

@@ -35,7 +36,7 @@ func (suite *TestSuiteStandard) TearDownTest() {
3536

3637
// SetupTest is called before each test in the suite.
3738
func (suite *TestSuiteStandard) SetupTest() {
38-
err := models.Connect(":memory:?_pragma=foreign_keys(1)")
39+
err := models.Connect(test.TmpFile(suite.T()))
3940
if err != nil {
4041
log.Fatalf("Database initialization failed with: %#v", err)
4142
}

pkg/importer/parser/ynab4/parse_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/envelope-zero/backend/v5/pkg/importer"
1616
"github.com/envelope-zero/backend/v5/pkg/importer/parser/ynab4"
1717
"github.com/envelope-zero/backend/v5/pkg/models"
18+
"github.com/envelope-zero/backend/v5/test"
1819
"github.com/shopspring/decimal"
1920
"github.com/stretchr/testify/assert"
2021
"github.com/stretchr/testify/require"
@@ -28,9 +29,9 @@ func date(year int, month time.Month, day int) time.Time {
2829
}
2930

3031
// testDB returns an in-memory test database and a function to close it.
31-
func testDB() (*gorm.DB, func() error) {
32+
func testDB(t *testing.T) (*gorm.DB, func() error) {
3233
// Connect a database
33-
err := models.Connect(":memory:?_pragma=foreign_keys(1)")
34+
err := models.Connect(test.TmpFile(t))
3435
if err != nil {
3536
log.Fatalf("Database connection failed with: %#v", err)
3637
}
@@ -88,7 +89,7 @@ func TestParse(t *testing.T) {
8889
require.Nil(t, err, "Parsing failed", err)
8990

9091
// Create test database and import
91-
db, closeDb := testDB()
92+
db, closeDb := testDB(t)
9293
defer closeDb()
9394

9495
b, err := importer.Create(db, r)

pkg/models/database.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,39 @@ func Connect(dsn string) error {
2929
Logger: gorm_zerolog.New(),
3030
}
3131

32+
// Migration with foreign keys disabled since we're dropping tables
33+
// during migration
34+
//
35+
// sqlite does not support ALTER COLUMN, so tables are copied to a temporary table,
36+
// then the table is dropped and recreated
3237
db, err := gorm.Open(sqlite.Open(dsn), config)
3338
if err != nil {
3439
return fmt.Errorf("failed to connect to database: %w", err)
3540
}
3641

42+
err = migrate(db)
43+
if err != nil {
44+
return err
45+
}
46+
47+
// Close the connection
3748
sqlDB, err := db.DB()
3849
if err != nil {
3950
return fmt.Errorf("failed to get database object: %w", err)
4051
}
52+
sqlDB.Close()
53+
54+
// Now, reconnect with foreign keys enabled
55+
dsn = fmt.Sprintf("%s?_pragma=foreign_keys(1)", dsn)
56+
db, err = gorm.Open(sqlite.Open(dsn), config)
57+
if err != nil {
58+
return fmt.Errorf("failed to connect to database: %w", err)
59+
}
60+
61+
sqlDB, err = db.DB()
62+
if err != nil {
63+
return fmt.Errorf("failed to get database object: %w", err)
64+
}
4165

4266
// Get new connections after one hour
4367
sqlDB.SetConnMaxLifetime(time.Hour)
@@ -47,11 +71,6 @@ func Connect(dsn string) error {
4771
sqlDB.SetMaxIdleConns(1)
4872
sqlDB.SetMaxOpenConns(1)
4973

50-
err = migrate(db)
51-
if err != nil {
52-
return err
53-
}
54-
5574
// Query callbacks
5675
err = db.Callback().Query().After("*").Register("envelope_zero:after_query", queryCallback)
5776
if err != nil {

pkg/models/database_test.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package models_test
22

33
import (
4-
"fmt"
4+
"os"
55
"testing"
66

77
"github.com/envelope-zero/backend/v5/pkg/models"
@@ -13,13 +13,38 @@ func TestMigrateWithExistingDB(t *testing.T) {
1313
testDB := test.TmpFile(t)
1414

1515
// Migrate the database once
16-
require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", testDB)))
16+
require.Nil(t, models.Connect(testDB))
1717

1818
// Close the connection
1919
sqlDB, err := models.DB.DB()
2020
require.Nil(t, err)
2121
sqlDB.Close()
2222

2323
// Migrate it again
24-
require.Nil(t, models.Connect(fmt.Sprintf("%s?_pragma=foreign_keys(1)", testDB)))
24+
require.Nil(t, models.Connect(testDB))
25+
}
26+
27+
// TestV4V5Migration tests the migration from v4 to v5
28+
func TestV4V5Migration(t *testing.T) {
29+
dbFile := test.TmpFile(t)
30+
31+
input, err := os.ReadFile("../../testdata/migrations/v4-v5.db")
32+
if err != nil {
33+
t.Error("Could not read test database")
34+
}
35+
err = os.WriteFile(dbFile, input, 0o644)
36+
if err != nil {
37+
t.Error("Could not create temporary copy for database")
38+
}
39+
40+
// Connect to the database
41+
require.Nil(t, models.Connect(dbFile))
42+
43+
// Close the connection
44+
sqlDB, err := models.DB.DB()
45+
require.Nil(t, err)
46+
sqlDB.Close()
47+
48+
// Reconnect
49+
require.Nil(t, models.Connect(dbFile))
2550
}

pkg/models/test_suite_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77

88
"github.com/envelope-zero/backend/v5/pkg/models"
9+
"github.com/envelope-zero/backend/v5/test"
910
"github.com/google/uuid"
1011
"github.com/stretchr/testify/suite"
1112
)
@@ -32,7 +33,7 @@ func (suite *TestSuiteStandard) TearDownTest() {
3233

3334
// SetupTest is called before each test in the suite.
3435
func (suite *TestSuiteStandard) SetupTest() {
35-
err := models.Connect(":memory:?_pragma=foreign_keys(1)")
36+
err := models.Connect(test.TmpFile(suite.T()))
3637
if err != nil {
3738
log.Fatalf("Database connection failed with: %#v", err)
3839
}
Binary file not shown.

0 commit comments

Comments
 (0)