diff --git a/main.go b/main.go index 9c64059..f002bf0 100644 --- a/main.go +++ b/main.go @@ -117,9 +117,7 @@ func main() { defer sqlDb.Close() // Migrate database schema - migrations.RunPreMigrations(db, config) - runDatabaseMigrations() - migrations.RunCustomPostMigrations(db, config) + migrations.Run(db, config) // Repositories aliasRepository = repositories.NewAliasRepository(db) @@ -268,9 +266,3 @@ func listen(handler http.Handler) { <-make(chan interface{}, 1) } - -func runDatabaseMigrations() { - if err := config.GetMigrationFunc(config.Db.Dialect)(db); err != nil { - logbuch.Fatal(err.Error()) - } -} diff --git a/migrations/20210221_add_created_date_column.go b/migrations/20210221_add_created_date_column.go new file mode 100644 index 0000000..b77954b --- /dev/null +++ b/migrations/20210221_add_created_date_column.go @@ -0,0 +1,41 @@ +package migrations + +import ( + "github.com/emvi/logbuch" + "github.com/muety/wakapi/config" + "github.com/muety/wakapi/models" + "gorm.io/gorm" +) + +func init() { + const name = "20210221-add_created_date_column" + f := migrationFunc{ + name: name, + f: func(db *gorm.DB, cfg *config.Config) error { + condition := "key = ?" + if cfg.Db.Dialect == config.SQLDialectMysql { + condition = "`key` = ?" + } + lookupResult := db.Where(condition, name).First(&models.KeyStringValue{}) + if lookupResult.Error == nil && lookupResult.RowsAffected > 0 { + logbuch.Info("no need to migrate '%s'", name) + return nil + } + + if err := db.Exec("UPDATE heartbeats SET created_at = time WHERE TRUE").Error; err != nil { + return err + } + + if err := db.Create(&models.KeyStringValue{ + Key: name, + Value: "done", + }).Error; err != nil { + return err + } + + return nil + }, + } + + registerPostMigration(f) +} diff --git a/migrations/migrations.go b/migrations/migrations.go index 1507b44..038ae5e 100644 --- a/migrations/migrations.go +++ b/migrations/migrations.go @@ -28,9 +28,17 @@ func registerPostMigration(f migrationFunc) { postMigrations = append(postMigrations, f) } -// NOTE: Currently, migrations themselves keep track -// of whether they have run, yet or not, because some -// simply run on every start. +func Run(db *gorm.DB, cfg *config.Config) { + RunPreMigrations(db, cfg) + RunSchemaMigrations(db, cfg) + RunPostMigrations(db, cfg) +} + +func RunSchemaMigrations(db *gorm.DB, cfg *config.Config) { + if err := cfg.GetMigrationFunc(cfg.Db.Dialect)(db); err != nil { + logbuch.Fatal(err.Error()) + } +} func RunPreMigrations(db *gorm.DB, cfg *config.Config) { sort.Sort(preMigrations) @@ -43,7 +51,7 @@ func RunPreMigrations(db *gorm.DB, cfg *config.Config) { } } -func RunCustomPostMigrations(db *gorm.DB, cfg *config.Config) { +func RunPostMigrations(db *gorm.DB, cfg *config.Config) { sort.Sort(postMigrations) for _, m := range postMigrations { diff --git a/models/heartbeat.go b/models/heartbeat.go index 003fce3..3a28d63 100644 --- a/models/heartbeat.go +++ b/models/heartbeat.go @@ -22,10 +22,11 @@ type Heartbeat struct { Editor string `json:"editor" hash:"ignore"` // ignored because editor might be parsed differently by wakatime OperatingSystem string `json:"operating_system" hash:"ignore"` // ignored because os might be parsed differently by wakatime Machine string `json:"machine" hash:"ignore"` // ignored because wakatime api doesn't return machines currently - Time CustomTime `json:"time" gorm:"type:timestamp; default:CURRENT_TIMESTAMP; index:idx_time,idx_time_user" swaggertype:"primitive,number"` + Time CustomTime `json:"time" gorm:"type:timestamp; index:idx_time,idx_time_user" swaggertype:"primitive,number"` Hash string `json:"-" gorm:"type:varchar(17); uniqueIndex"` Origin string `json:"-" hash:"ignore"` OriginId string `json:"-" hash:"ignore"` + CreatedAt CustomTime `json:"created_at" gorm:"type:timestamp" swaggertype:"primitive,number"` // https://gorm.io/docs/conventions.html#CreatedAt languageRegex *regexp.Regexp `hash:"ignore"` }