Skip to content

Commit 428402e

Browse files
authored
Support mariadb 12 and sqlite migrations properly (#243)
1 parent 0679ac1 commit 428402e

2 files changed

Lines changed: 82 additions & 41 deletions

File tree

apiserver/internal/migrations/001_initial_schema.go

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package migrations
22

33
import (
44
"context"
5+
"fmt"
56

67
"gorm.io/gorm"
78
)
@@ -21,45 +22,69 @@ func (m *InitialSchemaMigration) Name() string {
2122
}
2223

2324
func (m *InitialSchemaMigration) Up(ctx context.Context, db *gorm.DB) error {
25+
dialect := db.Dialector.Name()
26+
27+
var (
28+
autoInc string
29+
strCol string
30+
idxIne string
31+
tokenIdxCol string
32+
)
33+
34+
switch dialect {
35+
case "sqlite":
36+
autoInc = "AUTOINCREMENT"
37+
strCol = "TEXT"
38+
idxIne = "IF NOT EXISTS "
39+
tokenIdxCol = "token"
40+
case "mysql":
41+
autoInc = "AUTO_INCREMENT"
42+
strCol = "VARCHAR(255)"
43+
idxIne = ""
44+
tokenIdxCol = "token(255)"
45+
default:
46+
return fmt.Errorf("unsupported dialect: %s", dialect)
47+
}
48+
2449
statements := []string{
25-
`CREATE TABLE IF NOT EXISTS users (
26-
id INTEGER PRIMARY KEY AUTOINCREMENT,
27-
display_name TEXT NOT NULL DEFAULT '',
28-
email TEXT NOT NULL DEFAULT '' UNIQUE,
29-
password TEXT NOT NULL DEFAULT '',
50+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS users (
51+
id INTEGER PRIMARY KEY %s,
52+
display_name %s NOT NULL DEFAULT '',
53+
email %s NOT NULL DEFAULT '' UNIQUE,
54+
password %s NOT NULL DEFAULT '',
3055
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
3156
updated_at DATETIME DEFAULT NULL,
3257
disabled BOOLEAN DEFAULT false
33-
)`,
58+
)`, autoInc, strCol, strCol, strCol),
3459
`CREATE TABLE IF NOT EXISTS user_password_resets (
3560
user_id INTEGER NOT NULL PRIMARY KEY,
3661
email TEXT NOT NULL,
3762
token TEXT NOT NULL,
3863
expiration_date DATETIME NOT NULL
3964
)`,
40-
`CREATE TABLE IF NOT EXISTS app_tokens (
41-
id INTEGER PRIMARY KEY AUTOINCREMENT,
65+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS app_tokens (
66+
id INTEGER PRIMARY KEY %s,
4267
user_id INTEGER NOT NULL,
43-
name TEXT NOT NULL,
44-
token TEXT NOT NULL,
68+
name %s NOT NULL,
69+
token %s NOT NULL,
4570
scopes TEXT,
4671
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
4772
expires_at DATETIME DEFAULT CURRENT_TIMESTAMP,
4873
CONSTRAINT fk_users_app_tokens FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
49-
)`,
50-
`CREATE INDEX IF NOT EXISTS idx_app_tokens_token ON app_tokens(token)`,
51-
`CREATE TABLE IF NOT EXISTS labels (
52-
id INTEGER PRIMARY KEY AUTOINCREMENT,
53-
name TEXT NOT NULL,
74+
)`, autoInc, strCol, strCol),
75+
fmt.Sprintf(`CREATE INDEX %sidx_app_tokens_token ON app_tokens(%s)`, idxIne, tokenIdxCol),
76+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS labels (
77+
id INTEGER PRIMARY KEY %s,
78+
name %s NOT NULL,
5479
color VARCHAR(7) NOT NULL,
5580
created_by INTEGER NOT NULL,
5681
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
5782
updated_at DATETIME DEFAULT NULL,
5883
CONSTRAINT fk_users_labels FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE
59-
)`,
60-
`CREATE INDEX IF NOT EXISTS idx_labels_created_by ON labels(created_by)`,
61-
`CREATE TABLE IF NOT EXISTS tasks (
62-
id INTEGER PRIMARY KEY AUTOINCREMENT,
84+
)`, autoInc, strCol),
85+
fmt.Sprintf(`CREATE INDEX %sidx_labels_created_by ON labels(created_by)`, idxIne),
86+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS tasks (
87+
id INTEGER PRIMARY KEY %s,
6388
title TEXT NOT NULL,
6489
frequency_type VARCHAR(9),
6590
frequency_on VARCHAR(18) DEFAULT NULL,
@@ -79,25 +104,25 @@ func (m *InitialSchemaMigration) Up(ctx context.Context, db *gorm.DB) error {
79104
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
80105
updated_at DATETIME DEFAULT NULL,
81106
CONSTRAINT fk_users_tasks FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE
82-
)`,
83-
`CREATE INDEX IF NOT EXISTS idx_tasks_next_due_date ON tasks(next_due_date)`,
84-
`CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)`,
85-
`CREATE INDEX IF NOT EXISTS idx_tasks_is_active ON tasks(is_active)`,
107+
)`, autoInc),
108+
fmt.Sprintf(`CREATE INDEX %sidx_tasks_next_due_date ON tasks(next_due_date)`, idxIne),
109+
fmt.Sprintf(`CREATE INDEX %sidx_tasks_created_by ON tasks(created_by)`, idxIne),
110+
fmt.Sprintf(`CREATE INDEX %sidx_tasks_is_active ON tasks(is_active)`, idxIne),
86111
`CREATE TABLE IF NOT EXISTS task_labels (
87112
task_id INTEGER NOT NULL,
88113
label_id INTEGER NOT NULL,
89114
PRIMARY KEY (task_id, label_id),
90115
CONSTRAINT fk_task_labels_task FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
91116
CONSTRAINT fk_task_labels_label FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE
92117
)`,
93-
`CREATE TABLE IF NOT EXISTS task_histories (
94-
id INTEGER PRIMARY KEY AUTOINCREMENT,
118+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS task_histories (
119+
id INTEGER PRIMARY KEY %s,
95120
task_id INTEGER NOT NULL,
96121
completed_date DATETIME,
97122
due_date DATETIME,
98123
CONSTRAINT fk_tasks_history FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE
99-
)`,
100-
`CREATE INDEX IF NOT EXISTS idx_task_histories_task_id ON task_histories(task_id)`,
124+
)`, autoInc),
125+
fmt.Sprintf(`CREATE INDEX %sidx_task_histories_task_id ON task_histories(task_id)`, idxIne),
101126
`CREATE TABLE IF NOT EXISTS notification_settings (
102127
user_id INTEGER NOT NULL,
103128
notifications_provider_type VARCHAR(7),
@@ -110,8 +135,8 @@ func (m *InitialSchemaMigration) Up(ctx context.Context, db *gorm.DB) error {
110135
notifications_triggers_overdue BOOLEAN DEFAULT false,
111136
CONSTRAINT fk_users_notification_settings FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
112137
)`,
113-
`CREATE TABLE IF NOT EXISTS notifications (
114-
id INTEGER PRIMARY KEY AUTOINCREMENT,
138+
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS notifications (
139+
id INTEGER PRIMARY KEY %s,
115140
task_id INTEGER NOT NULL,
116141
user_id INTEGER NOT NULL,
117142
text TEXT NOT NULL,
@@ -121,11 +146,11 @@ func (m *InitialSchemaMigration) Up(ctx context.Context, db *gorm.DB) error {
121146
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
122147
CONSTRAINT fk_tasks_notifications FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
123148
CONSTRAINT fk_users_notifications FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
124-
)`,
125-
`CREATE INDEX IF NOT EXISTS idx_notifications_task_id ON notifications(task_id)`,
126-
`CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications(user_id)`,
127-
`CREATE INDEX IF NOT EXISTS idx_notifications_is_sent ON notifications(is_sent)`,
128-
`CREATE INDEX IF NOT EXISTS idx_notifications_scheduled_for ON notifications(scheduled_for)`,
149+
)`, autoInc),
150+
fmt.Sprintf(`CREATE INDEX %sidx_notifications_task_id ON notifications(task_id)`, idxIne),
151+
fmt.Sprintf(`CREATE INDEX %sidx_notifications_user_id ON notifications(user_id)`, idxIne),
152+
fmt.Sprintf(`CREATE INDEX %sidx_notifications_is_sent ON notifications(is_sent)`, idxIne),
153+
fmt.Sprintf(`CREATE INDEX %sidx_notifications_scheduled_for ON notifications(scheduled_for)`, idxIne),
129154
}
130155

131156
for _, stmt := range statements {

apiserver/internal/migrations/002_entra_auth.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,21 @@ func (m *EntraAuthMigration) Up(ctx context.Context, db *gorm.DB) error {
4949
}
5050

5151
if !migrator.HasIndex("users", "idx_users_entra_id") {
52-
var indexSQL string
5352
switch dialect {
5453
case "sqlite":
55-
indexSQL = "CREATE UNIQUE INDEX idx_users_entra_id ON users(directory_id, object_id) WHERE directory_id != '' AND object_id != ''"
54+
if err := dbCtx.Exec("CREATE UNIQUE INDEX idx_users_entra_id ON users(directory_id, object_id) WHERE directory_id != '' AND object_id != ''").Error; err != nil {
55+
return err
56+
}
5657
case "mysql":
57-
indexSQL = "CREATE UNIQUE INDEX idx_users_entra_id ON users ((IF(directory_id = '', NULL, directory_id)), (IF(object_id = '', NULL, object_id)))"
58-
}
59-
60-
if err := dbCtx.Exec(indexSQL).Error; err != nil {
61-
return err
58+
for _, stmt := range []string{
59+
"ALTER TABLE users ADD COLUMN directory_id_idx VARCHAR(255) GENERATED ALWAYS AS (IF(directory_id = '', NULL, directory_id)) VIRTUAL",
60+
"ALTER TABLE users ADD COLUMN object_id_idx VARCHAR(255) GENERATED ALWAYS AS (IF(object_id = '', NULL, object_id)) VIRTUAL",
61+
"CREATE UNIQUE INDEX idx_users_entra_id ON users (directory_id_idx, object_id_idx)",
62+
} {
63+
if err := dbCtx.Exec(stmt).Error; err != nil {
64+
return err
65+
}
66+
}
6267
}
6368
}
6469

@@ -72,13 +77,24 @@ func (m *EntraAuthMigration) Up(ctx context.Context, db *gorm.DB) error {
7277
func (m *EntraAuthMigration) Down(ctx context.Context, db *gorm.DB) error {
7378
dbCtx := db.WithContext(ctx)
7479
migrator := dbCtx.Migrator()
80+
dialect := db.Dialector.Name()
7581

7682
if migrator.HasIndex("users", "idx_users_entra_id") {
7783
if err := migrator.DropIndex("users", "idx_users_entra_id"); err != nil {
7884
return err
7985
}
8086
}
8187

88+
if dialect == "mysql" {
89+
for _, col := range []string{"directory_id_idx", "object_id_idx"} {
90+
if migrator.HasColumn("users", col) {
91+
if err := dbCtx.Exec("ALTER TABLE users DROP COLUMN " + col).Error; err != nil {
92+
return err
93+
}
94+
}
95+
}
96+
}
97+
8298
if err := dbCtx.Exec(`CREATE TABLE IF NOT EXISTS user_password_resets (
8399
user_id INTEGER NOT NULL PRIMARY KEY,
84100
email TEXT NOT NULL,

0 commit comments

Comments
 (0)