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

refactor: distinguish between Unique and UniqueIndex #123

Merged
merged 5 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ go 1.14

require (
github.com/go-sql-driver/mysql v1.7.0
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
)
6 changes: 5 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.6-0.20231115133256-3207ad6033aa h1:cGDODlWbAjO6jreDwDD34SsdQVhuFE5KjXO1LmpKZYQ=
gorm.io/gorm v1.25.6-0.20231115133256-3207ad6033aa/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
88 changes: 72 additions & 16 deletions migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,78 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) clause.Expr {
return expr
}

// MigrateColumnUnique migrate column's UNIQUE constraint.
// In MySQL, ColumnType's Unique is affected by UniqueIndex, so we have to take care of the UniqueIndex.
func (m Migrator) MigrateColumnUnique(value interface{}, field *schema.Field, columnType gorm.ColumnType) error {
unique, ok := columnType.Unique()
if !ok || field.PrimaryKey {
return nil // skip primary key
}

queryTx, execTx := m.GetQueryAndExecTx()
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
// We're currently only receiving boolean values on `Unique` tag,
// so the UniqueConstraint name is fixed
constraint := m.DB.NamingStrategy.UniqueName(stmt.Table, field.DBName)
if unique {
// Clean up redundant unique indexes
indexes, _ := queryTx.Migrator().GetIndexes(value)
for _, index := range indexes {
if uni, ok := index.Unique(); !ok || !uni {
continue
}
if columns := index.Columns(); len(columns) != 1 || columns[0] != field.DBName {
continue
}
if name := index.Name(); name == constraint || name == field.UniqueIndex {
continue
}
if err := execTx.Migrator().DropIndex(value, index.Name()); err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a column for which I changed from index to uniqueIndex

MyColumn int32 gorm:"index"
Gorm had created idx_

_<column_name>

which I changed to

MyColumn int32 gorm:"uniqueIndex"
Gorm retained old index idx_

_<column_name> and created a new unique index <column_name>

After this updatae

gorm.io/driver/mysql v1.5.2 => v1.5.6
gorm.io/gorm v1.25.5 => v1.25.10

It dropped index <column_name> which had unique index and tried to create index with name idx_

_<column_name> and failed.

Ideally we should have also dropped idx_

_<column_name> once we realised we are creating it.

As per the text here - https://gorm.io/docs/migration.html 'It WON’T delete unused columns to protect your data.' we should not have done this right '// Clean up redundant unique indexes'

Option could have been

  1. Check if can't create - stop
  2. Drop what we have figured we want to create?

Please let me know.

return err
}
}

hasConstraint := queryTx.Migrator().HasConstraint(value, constraint)
switch {
case field.Unique && !hasConstraint:
if field.Unique {
if err := execTx.Migrator().CreateConstraint(value, constraint); err != nil {
return err
}
}
// field isn't Unique but ColumnType's Unique is reported by UniqueConstraint.
case !field.Unique && hasConstraint:
if err := execTx.Migrator().DropConstraint(value, constraint); err != nil {
return err
}
if field.UniqueIndex != "" {
if err := execTx.Migrator().CreateIndex(value, field.UniqueIndex); err != nil {
return err
}
}
}

if field.UniqueIndex != "" && !queryTx.Migrator().HasIndex(value, field.UniqueIndex) {
if err := execTx.Migrator().CreateIndex(value, field.UniqueIndex); err != nil {
return err
}
}
} else {
if field.Unique {
if err := execTx.Migrator().CreateConstraint(value, constraint); err != nil {
return err
}
}
if field.UniqueIndex != "" {
if err := execTx.Migrator().CreateIndex(value, field.UniqueIndex); err != nil {
return err
}
}
}
return nil
})
}

func (m Migrator) AddColumn(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
// avoid using the same name field
Expand Down Expand Up @@ -209,22 +281,6 @@ func (m Migrator) DropTable(values ...interface{}) error {
})
}

func (m Migrator) DropConstraint(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
if chk != nil {
return m.DB.Exec("ALTER TABLE ? DROP CHECK ?", clause.Table{Name: stmt.Table}, clause.Column{Name: chk.Name}).Error
}
if constraint != nil {
name = constraint.Name
}

return m.DB.Exec(
"ALTER TABLE ? DROP FOREIGN KEY ?", clause.Table{Name: table}, clause.Column{Name: name},
).Error
})
}

// ColumnTypes column types return columnTypes,error
func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
columnTypes := make([]gorm.ColumnType, 0)
Expand Down
Loading