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 with Auto, which should be more smart. And I found that some prime users like me just use AutoMigrate 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?

Comment From: jinzhu

We are trying to achieve this goal, could you create a playground that could reproduce the case?

Comment From: kkocdko

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()
}