github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/gormgen/internal/model/tbl_column.go (about)

     1  package model
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  
     8  	"github.com/unionj-cloud/go-doudou/v2/toolkit/gormgen/field"
     9  	"gorm.io/gorm"
    10  )
    11  
    12  // Column table column's info
    13  type Column struct {
    14  	gorm.ColumnType
    15  	TableName   string                                                        `gorm:"column:TABLE_NAME"`
    16  	Indexes     []*Index                                                      `gorm:"-"`
    17  	UseScanType bool                                                          `gorm:"-"`
    18  	dataTypeMap map[string]func(columnType gorm.ColumnType) (dataType string) `gorm:"-"`
    19  	jsonTagNS   func(columnName string) string                                `gorm:"-"`
    20  }
    21  
    22  // SetDataTypeMap set data type map
    23  func (c *Column) SetDataTypeMap(m map[string]func(columnType gorm.ColumnType) (dataType string)) {
    24  	c.dataTypeMap = m
    25  }
    26  
    27  // GetDataType get data type
    28  func (c *Column) GetDataType() (fieldtype string) {
    29  	if mapping, ok := c.dataTypeMap[c.DatabaseTypeName()]; ok {
    30  		return mapping(c.ColumnType)
    31  	}
    32  	if c.UseScanType && c.ScanType() != nil {
    33  		return c.ScanType().String()
    34  	}
    35  	return dataType.Get(c.DatabaseTypeName(), c.columnType())
    36  }
    37  
    38  // WithNS with name strategy
    39  func (c *Column) WithNS(jsonTagNS func(columnName string) string) {
    40  	c.jsonTagNS = jsonTagNS
    41  	if c.jsonTagNS == nil {
    42  		c.jsonTagNS = func(n string) string { return n }
    43  	}
    44  }
    45  
    46  // ToField convert to field
    47  func (c *Column) ToField(nullable, coverable, signable bool) *Field {
    48  	fieldType := c.GetDataType()
    49  	if signable && strings.Contains(c.columnType(), "unsigned") && strings.HasPrefix(fieldType, "int") {
    50  		fieldType = "u" + fieldType
    51  	}
    52  	switch {
    53  	case c.Name() == "deleted_at" && fieldType == "time.Time":
    54  		fieldType = "gorm.DeletedAt"
    55  	case coverable && c.needDefaultTag(c.defaultTagValue()):
    56  		fieldType = "*" + fieldType
    57  	case nullable:
    58  		if n, ok := c.Nullable(); ok && n {
    59  			fieldType = "*" + fieldType
    60  		}
    61  	}
    62  
    63  	var comment string
    64  	if c, ok := c.Comment(); ok {
    65  		comment = c
    66  	}
    67  
    68  	isPriKey, ok := c.PrimaryKey()
    69  
    70  	return &Field{
    71  		Name:             c.Name(),
    72  		Type:             fieldType,
    73  		ColumnName:       c.Name(),
    74  		MultilineComment: c.multilineComment(),
    75  		GORMTag:          c.buildGormTag(),
    76  		Tag:              map[string]string{field.TagKeyJson: c.jsonTagNS(c.Name())},
    77  		ColumnComment:    comment,
    78  		PriKey:           ok && isPriKey,
    79  	}
    80  }
    81  
    82  func (c *Column) multilineComment() bool {
    83  	cm, ok := c.Comment()
    84  	return ok && strings.Contains(cm, "\n")
    85  }
    86  
    87  func (c *Column) buildGormTag() field.GormTag {
    88  	tag := field.GormTag{
    89  		field.TagKeyGormColumn: []string{c.Name()},
    90  		field.TagKeyGormType:   []string{c.columnType()},
    91  	}
    92  	isPriKey, ok := c.PrimaryKey()
    93  	isValidPriKey := ok && isPriKey
    94  	if isValidPriKey {
    95  		tag.Set(field.TagKeyGormPrimaryKey, "")
    96  		if at, ok := c.AutoIncrement(); ok {
    97  			tag.Set(field.TagKeyGormAutoIncrement, fmt.Sprintf("%t", at))
    98  		}
    99  	} else if n, ok := c.Nullable(); ok && !n {
   100  		tag.Set(field.TagKeyGormNotNull, "")
   101  	}
   102  
   103  	for _, idx := range c.Indexes {
   104  		if idx == nil {
   105  			continue
   106  		}
   107  		if pk, _ := idx.PrimaryKey(); pk { //ignore PrimaryKey
   108  			continue
   109  		}
   110  		if uniq, _ := idx.Unique(); uniq {
   111  			tag.Append(field.TagKeyGormUniqueIndex, fmt.Sprintf("%s,priority:%d", idx.Name(), idx.Priority))
   112  		} else {
   113  			tag.Append(field.TagKeyGormIndex, fmt.Sprintf("%s,priority:%d", idx.Name(), idx.Priority))
   114  		}
   115  	}
   116  
   117  	if dtValue := c.defaultTagValue(); c.needDefaultTag(dtValue) { // cannot set default tag for primary key
   118  		tag.Set(field.TagKeyGormDefault, dtValue)
   119  	}
   120  	if comment, ok := c.Comment(); ok && comment != "" {
   121  		if c.multilineComment() {
   122  			comment = strings.ReplaceAll(comment, "\n", "\\n")
   123  		}
   124  		tag.Set(field.TagKeyGormComment, comment)
   125  	}
   126  	return tag
   127  }
   128  
   129  // needDefaultTag check if default tag needed
   130  func (c *Column) needDefaultTag(defaultTagValue string) bool {
   131  	if defaultTagValue == "" {
   132  		return false
   133  	}
   134  	switch c.ScanType().Kind() {
   135  	case reflect.Bool:
   136  		return defaultTagValue != "false"
   137  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
   138  		return defaultTagValue != "0"
   139  	case reflect.String:
   140  		return defaultTagValue != ""
   141  	case reflect.Struct:
   142  		return strings.Trim(defaultTagValue, "'0:- ") != ""
   143  	}
   144  	return c.Name() != "created_at" && c.Name() != "updated_at"
   145  }
   146  
   147  // defaultTagValue return gorm default tag's value
   148  func (c *Column) defaultTagValue() string {
   149  	value, ok := c.DefaultValue()
   150  	if !ok {
   151  		return ""
   152  	}
   153  	if value != "" && strings.TrimSpace(value) == "" {
   154  		return "'" + value + "'"
   155  	}
   156  	return value
   157  }
   158  
   159  func (c *Column) columnType() (v string) {
   160  	if cl, ok := c.ColumnType.ColumnType(); ok {
   161  		return cl
   162  	}
   163  	return c.DatabaseTypeName()
   164  }