|
|
@@ -1,160 +1,240 @@
|
|
|
package tag
|
|
|
|
|
|
import (
|
|
|
- "git.sxidc.com/go-framework/baize/infrastructure/logger"
|
|
|
+ "git.sxidc.com/go-tools/utils/reflectutils"
|
|
|
"git.sxidc.com/go-tools/utils/strutils"
|
|
|
"git.sxidc.com/service-supports/fserr"
|
|
|
+ "git.sxidc.com/service-supports/fslog"
|
|
|
"reflect"
|
|
|
"strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
-func AssignTo[F any, T any](from F) T {
|
|
|
+func AssignTo[T any](from any) (T, error) {
|
|
|
var zero T
|
|
|
|
|
|
- assign, err := ParseAssignTag(from)
|
|
|
- if err != nil {
|
|
|
- logger.GetInstance().Error(err)
|
|
|
- return zero
|
|
|
+ if from == nil {
|
|
|
+ return zero, nil
|
|
|
}
|
|
|
|
|
|
- retType := reflect.TypeOf(zero)
|
|
|
- retValue := reflect.New(retType).Elem()
|
|
|
-
|
|
|
- return retValue.Interface()
|
|
|
-}
|
|
|
-
|
|
|
-const (
|
|
|
- assignDefaultStringSliceSeparator = "::"
|
|
|
- assignTagPartSeparator = ";"
|
|
|
- assignTagPartKeyValueSeparator = ":"
|
|
|
-)
|
|
|
-
|
|
|
-const (
|
|
|
- assignTagKey = "assign"
|
|
|
- assignIgnore = "-"
|
|
|
- assignToField = "toField"
|
|
|
- assignParseTime = "parseTime"
|
|
|
- assignFormatTime = "formatTime"
|
|
|
- assignJoinWith = "joinWith"
|
|
|
- assignSplitWith = "splitWith"
|
|
|
- assignTrim = "trim"
|
|
|
- assignTrimLeft = "trimLeft"
|
|
|
- assignTrimRight = "trimRight"
|
|
|
-)
|
|
|
-
|
|
|
-type Assign struct {
|
|
|
- AssignElement map[string]any
|
|
|
-}
|
|
|
-
|
|
|
-type AssignElement struct {
|
|
|
- ToField string
|
|
|
- ParseTime string
|
|
|
- FormatTime string
|
|
|
- JoinWith string
|
|
|
- SplitWith string
|
|
|
- Trim string
|
|
|
- TrimLeft string
|
|
|
- TrimRight string
|
|
|
-
|
|
|
- // 原字段的反射结构
|
|
|
- OriginFieldType reflect.Type
|
|
|
- OriginFieldValue reflect.Value
|
|
|
-
|
|
|
- // 值类型的反射结构
|
|
|
- FieldTypeElem reflect.Type
|
|
|
- FieldValueElem reflect.Value
|
|
|
-}
|
|
|
+ fromValue := reflect.ValueOf(from)
|
|
|
+ retValue := reflect.ValueOf(zero)
|
|
|
|
|
|
-func ParseAssignTag(from any) (*Assign, error) {
|
|
|
- if from == nil {
|
|
|
- return nil, fserr.New("没有传递结构或结构指针")
|
|
|
+ // 类型校验
|
|
|
+ if fromValue.Kind() != reflect.Ptr && fromValue.Kind() != reflect.Struct {
|
|
|
+ return zero, fserr.New("参数不是结构或结构指针")
|
|
|
}
|
|
|
|
|
|
- fromType := reflect.TypeOf(from)
|
|
|
+ if fromValue.Kind() == reflect.Ptr && fromValue.Kind() != reflect.Struct {
|
|
|
+ return zero, fserr.New("参数不是结构或结构指针")
|
|
|
+ }
|
|
|
|
|
|
- if fromType.Kind() != reflect.Ptr && fromType.Kind() != reflect.Struct {
|
|
|
- return nil, fserr.New("参数不是结构或结构指针")
|
|
|
+ if retValue.Kind() != reflect.Ptr && retValue.Kind() != reflect.Struct {
|
|
|
+ return zero, fserr.New("返回类型不是结构或结构指针")
|
|
|
}
|
|
|
|
|
|
- if fromType.Kind() == reflect.Ptr && fromType.Elem().Kind() != reflect.Struct {
|
|
|
- return nil, fserr.New("参数不是结构或结构指针")
|
|
|
+ if retValue.Kind() == reflect.Ptr && retValue.Elem().Kind() != reflect.Struct {
|
|
|
+ return zero, fserr.New("返回类型不是结构或结构指针")
|
|
|
}
|
|
|
|
|
|
- fromValue := reflect.ValueOf(from)
|
|
|
fromElemValue := fromValue
|
|
|
- if fromType.Kind() == reflect.Ptr {
|
|
|
+ if fromValue.Kind() == reflect.Ptr {
|
|
|
fromElemValue = fromValue.Elem()
|
|
|
}
|
|
|
|
|
|
- assign := new(Assign)
|
|
|
- assign.AssignElement = make(map[string]any)
|
|
|
+ retElemValue := retValue
|
|
|
+ if retValue.Kind() == reflect.Ptr {
|
|
|
+ retElemValue = retValue.Elem()
|
|
|
+ }
|
|
|
|
|
|
for i := 0; i < fromElemValue.NumField(); i++ {
|
|
|
- field := fromType.Field(i)
|
|
|
- fieldValue := fromElemValue.Field(i)
|
|
|
+ fromField := fromElemValue.Type().Field(i)
|
|
|
+ tag, err := parseAssignTag(fromField)
|
|
|
+ if err != nil {
|
|
|
+ return zero, err
|
|
|
+ }
|
|
|
|
|
|
- // 零值,不用赋值
|
|
|
- if !fieldValue.IsValid() {
|
|
|
+ if tag == nil {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- element, err := parseSqlMappingElement(field, fieldValue)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
+ fromFieldValue := fromElemValue.Field(i)
|
|
|
+
|
|
|
+ // 无效零值,不进行赋值
|
|
|
+ if !fromFieldValue.IsValid() || fromFieldValue.IsNil() || fromFieldValue.IsZero() {
|
|
|
+ continue
|
|
|
}
|
|
|
|
|
|
- if element == nil {
|
|
|
+ fromFieldElemValue := fromFieldValue
|
|
|
+ if fromFieldValue.Kind() == reflect.Ptr {
|
|
|
+ fromFieldElemValue = fromFieldValue.Elem()
|
|
|
+ }
|
|
|
+
|
|
|
+ retFieldValue := retElemValue.FieldByName(tag.ToField)
|
|
|
+
|
|
|
+ // 不存在对应的字段
|
|
|
+ if !retFieldValue.IsValid() {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- assign.AssignElement[field.Name] = element
|
|
|
+ retFieldElemValue := retFieldValue
|
|
|
+ if retFieldValue.Kind() == reflect.Ptr {
|
|
|
+ if !retFieldValue.IsValid() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if !retFieldValue.CanSet() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 空值针,初始化
|
|
|
+ if retFieldValue.IsNil() {
|
|
|
+ retFieldValue.Set(reflect.New(retFieldValue.Type().Elem()))
|
|
|
+ }
|
|
|
+
|
|
|
+ retFieldElemValue = retFieldValue.Elem()
|
|
|
+ }
|
|
|
+
|
|
|
+ err = assignTo(fromFieldElemValue, retFieldElemValue, tag)
|
|
|
+ if err != nil {
|
|
|
+ return zero, err
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return assign, nil
|
|
|
+ return retValue.Interface(), nil
|
|
|
}
|
|
|
|
|
|
-func parseSqlMappingElement(field reflect.StructField, fieldValue reflect.Value) (any, error) {
|
|
|
- assignTag := field.Tag.Get(assignTagKey)
|
|
|
- if assignTag == assignIgnore {
|
|
|
- return nil, nil
|
|
|
+func assignTo(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Value, tag *assignTag) error {
|
|
|
+ fromKind := reflectutils.GroupValueKind(fromFieldElemValue)
|
|
|
+ retKind := reflectutils.GroupValueKind(retFieldElemValue)
|
|
|
+
|
|
|
+ var fromAny any
|
|
|
+ switch fromKind {
|
|
|
+ case reflect.Struct:
|
|
|
+ if fromFieldElemValue.Type().String() == "time.Time" && retKind == reflect.String {
|
|
|
+ fromString := fromFieldElemValue.Interface().(time.Time).Format(tag.FormatTime)
|
|
|
+ fromAny = trimFromString(fromString, tag)
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ fromAny = fromFieldElemValue.Interface()
|
|
|
+ case reflect.Slice:
|
|
|
+ if fromFieldElemValue.Elem().Kind() == reflect.String && retKind == reflect.String {
|
|
|
+ fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
|
|
|
+ fromAny = trimFromString(fromString, tag)
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ fromAny = fromFieldElemValue.Interface()
|
|
|
+ case reflect.String:
|
|
|
+ fromString := fromFieldElemValue.String()
|
|
|
+
|
|
|
+ if retKind == reflect.Struct && retFieldElemValue.Type().String() == "time.Time" {
|
|
|
+ retTimeField, err := time.ParseInLocation(tag.ParseTime, fromString, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ fromAny = retTimeField
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ if retFieldElemValue.Kind() == reflect.Slice && retFieldElemValue.Elem().Kind() == reflect.String {
|
|
|
+ fromAny = strings.Split(fromString, tag.SplitWith)
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ fromAny = trimFromString(fromString, tag)
|
|
|
+ default:
|
|
|
+ fromAny = fromFieldElemValue.Interface()
|
|
|
}
|
|
|
|
|
|
- fieldValueElemType := field.Type
|
|
|
- if field.Type.Kind() == reflect.Ptr {
|
|
|
- fieldValueElemType = field.Type.Elem()
|
|
|
+ switch retKind {
|
|
|
+ case reflect.Int64:
|
|
|
+ return reflectutils.AssignInt64Value(fromAny, retFieldElemValue)
|
|
|
+ case reflect.Uint64:
|
|
|
+ return reflectutils.AssignUint64Value(fromAny, retFieldElemValue)
|
|
|
+ case reflect.Float64:
|
|
|
+ return reflectutils.AssignFloat64Value(fromAny, retFieldElemValue)
|
|
|
+ case reflect.Bool:
|
|
|
+ return reflectutils.AssignBoolValue(fromAny, retFieldElemValue)
|
|
|
+ case reflect.String:
|
|
|
+ return reflectutils.AssignStringValue(fromAny, retFieldElemValue)
|
|
|
+ default:
|
|
|
+ retFieldElemValue.Set(reflect.ValueOf(fromAny))
|
|
|
+ return nil
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- fieldValueElem := fieldValue
|
|
|
- if fieldValue.Kind() == reflect.Ptr {
|
|
|
- fieldValueElem = fieldValue.Elem()
|
|
|
+func trimFromString(fromString string, tag *assignTag) string {
|
|
|
+ if strutils.IsStringNotEmpty(tag.Trim) {
|
|
|
+ return strings.Trim(fromString, tag.Trim)
|
|
|
+ } else {
|
|
|
+ if strutils.IsStringNotEmpty(tag.TrimPrefix) {
|
|
|
+ return strings.TrimPrefix(fromString, tag.TrimPrefix)
|
|
|
+ }
|
|
|
+
|
|
|
+ if strutils.IsStringNotEmpty(tag.TrimSuffix) {
|
|
|
+ return strings.TrimSuffix(fromString, tag.TrimSuffix)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if fieldValueElemType.Kind() == reflect.Struct && fieldValueElemType != reflect.TypeOf(time.Time{}) {
|
|
|
- return ParseAssignTag(fieldValueElem.Interface())
|
|
|
+ return fromString
|
|
|
+}
|
|
|
+
|
|
|
+const (
|
|
|
+ assignDefaultStringSliceSeparator = "::"
|
|
|
+ assignTagPartSeparator = ";"
|
|
|
+ assignTagPartKeyValueSeparator = ":"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ assignTagKey = "assign"
|
|
|
+ assignIgnore = "-"
|
|
|
+ assignToField = "toField"
|
|
|
+ assignParseTime = "parseTime"
|
|
|
+ assignFormatTime = "formatTime"
|
|
|
+ assignJoinWith = "joinWith"
|
|
|
+ assignSplitWith = "splitWith"
|
|
|
+ assignTrim = "trim"
|
|
|
+ assignTrimPrefix = "trimPrefix"
|
|
|
+ assignTrimSuffix = "trimSuffix"
|
|
|
+)
|
|
|
+
|
|
|
+type assignTag struct {
|
|
|
+ ToField string
|
|
|
+ ParseTime string
|
|
|
+ FormatTime string
|
|
|
+ JoinWith string
|
|
|
+ SplitWith string
|
|
|
+ Trim string
|
|
|
+ TrimPrefix string
|
|
|
+ TrimSuffix string
|
|
|
+}
|
|
|
+
|
|
|
+func parseAssignTag(field reflect.StructField) (*assignTag, error) {
|
|
|
+ tagStr := field.Tag.Get(assignTagKey)
|
|
|
+
|
|
|
+ if tagStr == assignIgnore {
|
|
|
+ return nil, nil
|
|
|
}
|
|
|
|
|
|
- element := &AssignElement{
|
|
|
+ tag := &assignTag{
|
|
|
ToField: field.Name,
|
|
|
ParseTime: time.DateTime,
|
|
|
FormatTime: time.DateTime,
|
|
|
JoinWith: assignDefaultStringSliceSeparator,
|
|
|
SplitWith: assignDefaultStringSliceSeparator,
|
|
|
Trim: "",
|
|
|
- TrimLeft: "",
|
|
|
- TrimRight: "",
|
|
|
-
|
|
|
- OriginFieldType: field.Type,
|
|
|
- OriginFieldValue: fieldValue,
|
|
|
- FieldTypeElem: fieldValueElemType,
|
|
|
- FieldValueElem: fieldValueElem,
|
|
|
+ TrimPrefix: "",
|
|
|
+ TrimSuffix: "",
|
|
|
}
|
|
|
|
|
|
- if strutils.IsStringEmpty(assignTag) {
|
|
|
- return element, nil
|
|
|
+ if strutils.IsStringEmpty(tagStr) {
|
|
|
+ return tag, nil
|
|
|
}
|
|
|
|
|
|
- assignParts := strings.Split(assignTag, assignTagPartSeparator)
|
|
|
+ assignParts := strings.Split(tagStr, assignTagPartSeparator)
|
|
|
if assignParts != nil || len(assignParts) != 0 {
|
|
|
for _, assignPart := range assignParts {
|
|
|
assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2)
|
|
|
@@ -165,62 +245,36 @@ func parseSqlMappingElement(field reflect.StructField, fieldValue reflect.Value)
|
|
|
|
|
|
switch assignPartKeyValue[0] {
|
|
|
case assignToField:
|
|
|
- element.ToField = assignPartKeyValue[1]
|
|
|
+ tag.ToField = assignPartKeyValue[1]
|
|
|
case assignParseTime:
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignParseTime + "应该添加在string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.ParseTime = assignPartKeyValue[1]
|
|
|
+ tag.ParseTime = assignPartKeyValue[1]
|
|
|
case assignFormatTime:
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.Struct && fieldValueElemType != reflect.TypeOf(time.Time{}) {
|
|
|
- return nil, fserr.New(assignFormatTime + "应该添加在time.Time字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.FormatTime = assignPartKeyValue[1]
|
|
|
+ tag.FormatTime = assignPartKeyValue[1]
|
|
|
case assignJoinWith:
|
|
|
if strutils.IsStringEmpty(assignPartKeyValue[1]) {
|
|
|
return nil, fserr.New(assignJoinWith + "没有赋值分隔符")
|
|
|
}
|
|
|
|
|
|
- if fieldValueElemType.Kind() != reflect.Slice || fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignJoinWith + "应该添加在[]string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.JoinWith = assignPartKeyValue[1]
|
|
|
+ tag.JoinWith = assignPartKeyValue[1]
|
|
|
case assignSplitWith:
|
|
|
if strutils.IsStringEmpty(assignPartKeyValue[1]) {
|
|
|
return nil, fserr.New(assignSplitWith + "没有赋值分隔符")
|
|
|
}
|
|
|
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignSplitWith + "应该添加在string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.SplitWith = assignPartKeyValue[1]
|
|
|
+ tag.SplitWith = assignPartKeyValue[1]
|
|
|
case assignTrim:
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignTrim + "应该添加在string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.Trim = assignPartKeyValue[1]
|
|
|
- case assignTrimLeft:
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignTrimLeft + "应该添加在string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.TrimLeft = assignPartKeyValue[1]
|
|
|
- case assignTrimRight:
|
|
|
- if fieldValueElemType.Elem().Kind() != reflect.String {
|
|
|
- return nil, fserr.New(assignTrimRight + "应该添加在string字段上")
|
|
|
- }
|
|
|
-
|
|
|
- element.TrimRight = assignPartKeyValue[1]
|
|
|
+ tag.Trim = assignPartKeyValue[1]
|
|
|
+ case assignTrimPrefix:
|
|
|
+ tag.TrimPrefix = assignPartKeyValue[1]
|
|
|
+ case assignTrimSuffix:
|
|
|
+ tag.TrimSuffix = assignPartKeyValue[1]
|
|
|
default:
|
|
|
+ err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0])
|
|
|
+ fslog.Error(err)
|
|
|
continue
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return element, nil
|
|
|
+ return tag, nil
|
|
|
}
|