167 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package schema
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| type Index struct {
 | |
| 	Name    string
 | |
| 	Class   string // UNIQUE | FULLTEXT | SPATIAL
 | |
| 	Type    string // btree, hash, gist, spgist, gin, and brin
 | |
| 	Where   string
 | |
| 	Comment string
 | |
| 	Option  string        // WITH PARSER parser_name
 | |
| 	Fields  []IndexOption // Note: IndexOption's Field maybe the same
 | |
| }
 | |
| 
 | |
| type IndexOption struct {
 | |
| 	*Field
 | |
| 	Expression string
 | |
| 	Sort       string // DESC, ASC
 | |
| 	Collate    string
 | |
| 	Length     int
 | |
| 	priority   int
 | |
| }
 | |
| 
 | |
| // ParseIndexes parse schema indexes
 | |
| func (schema *Schema) ParseIndexes() map[string]Index {
 | |
| 	indexes := map[string]Index{}
 | |
| 
 | |
| 	for _, field := range schema.Fields {
 | |
| 		if field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUEINDEX"] != "" {
 | |
| 			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 == "" {
 | |
| 					idx.Class = index.Class
 | |
| 				}
 | |
| 				if idx.Type == "" {
 | |
| 					idx.Type = index.Type
 | |
| 				}
 | |
| 				if idx.Where == "" {
 | |
| 					idx.Where = index.Where
 | |
| 				}
 | |
| 				if idx.Comment == "" {
 | |
| 					idx.Comment = index.Comment
 | |
| 				}
 | |
| 				if idx.Option == "" {
 | |
| 					idx.Option = index.Option
 | |
| 				}
 | |
| 
 | |
| 				idx.Fields = append(idx.Fields, index.Fields...)
 | |
| 				sort.Slice(idx.Fields, func(i, j int) bool {
 | |
| 					return idx.Fields[i].priority < idx.Fields[j].priority
 | |
| 				})
 | |
| 
 | |
| 				indexes[index.Name] = idx
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	for _, index := range indexes {
 | |
| 		if index.Class == "UNIQUE" && len(index.Fields) == 1 {
 | |
| 			index.Fields[0].Field.UniqueIndex = index.Name
 | |
| 		}
 | |
| 	}
 | |
| 	return indexes
 | |
| }
 | |
| 
 | |
| func (schema *Schema) LookIndex(name string) *Index {
 | |
| 	if schema != nil {
 | |
| 		indexes := schema.ParseIndexes()
 | |
| 		for _, index := range indexes {
 | |
| 			if index.Name == name {
 | |
| 				return &index
 | |
| 			}
 | |
| 
 | |
| 			for _, field := range index.Fields {
 | |
| 				if field.Name == name {
 | |
| 					return &index
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func parseFieldIndexes(field *Field) (indexes []Index, err error) {
 | |
| 	for _, value := range strings.Split(field.Tag.Get("gorm"), ";") {
 | |
| 		if value != "" {
 | |
| 			v := strings.Split(value, ":")
 | |
| 			k := strings.TrimSpace(strings.ToUpper(v[0]))
 | |
| 			if k == "INDEX" || k == "UNIQUEINDEX" {
 | |
| 				var (
 | |
| 					name       string
 | |
| 					tag        = strings.Join(v[1:], ":")
 | |
| 					idx        = strings.Index(tag, ",")
 | |
| 					tagSetting = strings.Join(strings.Split(tag, ",")[1:], ",")
 | |
| 					settings   = ParseTagSetting(tagSetting, ",")
 | |
| 					length, _  = strconv.Atoi(settings["LENGTH"])
 | |
| 				)
 | |
| 
 | |
| 				if idx == -1 {
 | |
| 					idx = len(tag)
 | |
| 				}
 | |
| 
 | |
| 				if idx != -1 {
 | |
| 					name = tag[0:idx]
 | |
| 				}
 | |
| 
 | |
| 				if 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"] != "" {
 | |
| 					settings["CLASS"] = "UNIQUE"
 | |
| 				}
 | |
| 
 | |
| 				priority, err := strconv.Atoi(settings["PRIORITY"])
 | |
| 				if err != nil {
 | |
| 					priority = 10
 | |
| 				}
 | |
| 
 | |
| 				indexes = append(indexes, Index{
 | |
| 					Name:    name,
 | |
| 					Class:   settings["CLASS"],
 | |
| 					Type:    settings["TYPE"],
 | |
| 					Where:   settings["WHERE"],
 | |
| 					Comment: settings["COMMENT"],
 | |
| 					Option:  settings["OPTION"],
 | |
| 					Fields: []IndexOption{{
 | |
| 						Field:      field,
 | |
| 						Expression: settings["EXPRESSION"],
 | |
| 						Sort:       settings["SORT"],
 | |
| 						Collate:    settings["COLLATE"],
 | |
| 						Length:     length,
 | |
| 						priority:   priority,
 | |
| 					}},
 | |
| 				})
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	err = nil
 | |
| 	return
 | |
| }
 |