package sql import ( "errors" "fmt" "git.sxidc.com/go-tools/utils/encoding" "git.sxidc.com/go-tools/utils/reflectutils" "git.sxidc.com/go-tools/utils/strutils" "git.sxidc.com/service-supports/ds-sdk/sdk" "reflect" "strings" "time" ) func ParseSqlResult[T any](input any) (T, error) { var zero T if input == nil { return zero, nil } // 构造需要遍历的tableRows tableRows, ok := input.([]sdk.SqlResult) if !ok { tableRow, ok := input.(sdk.SqlResult) if !ok { return zero, errors.New("输入数据应该为sdk.SqlResult或[]sdk.SqlResult") } tableRows = []sdk.SqlResult{tableRow} } // 构造outputValue typeCheckErr := errors.New("可以接受的类型为struct, *struct, []struct, []*struct") outputType := reflect.TypeOf(zero) if outputType.Kind() != reflect.Struct && outputType.Kind() != reflect.Ptr && outputType.Kind() != reflect.Slice { return zero, typeCheckErr } else if outputType.Kind() == reflect.Ptr && outputType.Elem().Kind() != reflect.Struct { return zero, typeCheckErr } else if outputType.Kind() == reflect.Slice && (outputType.Elem().Kind() != reflect.Struct && outputType.Elem().Kind() != reflect.Ptr) { return zero, typeCheckErr } else if outputType.Kind() == reflect.Slice && outputType.Elem().Kind() == reflect.Ptr && outputType.Elem().Elem().Kind() != reflect.Struct { return zero, typeCheckErr } var outputValue reflect.Value if outputType.Kind() == reflect.Struct || outputType.Kind() == reflect.Ptr { outputValue = reflect.New(outputType).Elem() } else { outputValue = reflect.MakeSlice(outputType, 0, 0) } for _, tableRow := range tableRows { // 构造输出实体 var outputEntity any if outputType.Kind() == reflect.Struct { outputEntity = outputValue.Addr().Interface() } else if outputType.Kind() == reflect.Ptr { outputEntity = reflect.New(outputType.Elem()).Interface() } else { if outputType.Elem().Kind() == reflect.Struct { outputEntity = reflect.New(outputType.Elem()).Interface() } else { outputValueElemPtr := reflect.New(outputType.Elem()).Elem() outputValueElemPtr.Set(reflect.New(outputType.Elem().Elem())) outputEntity = outputValueElemPtr.Interface() } } sqlResult, err := ParseSqlResultTag(outputEntity) if err != nil { return zero, err } err = formOutputEntity(tableRow, sqlResult) if err != nil { return zero, err } if outputType.Kind() == reflect.Ptr { outputValue = reflect.ValueOf(outputEntity) } else if outputType.Kind() == reflect.Slice { if outputType.Elem().Kind() == reflect.Struct { outputValue = reflect.Append(outputValue, reflect.ValueOf(outputEntity).Elem()) } else { outputValue = reflect.Append(outputValue, reflect.ValueOf(outputEntity)) } } } output, ok := outputValue.Interface().(T) if !ok { return zero, errors.New("输出类型不匹配") } return output, nil } func formOutputEntity(tableRow sdk.SqlResult, sqlResult *Result) error { for fieldName, resultElement := range sqlResult.ResultElement { switch element := resultElement.(type) { case *Result: err := formOutputEntity(tableRow, element) if err != nil { return err } case *ResultColumn: tableRowValue, ok := tableRow[element.Name] if !ok { continue } if tableRowValue == nil { continue } // 构造结构字段,如果结构字段是指针且为nil,需要构造元素 fieldTypeElem := element.FieldTypeElem fieldValueElem := element.FieldValueElem outputKind := reflectutils.GroupValueKind(fieldValueElem) if !fieldValueElem.CanSet() { continue } switch outputKind { case reflect.Bool: err := reflectutils.AssignBoolValue(tableRowValue, fieldValueElem) if err != nil { return err } case reflect.String: strValue := tableRowValue.(string) if strutils.IsStringNotEmpty(element.ParseTime) { parsedTime, err := sdk.ParseSqlResultTimeStr(strValue) if err != nil { return err } strValue = parsedTime.Format(element.ParseTime) } else if strutils.IsStringNotEmpty(element.AESKey) { if strutils.IsStringNotEmpty(strValue) { decryptedValue, err := encoding.AESDecrypt(strValue, element.AESKey) if err != nil { return err } strValue = decryptedValue } } err := reflectutils.AssignStringValue(strValue, fieldValueElem) if err != nil { return err } case reflect.Int64: err := reflectutils.AssignInt64Value(tableRowValue, fieldValueElem) if err != nil { return err } case reflect.Uint64: err := reflectutils.AssignUint64Value(tableRowValue, fieldValueElem) if err != nil { return err } case reflect.Float64: err := reflectutils.AssignFloat64Value(tableRowValue, fieldValueElem) if err != nil { return err } case reflect.Struct: if fieldValueElem.Type() == reflect.TypeOf(time.Time{}) { parsedTime, err := sdk.ParseSqlResultTimeStr(tableRowValue.(string)) if err != nil { return err } fieldValueElem.Set(reflect.ValueOf(parsedTime)) continue } return fmt.Errorf("字段: %s 列: %s 不支持的类型: %s", fieldName, element.Name, fieldTypeElem.String()) case reflect.Slice: if fieldTypeElem.Elem().Kind() != reflect.String { return errors.New("slice仅支持[]string") } strValue, ok := tableRowValue.(string) if !ok { return errors.New("slice仅支持[]string") } strParts := strings.Split(strValue, element.SplitWith) if strParts == nil || len(strParts) == 0 { return nil } valSlice := fieldValueElem if valSlice.IsNil() { valSlice = reflect.MakeSlice(fieldTypeElem, 0, 0) } for _, strPart := range strParts { valSlice = reflect.Append(valSlice, reflect.ValueOf(strPart)) } fieldValueElem.Set(valSlice) default: return fmt.Errorf("字段: %s 列: %s 不支持的类型: %s", fieldName, element.Name, fieldTypeElem.String()) } default: return errors.New("不支持的元素类型") } } return nil }