Database: Add migrations #319
This commit is contained in:
parent
abcdee6728
commit
7a47177105
9 changed files with 80 additions and 35 deletions
|
@ -3,8 +3,13 @@ package migrate
|
|||
|
||||
var DialectMySQL = Migrations{
|
||||
{
|
||||
ID: "20211121-094727",
|
||||
Dialect: "mysql",
|
||||
Query: "DROP INDEX IF EXISTS uix_places_place_label ON `places`",
|
||||
ID: "20211121-094727",
|
||||
Dialect: "mysql",
|
||||
Statements: []string{"DROP INDEX IF EXISTS uix_places_place_label ON `places`;"},
|
||||
},
|
||||
{
|
||||
ID: "20211124-120008",
|
||||
Dialect: "mysql",
|
||||
Statements: []string{"DROP INDEX IF EXISTS idx_places_place_label ON `places`;", "DROP INDEX IF EXISTS uix_places_label ON `places`;"},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,8 +3,13 @@ package migrate
|
|||
|
||||
var DialectSQLite = Migrations{
|
||||
{
|
||||
ID: "20211121-094727",
|
||||
Dialect: "sqlite",
|
||||
Query: "DROP INDEX IF EXISTS idx_places_place_label",
|
||||
ID: "20211121-094727",
|
||||
Dialect: "sqlite",
|
||||
Statements: []string{"DROP INDEX IF EXISTS idx_places_place_label;"},
|
||||
},
|
||||
{
|
||||
ID: "20211124-120008",
|
||||
Dialect: "sqlite",
|
||||
Statements: []string{"DROP INDEX IF EXISTS uix_places_place_label;", "DROP INDEX IF EXISTS uix_places_label;"},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -20,9 +21,9 @@ func gen_migrations(name string) {
|
|||
dialect := strings.ToLower(name)
|
||||
|
||||
type Migration struct {
|
||||
ID string
|
||||
Dialect string
|
||||
Query string
|
||||
ID string
|
||||
Dialect string
|
||||
Statements []string
|
||||
}
|
||||
|
||||
var migrations []Migration
|
||||
|
@ -35,6 +36,23 @@ func gen_migrations(name string) {
|
|||
|
||||
fmt.Printf("generating %s...", dialect)
|
||||
|
||||
strToStmts := func(b []byte) (result []string) {
|
||||
stmts := bytes.Split(b, []byte(";\n"))
|
||||
result = make([]string, 0, len(stmts))
|
||||
|
||||
for i := range stmts {
|
||||
if s := bytes.TrimSpace(stmts[i]); len(s) > 0 {
|
||||
if s[len(s)-1] != ';' {
|
||||
s = append(s, ';')
|
||||
}
|
||||
|
||||
result = append(result, string(s))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Read migrations from files.
|
||||
for _, file := range files {
|
||||
filePath := filepath.Join(folder, file.Name())
|
||||
|
@ -44,9 +62,10 @@ func gen_migrations(name string) {
|
|||
} else if id := strings.SplitN(filepath.Base(file.Name()), ".", 2)[0]; id == "" {
|
||||
fmt.Printf("e")
|
||||
// Ignore.
|
||||
} else if query, err := os.ReadFile(filePath); err == nil && len(query) > 0 {
|
||||
} else if s, err := os.ReadFile(filePath); err == nil && len(s) > 0 {
|
||||
fmt.Printf(".")
|
||||
migrations = append(migrations, Migration{ID: id, Dialect: dialect, Query: string(query)})
|
||||
|
||||
migrations = append(migrations, Migration{ID: id, Dialect: dialect, Statements: strToStmts(s)})
|
||||
} else {
|
||||
fmt.Printf("f")
|
||||
fmt.Println(err.Error())
|
||||
|
@ -85,9 +104,9 @@ package migrate
|
|||
var Dialect{{ print .Name }} = Migrations{
|
||||
{{- range .Migrations }}
|
||||
{
|
||||
ID: {{ printf "%q" .ID }},
|
||||
Dialect: {{ printf "%q" .Dialect }},
|
||||
Query: {{ printf "%q" .Query }},
|
||||
ID: {{ printf "%q" .ID }},
|
||||
Dialect: {{ printf "%q" .Dialect }},
|
||||
Statements: []string{ {{ range $index, $s := .Statements}}{{if $index}},{{end}}{{ printf "%q" $s }}{{end}} },
|
||||
},
|
||||
{{- end }}
|
||||
}`))
|
||||
|
|
|
@ -12,7 +12,7 @@ type Migration struct {
|
|||
Dialect string `gorm:"size:16;" json:"Dialect" yaml:"Dialect,omitempty"`
|
||||
Error string `gorm:"size:255;" json:"Error" yaml:"Error,omitempty"`
|
||||
Source string `gorm:"size:16;" json:"Source" yaml:"Source,omitempty"`
|
||||
Query string `gorm:"-" json:"Query" yaml:"Query,omitempty"`
|
||||
Statements []string `gorm:"-" json:"Statements" yaml:"Statements,omitempty"`
|
||||
StartedAt time.Time `json:"StartedAt" yaml:"StartedAt,omitempty"`
|
||||
FinishedAt *time.Time `json:"FinishedAt" yaml:"FinishedAt,omitempty"`
|
||||
}
|
||||
|
@ -33,25 +33,17 @@ func (m *Migration) Fail(err error, db *gorm.DB) {
|
|||
}
|
||||
|
||||
// Finish updates the FinishedAt timestamp when the migration was successful.
|
||||
func (m *Migration) Finish(db *gorm.DB) {
|
||||
db.Model(m).Updates(Values{"FinishedAt": time.Now().UTC()})
|
||||
func (m *Migration) Finish(db *gorm.DB) error {
|
||||
return db.Model(m).Updates(Values{"FinishedAt": time.Now().UTC()}).Error
|
||||
}
|
||||
|
||||
// Execute runs the migration.
|
||||
func (m *Migration) Execute(db *gorm.DB) {
|
||||
start := time.Now()
|
||||
|
||||
m.StartedAt = start.UTC().Round(time.Second)
|
||||
|
||||
if err := db.Create(m).Error; err != nil {
|
||||
return
|
||||
func (m *Migration) Execute(db *gorm.DB) error {
|
||||
for _, s := range m.Statements {
|
||||
if err := db.Exec(s).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Exec(m.Query).Error; err != nil {
|
||||
m.Fail(err, db)
|
||||
log.Errorf("migration %s failed: %s [%s]", m.ID, err, time.Since(start))
|
||||
} else {
|
||||
m.Finish(db)
|
||||
log.Infof("migration %s successful [%s]", m.ID, time.Since(start))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package migrate
|
||||
|
||||
import "github.com/jinzhu/gorm"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// Migrations represents a sorted list of migrations.
|
||||
type Migrations []Migration
|
||||
|
@ -8,6 +12,22 @@ type Migrations []Migration
|
|||
// Start runs all migrations that haven't been executed yet.
|
||||
func (m *Migrations) Start(db *gorm.DB) {
|
||||
for _, migration := range *m {
|
||||
migration.Execute(db)
|
||||
start := time.Now()
|
||||
|
||||
migration.StartedAt = start.UTC().Round(time.Second)
|
||||
|
||||
// Continue if already executed.
|
||||
if err := db.Create(migration).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := migration.Execute(db); err != nil {
|
||||
migration.Fail(err, db)
|
||||
log.Errorf("migration %s failed: %s [%s]", migration.ID, err, time.Since(start))
|
||||
} else if err = migration.Finish(db); err != nil {
|
||||
log.Warnf("migration %s failed: %s [%s]", migration.ID, err, time.Since(start))
|
||||
} else {
|
||||
log.Infof("migration %s successful [%s]", migration.ID, time.Since(start))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
DROP INDEX IF EXISTS uix_places_place_label ON `places`
|
||||
DROP INDEX IF EXISTS uix_places_place_label ON `places`;
|
2
internal/migrate/mysql/20211124-120008.sql
Normal file
2
internal/migrate/mysql/20211124-120008.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
DROP INDEX IF EXISTS idx_places_place_label ON `places`;
|
||||
DROP INDEX IF EXISTS uix_places_label ON `places`;
|
|
@ -1 +1 @@
|
|||
DROP INDEX IF EXISTS idx_places_place_label
|
||||
DROP INDEX IF EXISTS idx_places_place_label;
|
||||
|
|
2
internal/migrate/sqlite/20211124-120008.sql
Normal file
2
internal/migrate/sqlite/20211124-120008.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
DROP INDEX IF EXISTS uix_places_place_label;
|
||||
DROP INDEX IF EXISTS uix_places_label;
|
Loading…
Reference in a new issue