diff --git a/schema/index.go b/schema/index.go index 16d096b76..5003c7428 100644 --- a/schema/index.go +++ b/schema/index.go @@ -1,6 +1,7 @@ package schema import ( + "fmt" "sort" "strconv" "strings" @@ -31,7 +32,12 @@ func (schema *Schema) ParseIndexes() map[string]Index { for _, field := range schema.Fields { if field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUEINDEX"] != "" { - for _, index := range parseFieldIndexes(field) { + fieldIndexes, err := parseFieldIndexes(field) + if err != nil { + schema.err = err + break + } + for _, index := range fieldIndexes { idx := indexes[index.Name] idx.Name = index.Name if idx.Class == "" { @@ -82,7 +88,7 @@ func (schema *Schema) LookIndex(name string) *Index { return nil } -func parseFieldIndexes(field *Field) (indexes []Index) { +func parseFieldIndexes(field *Field) (indexes []Index, err error) { for _, value := range strings.Split(field.Tag.Get("gorm"), ";") { if value != "" { v := strings.Split(value, ":") @@ -106,7 +112,20 @@ func parseFieldIndexes(field *Field) (indexes []Index) { } if name == "" { - name = field.Schema.namer.IndexName(field.Schema.Table, field.Name) + subName := field.Name + const key = "COMPOSITE" + if composite, found := settings[key]; found { + if len(composite) == 0 || composite == key { + err = fmt.Errorf( + "The composite tag of %s.%s cannot be empty", + field.Schema.Name, + field.Name) + return + } + subName = composite + } + name = field.Schema.namer.IndexName( + field.Schema.Table, subName) } if (k == "UNIQUEINDEX") || settings["UNIQUE"] != "" { @@ -138,5 +157,6 @@ func parseFieldIndexes(field *Field) (indexes []Index) { } } + err = nil return } diff --git a/schema/index_test.go b/schema/index_test.go index 3c4582bb4..1fe31cc1b 100644 --- a/schema/index_test.go +++ b/schema/index_test.go @@ -19,6 +19,36 @@ type UserIndex struct { OID int64 `gorm:"index:idx_id;index:idx_oid,unique"` MemberNumber string `gorm:"index:idx_id,priority:1"` Name7 string `gorm:"index:type"` + + // Composite Index: Flattened structure. + Data0A string `gorm:"index:,composite:comp_id0"` + Data0B string `gorm:"index:,composite:comp_id0"` + + // Composite Index: Nested structure. + Data1A string `gorm:"index:,composite:comp_id1"` + CompIdxLevel1C + + // Composite Index: Unique and priority. + Data2A string `gorm:"index:,unique,composite:comp_id2,priority:2"` + CompIdxLevel2C +} + +type CompIdxLevel1C struct { + CompIdxLevel1B + Data1C string `gorm:"index:,composite:comp_id1"` +} + +type CompIdxLevel1B struct { + Data1B string `gorm:"index:,composite:comp_id1"` +} + +type CompIdxLevel2C struct { + CompIdxLevel2B + Data2C string `gorm:"index:,unique,composite:comp_id2,priority:1"` +} + +type CompIdxLevel2B struct { + Data2B string `gorm:"index:,unique,composite:comp_id2,priority:3"` } func TestParseIndex(t *testing.T) { @@ -84,6 +114,36 @@ func TestParseIndex(t *testing.T) { Type: "", Fields: []schema.IndexOption{{Field: &schema.Field{Name: "Name7"}}}, }, + "idx_user_indices_comp_id0": { + Name: "idx_user_indices_comp_id0", + Type: "", + Fields: []schema.IndexOption{{ + Field: &schema.Field{Name: "Data0A"}, + }, { + Field: &schema.Field{Name: "Data0B"}, + }}, + }, + "idx_user_indices_comp_id1": { + Name: "idx_user_indices_comp_id1", + Fields: []schema.IndexOption{{ + Field: &schema.Field{Name: "Data1A"}, + }, { + Field: &schema.Field{Name: "Data1B"}, + }, { + Field: &schema.Field{Name: "Data1C"}, + }}, + }, + "idx_user_indices_comp_id2": { + Name: "idx_user_indices_comp_id2", + Class: "UNIQUE", + Fields: []schema.IndexOption{{ + Field: &schema.Field{Name: "Data2C"}, + }, { + Field: &schema.Field{Name: "Data2A"}, + }, { + Field: &schema.Field{Name: "Data2B"}, + }}, + }, } indices := user.ParseIndexes()