package sql import ( "errors" "github.com/iancoleman/strcase" "reflect" "strings" "time" ) const ( sqlResultTagPartSeparator = ";" sqlResultTagPartKeyValueSeparator = ":" ) const ( sqlResultTagKey = "sqlresult" sqlResultIgnore = "-" sqlResultColumn = "column" sqlResultParseTime = "parseTime" sqlResultAes = "aes" ) type Result struct { ResultElement map[string]any } func ParseSqlResult(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 } type ResultStruct struct { ResultTypesAndValues } type ResultColumn struct { Name string ParseTime string AESKey string ResultTypesAndValues } type ResultTypesAndValues struct { // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 FieldTypeElem reflect.Type FieldValueElem reflect.Value } func parseSqlResultElement(field reflect.StructField, fieldValue reflect.Value) (any, error) { 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() { fieldValue.Set(reflect.New(fieldValueTypeElem).Elem().Addr()) } fieldValueElem = fieldValue.Elem() } if fieldValueTypeElem.Kind() == reflect.Struct && fieldValueTypeElem != reflect.TypeOf(time.Time{}) { return &ResultStruct{ ResultTypesAndValues: ResultTypesAndValues{ OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: fieldValueTypeElem, FieldValueElem: fieldValueElem, }, }, nil } sqlColumn := &ResultColumn{ Name: strcase.ToSnake(field.Name), ParseTime: "", AESKey: "", ResultTypesAndValues: ResultTypesAndValues{ OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: fieldValueTypeElem, FieldValueElem: fieldValueElem, }, } sqlResultTag, ok := field.Tag.Lookup(sqlResultTagKey) if !ok { return sqlColumn, nil } if sqlResultTag == sqlResultIgnore { return nil, nil } sqlResultParts := strings.Split(sqlResultTag, sqlResultTagPartSeparator) if sqlResultParts != nil || len(sqlResultParts) != 0 { for _, sqlResultPart := range sqlResultParts { sqlPartKeyValue := strings.SplitN(strings.TrimSpace(sqlResultPart), sqlResultTagPartKeyValueSeparator, 2) switch sqlPartKeyValue[0] { case sqlResultColumn: sqlColumn.Name = strings.TrimSpace(sqlPartKeyValue[1]) case sqlResultParseTime: sqlColumn.ParseTime = strings.TrimSpace(sqlPartKeyValue[1]) case sqlResultAes: if len(strings.TrimSpace(sqlPartKeyValue[1])) != 32 { return nil, errors.New("AES密钥长度应该为32个字节") } sqlColumn.AESKey = strings.TrimSpace(sqlPartKeyValue[1]) default: continue } } } return sqlColumn, nil }