Browse Source

完成assign tag定义

yjp 1 năm trước cách đây
mục cha
commit
9930813a90
5 tập tin đã thay đổi với 237 bổ sung8 xóa
  1. 1 1
      binding/dto.go
  2. 6 6
      domain/object.go
  3. 2 1
      go.mod
  4. 2 0
      go.sum
  5. 226 0
      tag/assign_struct.go

+ 1 - 1
binding/dto.go

@@ -55,7 +55,7 @@ func getDTOFieldValue(dto DTO, fieldName string) (*reflect.Value, error) {
 	}
 
 	dtoValue := reflect.ValueOf(dto)
-	if !dtoValue.IsValid() {
+	if dtoType.Kind() == reflect.Ptr && !dtoValue.IsValid() {
 		return nil, fserr.New("dto为nil")
 	}
 

+ 6 - 6
domain/object.go

@@ -60,22 +60,22 @@ func ToConcreteObject[T Object](object Object) (T, error) {
 }
 
 func getObjectFieldValue(object Object, fieldName string) (*reflect.Value, error) {
-	dtoType := reflect.TypeOf(object)
+	objectType := reflect.TypeOf(object)
 
-	if dtoType.Kind() != reflect.Ptr {
+	if objectType.Kind() != reflect.Ptr {
 		return nil, fserr.New("object必须是结构指针类型")
 	}
 
-	if dtoType.Kind() == reflect.Ptr && dtoType.Elem().Kind() != reflect.Struct {
+	if objectType.Kind() == reflect.Ptr && objectType.Elem().Kind() != reflect.Struct {
 		return nil, fserr.New("object必须是结构指针类型")
 	}
 
-	dtoValue := reflect.ValueOf(object)
-	if !dtoValue.IsValid() {
+	objectValue := reflect.ValueOf(object)
+	if objectType.Kind() == reflect.Ptr && !objectValue.IsValid() {
 		return nil, fserr.New("object为nil")
 	}
 
-	fieldValue := dtoValue.Elem().FieldByName(fieldName)
+	fieldValue := objectValue.Elem().FieldByName(fieldName)
 
 	return &fieldValue, nil
 }

+ 2 - 1
go.mod

@@ -5,9 +5,9 @@ go 1.22.3
 require (
 	git.sxidc.com/go-tools/utils v1.5.7
 	git.sxidc.com/service-supports/fserr v0.3.5
-	git.sxidc.com/service-supports/fslog v0.5.9
 	git.sxidc.com/service-supports/websocket v1.3.1
 	github.com/gin-gonic/gin v1.10.0
+	github.com/iancoleman/strcase v0.3.0
 	github.com/vrecan/death v3.0.1+incompatible
 	go.uber.org/zap v1.27.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
@@ -15,6 +15,7 @@ require (
 )
 
 require (
+	git.sxidc.com/service-supports/fslog v0.5.9 // indirect
 	github.com/bytedance/sonic v1.11.6 // indirect
 	github.com/bytedance/sonic/loader v0.1.1 // indirect
 	github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect

+ 2 - 0
go.sum

@@ -42,6 +42,8 @@ github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25d
 github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
+github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=

+ 226 - 0
tag/assign_struct.go

@@ -0,0 +1,226 @@
+package tag
+
+import (
+	"git.sxidc.com/go-framework/baize/infrastructure/logger"
+	"git.sxidc.com/go-tools/utils/strutils"
+	"git.sxidc.com/service-supports/fserr"
+	"reflect"
+	"strings"
+	"time"
+)
+
+func AssignTo[F any, T any](from F) T {
+	var zero T
+
+	assign, err := ParseAssignTag(from)
+	if err != nil {
+		logger.GetInstance().Error(err)
+		return zero
+	}
+
+	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
+}
+
+func ParseAssignTag(from any) (*Assign, error) {
+	if from == nil {
+		return nil, fserr.New("没有传递结构或结构指针")
+	}
+
+	fromType := reflect.TypeOf(from)
+
+	if fromType.Kind() != reflect.Ptr && fromType.Kind() != reflect.Struct {
+		return nil, fserr.New("参数不是结构或结构指针")
+	}
+
+	if fromType.Kind() == reflect.Ptr && fromType.Elem().Kind() != reflect.Struct {
+		return nil, fserr.New("参数不是结构或结构指针")
+	}
+
+	fromValue := reflect.ValueOf(from)
+	fromElemValue := fromValue
+	if fromType.Kind() == reflect.Ptr {
+		fromElemValue = fromValue.Elem()
+	}
+
+	assign := new(Assign)
+	assign.AssignElement = make(map[string]any)
+
+	for i := 0; i < fromElemValue.NumField(); i++ {
+		field := fromType.Field(i)
+		fieldValue := fromElemValue.Field(i)
+
+		// 零值,不用赋值
+		if !fieldValue.IsValid() {
+			continue
+		}
+
+		element, err := parseSqlMappingElement(field, fieldValue)
+		if err != nil {
+			return nil, err
+		}
+
+		if element == nil {
+			continue
+		}
+
+		assign.AssignElement[field.Name] = element
+	}
+
+	return assign, nil
+}
+
+func parseSqlMappingElement(field reflect.StructField, fieldValue reflect.Value) (any, error) {
+	assignTag := field.Tag.Get(assignTagKey)
+	if assignTag == assignIgnore {
+		return nil, nil
+	}
+
+	fieldValueElemType := field.Type
+	if field.Type.Kind() == reflect.Ptr {
+		fieldValueElemType = field.Type.Elem()
+	}
+
+	fieldValueElem := fieldValue
+	if fieldValue.Kind() == reflect.Ptr {
+		fieldValueElem = fieldValue.Elem()
+	}
+
+	if fieldValueElemType.Kind() == reflect.Struct && fieldValueElemType != reflect.TypeOf(time.Time{}) {
+		return ParseAssignTag(fieldValueElem.Interface())
+	}
+
+	element := &AssignElement{
+		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,
+	}
+
+	if strutils.IsStringEmpty(assignTag) {
+		return element, nil
+	}
+
+	assignParts := strings.Split(assignTag, assignTagPartSeparator)
+	if assignParts != nil || len(assignParts) != 0 {
+		for _, assignPart := range assignParts {
+			assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2)
+			if assignPartKeyValue != nil && len(assignPartKeyValue) == 2 && strutils.IsStringNotEmpty(assignPartKeyValue[1]) {
+				// 可以支持' ' ',获取到'字符
+				assignPartKeyValue[1] = strings.TrimSpace(strings.Trim(assignPartKeyValue[1], "'"))
+			}
+
+			switch assignPartKeyValue[0] {
+			case assignToField:
+				element.ToField = assignPartKeyValue[1]
+			case assignParseTime:
+				if fieldValueElemType.Elem().Kind() != reflect.String {
+					return nil, fserr.New(assignParseTime + "应该添加在string字段上")
+				}
+
+				element.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]
+			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]
+			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]
+			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]
+			default:
+				continue
+			}
+		}
+	}
+
+	return element, nil
+}