Skip to content

Commit 5c7c151

Browse files
authored
Stand up DB migrations now that the app is mature enough (#229)
1 parent 416122e commit 5c7c151

File tree

8 files changed

+372
-181
lines changed

8 files changed

+372
-181
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package migrations
2+
3+
import (
4+
"context"
5+
6+
"dkhalife.com/tasks/core/internal/models"
7+
"gorm.io/gorm"
8+
)
9+
10+
func init() {
11+
Register(&InitialSchemaMigration{})
12+
}
13+
14+
type InitialSchemaMigration struct{}
15+
16+
func (m *InitialSchemaMigration) Version() int {
17+
return 1
18+
}
19+
20+
func (m *InitialSchemaMigration) Name() string {
21+
return "initial_schema"
22+
}
23+
24+
func (m *InitialSchemaMigration) Up(ctx context.Context, db *gorm.DB) error {
25+
tables := []interface{}{
26+
&models.User{},
27+
&models.UserPasswordReset{},
28+
&models.AppToken{},
29+
&models.Label{},
30+
&models.Task{},
31+
&models.TaskLabel{},
32+
&models.TaskHistory{},
33+
&models.NotificationSettings{},
34+
&models.Notification{},
35+
}
36+
37+
for _, table := range tables {
38+
if err := db.WithContext(ctx).AutoMigrate(table); err != nil {
39+
return err
40+
}
41+
}
42+
43+
return nil
44+
}
45+
46+
func (m *InitialSchemaMigration) Down(ctx context.Context, db *gorm.DB) error {
47+
tables := []string{
48+
"notifications",
49+
"notification_settings",
50+
"task_histories",
51+
"task_labels",
52+
"tasks",
53+
"labels",
54+
"app_tokens",
55+
"user_password_resets",
56+
"users",
57+
}
58+
59+
for _, table := range tables {
60+
if err := db.WithContext(ctx).Exec("DROP TABLE IF EXISTS " + table + " CASCADE").Error; err != nil {
61+
return err
62+
}
63+
}
64+
65+
return nil
66+
}

apiserver/internal/migrations/base.go

Lines changed: 0 additions & 99 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package migrations
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"sort"
8+
"sync"
9+
"time"
10+
11+
"gorm.io/gorm"
12+
)
13+
14+
type Migration interface {
15+
Version() int
16+
Name() string
17+
Up(ctx context.Context, db *gorm.DB) error
18+
Down(ctx context.Context, db *gorm.DB) error
19+
}
20+
21+
type SchemaVersion struct {
22+
Version int `gorm:"primaryKey"`
23+
Name string `gorm:"size:255;not null"`
24+
AppliedAt time.Time `gorm:"not null"`
25+
}
26+
27+
func (SchemaVersion) TableName() string {
28+
return "schema_versions"
29+
}
30+
31+
var (
32+
registry = make(map[int]Migration)
33+
registryLock sync.RWMutex
34+
)
35+
36+
func Register(m Migration) {
37+
registryLock.Lock()
38+
defer registryLock.Unlock()
39+
40+
version := m.Version()
41+
if existing, ok := registry[version]; ok {
42+
panic(fmt.Sprintf("migration version %d already registered by %q, cannot register %q",
43+
version, existing.Name(), m.Name()))
44+
}
45+
registry[version] = m
46+
log.Printf("Registered migration %d: %s", version, m.Name())
47+
}
48+
49+
func GetMigrations() []Migration {
50+
registryLock.RLock()
51+
defer registryLock.RUnlock()
52+
53+
migrations := make([]Migration, 0, len(registry))
54+
for _, m := range registry {
55+
migrations = append(migrations, m)
56+
}
57+
58+
sort.Slice(migrations, func(i, j int) bool {
59+
return migrations[i].Version() < migrations[j].Version()
60+
})
61+
62+
return migrations
63+
}
64+
65+
func GetMigration(version int) (Migration, bool) {
66+
registryLock.RLock()
67+
defer registryLock.RUnlock()
68+
69+
m, ok := registry[version]
70+
return m, ok
71+
}
72+
73+
func GetLatestVersion() int {
74+
registryLock.RLock()
75+
defer registryLock.RUnlock()
76+
77+
latest := 0
78+
for version := range registry {
79+
if version > latest {
80+
latest = version
81+
}
82+
}
83+
return latest
84+
}

0 commit comments

Comments
 (0)