package sql import ( "errors" "github.com/iancoleman/strcase" "reflect" "strings" ) const ( sqlResultTagPartSeparator = ";" sqlResultTagPartKeyValueSeparator = ":" ) const ( sqlResultTagKey = "sqlresult" sqlResultIgnore = "-" sqlResultColumn = "column" sqlResultParseTime = "parseTime" sqlResultAes = "aes" ) type Result struct { ColumnMap map[string]ResultColumn } 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.ColumnMap = make(map[string]ResultColumn) fieldNum := entityType.NumField() for i := 0; i < fieldNum; i++ { field := entityType.Field(i) fieldValue := entityValue.Field(i) column, err := parseSqlResultColumn(field, fieldValue) if err != nil { return nil, err } if column == nil { continue } sqlResult.ColumnMap[field.Name] = *column } return sqlResult, nil } type ResultColumn struct { Name string ParseTime string AESKey string // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 FieldTypeElem reflect.Type FieldValueElem reflect.Value } func parseSqlResultColumn(field reflect.StructField, fieldValue reflect.Value) (*ResultColumn, 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 := &ResultColumn{ Name: strcase.ToSnake(field.Name), ParseTime: "", AESKey: "", OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: valueFieldType, FieldValueElem: valueFieldValue, } 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 }