Skip to content

Commit

Permalink
go-gorm#5635 Add Config.DryRunMigration to prevent actually changing …
Browse files Browse the repository at this point in the history
…the schema when doing AutoMigrate()
  • Loading branch information
googollee committed Aug 24, 2022
1 parent 8c3018b commit d3901da
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
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

0 comments on commit d3901da

Please sign in to comment.