#5635 when setting Config.DryRunMigration, AutoMigrate() returns an error before changing schemas.
This commit is contained in:
parent
edb00c10ad
commit
9d4ea5135a
9
gorm.go
9
gorm.go
@ -31,6 +31,8 @@ type Config struct {
|
|||||||
NowFunc func() time.Time
|
NowFunc func() time.Time
|
||||||
// DryRun generate sql without execute
|
// DryRun generate sql without execute
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
// DryRunMigration prevent AutoMigrate() to change the schema
|
||||||
|
DryRunMigration bool
|
||||||
// PrepareStmt executes the given query in cached statement
|
// PrepareStmt executes the given query in cached statement
|
||||||
PrepareStmt bool
|
PrepareStmt bool
|
||||||
// DisableAutomaticPing
|
// DisableAutomaticPing
|
||||||
@ -97,6 +99,7 @@ type DB struct {
|
|||||||
// Session session config when create session with Session() method
|
// Session session config when create session with Session() method
|
||||||
type Session struct {
|
type Session struct {
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
DryRunMigration bool
|
||||||
PrepareStmt bool
|
PrepareStmt bool
|
||||||
NewDB bool
|
NewDB bool
|
||||||
Initialized bool
|
Initialized bool
|
||||||
@ -274,6 +277,10 @@ func (db *DB) Session(config *Session) *DB {
|
|||||||
tx.Config.DryRun = true
|
tx.Config.DryRun = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.DryRunMigration {
|
||||||
|
tx.Config.DryRunMigration = true
|
||||||
|
}
|
||||||
|
|
||||||
if config.QueryFields {
|
if config.QueryFields {
|
||||||
tx.Config.QueryFields = true
|
tx.Config.QueryFields = true
|
||||||
}
|
}
|
||||||
@ -457,10 +464,12 @@ func (db *DB) Use(plugin Plugin) error {
|
|||||||
// ToSQL for generate SQL string.
|
// ToSQL for generate SQL string.
|
||||||
//
|
//
|
||||||
// db.ToSQL(func(tx *gorm.DB) *gorm.DB {
|
// db.ToSQL(func(tx *gorm.DB) *gorm.DB {
|
||||||
|
//
|
||||||
// return tx.Model(&User{}).Where(&User{Name: "foo", Age: 20})
|
// return tx.Model(&User{}).Where(&User{Name: "foo", Age: 20})
|
||||||
// .Limit(10).Offset(5)
|
// .Limit(10).Offset(5)
|
||||||
// .Order("name ASC")
|
// .Order("name ASC")
|
||||||
// .First(&User{})
|
// .First(&User{})
|
||||||
|
//
|
||||||
// })
|
// })
|
||||||
func (db *DB) ToSQL(queryFn func(tx *DB) *DB) string {
|
func (db *DB) ToSQL(queryFn func(tx *DB) *DB) string {
|
||||||
tx := queryFn(db.Session(&Session{DryRun: true, SkipDefaultTransaction: true}))
|
tx := queryFn(db.Session(&Session{DryRun: true, SkipDefaultTransaction: true}))
|
||||||
|
@ -94,6 +94,10 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
|
|||||||
for _, value := range m.ReorderModels(values, true) {
|
for _, value := range m.ReorderModels(values, true) {
|
||||||
tx := m.DB.Session(&gorm.Session{})
|
tx := m.DB.Session(&gorm.Session{})
|
||||||
if !tx.Migrator().HasTable(value) {
|
if !tx.Migrator().HasTable(value) {
|
||||||
|
if tx.DryRunMigration {
|
||||||
|
return fmt.Errorf("create table for model %T: %w", value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Migrator().CreateTable(value); err != nil {
|
if err := tx.Migrator().CreateTable(value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -117,6 +121,10 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
|
|||||||
|
|
||||||
if foundColumn == nil {
|
if foundColumn == nil {
|
||||||
// not found, add column
|
// not found, add column
|
||||||
|
if tx.DryRunMigration {
|
||||||
|
return fmt.Errorf("create column for model %T: %w", value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Migrator().AddColumn(value, dbName); err != nil {
|
if err := tx.Migrator().AddColumn(value, dbName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -130,6 +138,10 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
|
|||||||
if !m.DB.Config.DisableForeignKeyConstraintWhenMigrating {
|
if !m.DB.Config.DisableForeignKeyConstraintWhenMigrating {
|
||||||
if constraint := rel.ParseConstraint(); constraint != nil &&
|
if constraint := rel.ParseConstraint(); constraint != nil &&
|
||||||
constraint.Schema == stmt.Schema && !tx.Migrator().HasConstraint(value, constraint.Name) {
|
constraint.Schema == stmt.Schema && !tx.Migrator().HasConstraint(value, constraint.Name) {
|
||||||
|
if tx.DryRunMigration {
|
||||||
|
return fmt.Errorf("create constraint %s for model %T: %w", constraint.Name, value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Migrator().CreateConstraint(value, constraint.Name); err != nil {
|
if err := tx.Migrator().CreateConstraint(value, constraint.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -139,6 +151,10 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
|
|||||||
|
|
||||||
for _, chk := range stmt.Schema.ParseCheckConstraints() {
|
for _, chk := range stmt.Schema.ParseCheckConstraints() {
|
||||||
if !tx.Migrator().HasConstraint(value, chk.Name) {
|
if !tx.Migrator().HasConstraint(value, chk.Name) {
|
||||||
|
if tx.DryRunMigration {
|
||||||
|
return fmt.Errorf("create constraint %s for model %T: %w", chk.Name, value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Migrator().CreateConstraint(value, chk.Name); err != nil {
|
if err := tx.Migrator().CreateConstraint(value, chk.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -147,6 +163,10 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
|
|||||||
|
|
||||||
for _, idx := range stmt.Schema.ParseIndexes() {
|
for _, idx := range stmt.Schema.ParseIndexes() {
|
||||||
if !tx.Migrator().HasIndex(value, idx.Name) {
|
if !tx.Migrator().HasIndex(value, idx.Name) {
|
||||||
|
if tx.DryRunMigration {
|
||||||
|
return fmt.Errorf("create index %s for model %T: %w", idx.Name, value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Migrator().CreateIndex(value, idx.Name); err != nil {
|
if err := tx.Migrator().CreateIndex(value, idx.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -478,6 +498,10 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
if alterColumn && !field.IgnoreMigration {
|
if alterColumn && !field.IgnoreMigration {
|
||||||
|
if m.DB.DryRunMigration {
|
||||||
|
return fmt.Errorf("alter column %s for model %T: %w", field.Name, value, gorm.ErrDryRunModeUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
return m.DB.Migrator().AlterColumn(value, field.Name)
|
return m.DB.Migrator().AlterColumn(value, field.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package tests_test
|
package tests_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -959,3 +960,64 @@ func TestMigrateArrayTypeModel(t *testing.T) {
|
|||||||
AssertEqual(t, nil, err)
|
AssertEqual(t, nil, err)
|
||||||
AssertEqual(t, "integer[]", ct.DatabaseTypeName())
|
AssertEqual(t, "integer[]", ct.DatabaseTypeName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Origin struct {
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
Data string `gorm:"null"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Origin) TableName() string {
|
||||||
|
return "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDryRunAutoMigrate(t *testing.T) {
|
||||||
|
type ChangeColumn struct {
|
||||||
|
Origin `gorm:"-"`
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
Data int64 `gorm:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddIndex struct {
|
||||||
|
Origin `gorm:"-"`
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
Data string `gorm:"null;index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddConstraint struct {
|
||||||
|
Origin `gorm:"-"`
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
Data string `gorm:"null;check:,data <> 'migrate'"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
from, to interface{}
|
||||||
|
dryrunErr bool
|
||||||
|
}{
|
||||||
|
{&Origin{}, &Origin{}, false},
|
||||||
|
{&Origin{}, &ChangeColumn{}, true},
|
||||||
|
{&Origin{}, &AddIndex{}, true},
|
||||||
|
{&Origin{}, &AddConstraint{}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
name := strings.ReplaceAll(fmt.Sprintf("%T", test.to), "*", "")
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
DB.Migrator().DropTable(test.from, test.to)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
DB.Migrator().DropTable(test.from, test.to)
|
||||||
|
})
|
||||||
|
|
||||||
|
err := DB.Migrator().CreateTable(test.from)
|
||||||
|
AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = DB.Session(&gorm.Session{DryRunMigration: true}).AutoMigrate(test.to)
|
||||||
|
if err != nil {
|
||||||
|
t.Log("migrate error:", err)
|
||||||
|
}
|
||||||
|
AssertEqual(t, test.dryrunErr, errors.Is(err, gorm.ErrDryRunModeUnsupported))
|
||||||
|
|
||||||
|
err = DB.AutoMigrate(test.to)
|
||||||
|
AssertEqual(t, false, errors.Is(err, gorm.ErrDryRunModeUnsupported))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user