package sql import ( "errors" "git.sxidc.com/go-tools/utils/strutils" "github.com/iancoleman/strcase" "reflect" "strings" "time" ) const ( sqlResultDefaultSplitWith = "::" sqlResultTagPartSeparator = ";" sqlResultTagPartKeyValueSeparator = ":" ) const ( sqlResultTagKey = "sqlresult" sqlResultIgnore = "-" sqlResultColumn = "column" sqlResultParseTime = "parseTime" sqlResultAes = "aes" sqlResultSplitWith = "splitWith" ) type Result struct { ResultElement map[string]any } type ResultColumn struct { Name string ParseTime string AESKey string SplitWith string // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 FieldTypeElem reflect.Type FieldValueElem reflect.Value } func ParseSqlResultTag(e any) (*Result, 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() } sqlResult := new(Result) sqlResult.ResultElement = make(map[string]any) fieldNum := entityType.NumField() for i := 0; i < fieldNum; i++ { field := entityType.Field(i) fieldValue := entityValue.Field(i) element, err := parseSqlResultElement(field, fieldValue) if err != nil { return nil, err } if element == nil { continue } sqlResult.ResultElement[field.Name] = element } return sqlResult, nil } func parseSqlResultElement(field reflect.StructField, fieldValue reflect.Value) (any, error) { sqlResultTag := field.Tag.Get(sqlResultTagKey) if sqlResultTag == sqlResultIgnore { return nil, nil } fieldValueTypeElem := field.Type if field.Type.Kind() == reflect.Ptr { fieldValueTypeElem = field.Type.Elem() } fieldValueElem := fieldValue if fieldValue.Kind() == reflect.Ptr { if !fieldValue.IsValid() || fieldValue.IsNil() { if !fieldValue.CanSet() { return nil, nil } fieldValue.Set(reflect.New(fieldValueTypeElem).Elem().Addr()) } fieldValueElem = fieldValue.Elem() } if fieldValueTypeElem.Kind() == reflect.Struct && fieldValueTypeElem != reflect.TypeOf(time.Time{}) { if !fieldValueElem.CanAddr() { return nil, errors.New("请使用指针作为变量") } return ParseSqlResultTag(fieldValueElem.Addr().Interface()) } sqlColumn := &ResultColumn{ Name: strcase.ToSnake(field.Name), ParseTime: "", AESKey: "", SplitWith: sqlResultDefaultSplitWith, OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: fieldValueTypeElem, FieldValueElem: fieldValueElem, } if strutils.IsStringEmpty(sqlResultTag) { return sqlColumn, nil } sqlResultParts := strings.Split(sqlResultTag, sqlResultTagPartSeparator) if sqlResultParts != nil || len(sqlResultParts) != 0 { for _, sqlResultPart := range sqlResultParts { sqlPartKeyValue := strings.SplitN(strings.TrimSpace(sqlResultPart), sqlResultTagPartKeyValueSeparator, 2) if sqlPartKeyValue != nil && len(sqlPartKeyValue) == 2 && strutils.IsStringNotEmpty(sqlPartKeyValue[1]) { sqlPartKeyValue[1] = strings.Trim(sqlPartKeyValue[1], "'") } switch sqlPartKeyValue[0] { case sqlResultColumn: sqlColumn.Name = sqlPartKeyValue[1] case sqlResultParseTime: sqlColumn.ParseTime = sqlPartKeyValue[1] case sqlResultAes: if len(sqlPartKeyValue[1]) != 32 { return nil, errors.New("AES密钥长度应该为32个字节") } sqlColumn.AESKey = sqlPartKeyValue[1] case sqlResultSplitWith: if strutils.IsStringEmpty(sqlPartKeyValue[1]) { return nil, errors.New(sqlResultDefaultSplitWith + "没有赋值分隔符") } if fieldValueTypeElem.Kind() != reflect.Slice || fieldValueTypeElem.Elem().Kind() != reflect.String { return nil, errors.New(sqlResultDefaultSplitWith + "应该添加在[]string字段上") } sqlColumn.SplitWith = sqlPartKeyValue[1] default: continue } } } return sqlColumn, nil }