Open kkocdko opened 1 year ago
We are trying to achieve this goal, could you create a playground that could reproduce the case?
My personal method to run migrate on-demand. Just fit my personal usage.
package main
import (
"encoding/json"
"fmt"
"reflect"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// MUST keep outputs stable
func GetDefine(v any) string {
t := reflect.TypeOf(v)
ret := "type " + t.Name() + " struct {\n"
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
ret += " " + field.Name + " " + field.Type.Name()
tag := string(field.Tag)
if tag != "" {
ret += " `" + string(field.Tag) + "`"
}
ret += "\n"
}
ret += "}"
return ret
}
func panicErr(v error, msg ...string) {
if v != nil {
if len(msg) != 0 {
fmt.Println(msg[0])
}
panic(v)
}
}
type KeyValue struct {
Key string
Value []byte
}
type FooBar struct {
Field1 string
Field2 int
Field3 byte
}
func initGorm() error {
gormCfg := gorm.Config{}
gormCfg.Logger.LogMode(logger.Info)
dsn := "file:data.db"
d, err := gorm.Open(sqlite.Open(dsn), &gormCfg)
panicErr(err)
// My personal method to run migrate on-demand
defs := map[string]string{}
kv := KeyValue{Key: "db_def"}
if d.First(&kv).Error == nil {
panicErr(json.Unmarshal(kv.Value, &defs))
}
for _, v := range []any{FooBar{}} {
name, def := reflect.TypeOf(v).Name(), GetDefine(v)
if defs[name] != def {
panicErr(d.AutoMigrate(&v))
defs[name] = def
fmt.Printf("AutoMigrate: %v\n", name)
}
}
kv.Value, _ = json.Marshal(defs)
d.Save(&kv)
return nil
}
func main() {
initGorm()
}
Describe the feature
AutoMigrate
is useful to migrate database but it runs migration every time even if the table structure (struct define) not changed.Motivation
The
AutoMigrate
is prefixed withAuto
, which should be more smart. And I found that some prime users like me just useAutoMigrate
at the begining of program and image it will skip migration when possible (LOL).Related Issues
If this feature was too complex to implement, maybe add this to docs?