package sql import ( "errors" "github.com/iancoleman/strcase" "reflect" "strings" ) const ( defaultKeyColumnName = "id" sqlMappingTagPartSeparator = ";" sqlMappingTagPartKeyValueSeparator = ":" ) const ( sqlMappingTagKey = "sqlmapping" sqlMappingIgnore = "-" sqlMappingColumn = "column" sqlMappingKey = "key" sqlMappingNotUpdate = "notUpdate" sqlMappingUpdateClear = "updateClear" sqlMappingAes = "aes" ) type Mapping struct { ColumnMap map[string]MappingColumn } func ParseSqlMapping(e any) (*Mapping, error) { if e == nil { return nil, errors.New("没有传递实体") } entityType := reflect.TypeOf(e) if entityType.Kind() == reflect.Ptr { entityType = entityType.Elem() } if entityType.Kind() != reflect.Struct { return nil, errors.New("传递的实体不是结构类型") } entityValue := reflect.ValueOf(e) if entityValue.Kind() == reflect.Ptr { entityValue = entityValue.Elem() } sqlMapping := new(Mapping) sqlMapping.ColumnMap = make(map[string]MappingColumn) fieldNum := entityType.NumField() for i := 0; i < fieldNum; i++ { field := entityType.Field(i) fieldValue := entityValue.Field(i) column, err := parseSqlMappingColumn(field, fieldValue) if err != nil { return nil, err } if column == nil { continue } sqlMapping.ColumnMap[field.Name] = *column } return sqlMapping, nil } type MappingColumn struct { Name string IsKey bool CanUpdate bool CanUpdateClear bool AESKey string // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 FieldTypeElem reflect.Type FieldValueElem reflect.Value } func parseSqlMappingColumn(field reflect.StructField, fieldValue reflect.Value) (*MappingColumn, error) { valueFieldType := field.Type valueFieldValue := fieldValue if valueFieldType.Kind() == reflect.Ptr { valueFieldType = valueFieldType.Elem() if !valueFieldValue.IsValid() || valueFieldValue.IsNil() || valueFieldValue.IsZero() { valueFieldValue = reflect.Zero(valueFieldType) } else { valueFieldValue = fieldValue.Elem() } } sqlColumn := &MappingColumn{ Name: strcase.ToSnake(field.Name), IsKey: false, CanUpdate: true, CanUpdateClear: false, AESKey: "", OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: valueFieldType, FieldValueElem: valueFieldValue, } if sqlColumn.Name == defaultKeyColumnName { sqlColumn.IsKey = true sqlColumn.CanUpdate = false } sqlMappingTag, ok := field.Tag.Lookup(sqlMappingTagKey) if !ok { return sqlColumn, nil } if sqlMappingTag == sqlMappingIgnore { return nil, nil } sqlMappingParts := strings.Split(sqlMappingTag, sqlMappingTagPartSeparator) if sqlMappingParts != nil || len(sqlMappingParts) != 0 { for _, sqlMappingPart := range sqlMappingParts { sqlPartKeyValue := strings.SplitN(strings.TrimSpace(sqlMappingPart), sqlMappingTagPartKeyValueSeparator, 2) switch sqlPartKeyValue[0] { case sqlMappingColumn: sqlColumn.Name = strings.TrimSpace(sqlPartKeyValue[1]) case sqlMappingKey: sqlColumn.IsKey = true sqlColumn.CanUpdate = false case sqlMappingNotUpdate: sqlColumn.CanUpdate = false case sqlMappingUpdateClear: sqlColumn.CanUpdateClear = true case sqlMappingAes: if len(strings.TrimSpace(sqlPartKeyValue[1])) != 32 { return nil, errors.New("AES密钥长度应该为32个字节") } sqlColumn.AESKey = strings.TrimSpace(sqlPartKeyValue[1]) default: continue } } } return sqlColumn, nil }