Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#5635 Add Config.DryRunMigration to prevent actually changing the schema when doing AutoMigrate() #5639

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions gorm.go
Expand Up @@ -31,6 +31,8 @@ type Config struct {
NowFunc func() time.Time
// DryRun generate sql without execute
DryRun bool
// DryRunMigration runs AutoMigrate() without changing schema
DryRunMigration bool
// PrepareStmt executes the given query in cached statement
PrepareStmt bool
// DisableAutomaticPing
Expand Down Expand Up @@ -457,10 +459,12 @@ func (db *DB) Use(plugin Plugin) error {
// ToSQL for generate SQL string.
//
// db.ToSQL(func(tx *gorm.DB) *gorm.DB {
// return tx.Model(&User{}).Where(&User{Name: "foo", Age: 20})
// .Limit(10).Offset(5)
// .Order("name ASC")
// .First(&User{})
//
// return tx.Model(&User{}).Where(&User{Name: "foo", Age: 20})
// .Limit(10).Offset(5)
// .Order("name ASC")
// .First(&User{})
//
// })
func (db *DB) ToSQL(queryFn func(tx *DB) *DB) string {
tx := queryFn(db.Session(&Session{DryRun: true, SkipDefaultTransaction: true}))
Expand Down
51 changes: 51 additions & 0 deletions migrator/migrator.go
Expand Up @@ -172,6 +172,10 @@ func (m Migrator) GetTables() (tableList []string, err error) {

// CreateTable create table in database for values
func (m Migrator) CreateTable(values ...interface{}) error {
if m.DB.DryRunMigration {
return fmt.Errorf("create table %#v: %w", values, gorm.ErrDryRunModeUnsupported)
}

for _, value := range m.ReorderModels(values, false) {
tx := m.DB.Session(&gorm.Session{})
if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) {
Expand Down Expand Up @@ -263,6 +267,10 @@ func (m Migrator) CreateTable(values ...interface{}) error {

// DropTable drop table for values
func (m Migrator) DropTable(values ...interface{}) error {
if m.DB.DryRunMigration {
return fmt.Errorf("drop table %#v: %w", values, gorm.ErrDryRunModeUnsupported)
}

values = m.ReorderModels(values, false)
for i := len(values) - 1; i >= 0; i-- {
tx := m.DB.Session(&gorm.Session{})
Expand All @@ -289,6 +297,10 @@ func (m Migrator) HasTable(value interface{}) bool {

// RenameTable rename table from oldName to newName
func (m Migrator) RenameTable(oldName, newName interface{}) error {
if m.DB.DryRunMigration {
return fmt.Errorf("rename table %s -> %s: %w", oldName, newName, gorm.ErrDryRunModeUnsupported)
}

var oldTable, newTable interface{}
if v, ok := oldName.(string); ok {
oldTable = clause.Table{Name: v}
Expand Down Expand Up @@ -325,6 +337,10 @@ func (m Migrator) AddColumn(value interface{}, name string) error {
}

if !f.IgnoreMigration {
if m.DB.DryRunMigration {
return fmt.Errorf("add column %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

return m.DB.Exec(
"ALTER TABLE ? ADD ? ?",
m.CurrentTable(stmt), clause.Column{Name: f.DBName}, m.DB.Migrator().FullDataTypeOf(f),
Expand All @@ -342,6 +358,10 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
name = field.DBName
}

if m.DB.DryRunMigration {
return fmt.Errorf("drop column %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

return m.DB.Exec(
"ALTER TABLE ? DROP COLUMN ?", m.CurrentTable(stmt), clause.Column{Name: name},
).Error
Expand All @@ -352,6 +372,10 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
func (m Migrator) AlterColumn(value interface{}, field string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if field := stmt.Schema.LookUpField(field); field != nil {
if m.DB.DryRunMigration {
return fmt.Errorf("alter column %s in table %s: %w", field.Name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

fileType := m.FullDataTypeOf(field)
return m.DB.Exec(
"ALTER TABLE ? ALTER COLUMN ? TYPE ?",
Expand Down Expand Up @@ -393,6 +417,10 @@ func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error
newName = field.DBName
}

if m.DB.DryRunMigration {
return fmt.Errorf("rename column %s -> %s in table %s: %w", oldName, newName, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

return m.DB.Exec(
"ALTER TABLE ? RENAME COLUMN ? TO ?",
m.CurrentTable(stmt), clause.Column{Name: oldName}, clause.Column{Name: newName},
Expand Down Expand Up @@ -478,6 +506,9 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
}

if alterColumn && !field.IgnoreMigration {
if m.DB.DryRunMigration {
return fmt.Errorf("migrate column %s in table %T: %w", field.Name, value, gorm.ErrDryRunModeUnsupported)
}
return m.DB.Migrator().AlterColumn(value, field.Name)
}

Expand Down Expand Up @@ -593,6 +624,10 @@ func (m Migrator) GuessConstraintAndTable(stmt *gorm.Statement, name string) (_
// CreateConstraint create constraint
func (m Migrator) CreateConstraint(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if m.DB.DryRunMigration {
return fmt.Errorf("create constraint %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
if chk != nil {
return m.DB.Exec(
Expand All @@ -617,6 +652,10 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
// DropConstraint drop constraint
func (m Migrator) DropConstraint(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if m.DB.DryRunMigration {
return fmt.Errorf("drop constraint %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
if constraint != nil {
name = constraint.Name
Expand Down Expand Up @@ -679,6 +718,10 @@ type BuildIndexOptionsInterface interface {
func (m Migrator) CreateIndex(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if idx := stmt.Schema.LookIndex(name); idx != nil {
if m.DB.DryRunMigration {
return fmt.Errorf("create index %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

opts := m.DB.Migrator().(BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt)
values := []interface{}{clause.Column{Name: idx.Name}, m.CurrentTable(stmt), opts}

Expand Down Expand Up @@ -710,6 +753,10 @@ func (m Migrator) CreateIndex(value interface{}, name string) error {
// DropIndex drop index `name`
func (m Migrator) DropIndex(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if m.DB.DryRunMigration {
return fmt.Errorf("drop index %s in table %s: %w", name, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

if idx := stmt.Schema.LookIndex(name); idx != nil {
name = idx.Name
}
Expand Down Expand Up @@ -739,6 +786,10 @@ func (m Migrator) HasIndex(value interface{}, name string) bool {
// RenameIndex rename index from oldName to newName
func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if m.DB.DryRunMigration {
return fmt.Errorf("rename index %s -> %s in table %s: %w", oldName, newName, m.CurrentTable(stmt), gorm.ErrDryRunModeUnsupported)
}

return m.DB.Exec(
"ALTER TABLE ? RENAME INDEX ? TO ?",
m.CurrentTable(stmt), clause.Column{Name: oldName}, clause.Column{Name: newName},
Expand Down