Browse Source

完成sqlresult移植

yjp 1 year ago
parent
commit
5e85d61173

+ 13 - 0
binding/dto.go

@@ -1,13 +1,26 @@
 package binding
 
 import (
+	"git.sxidc.com/go-framework/baize/domain"
 	"git.sxidc.com/go-framework/baize/infrastructure/logger"
+	"git.sxidc.com/go-framework/baize/tag"
 	"git.sxidc.com/service-supports/fserr"
 	"reflect"
 )
 
 type DTO interface{}
 
+func AssignDTOToDomainObject(dto DTO, domainObject domain.Object) error {
+	return tag.UseAssignTag(dto, domainObject,
+		func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, assignTag *tag.AssignTag) error {
+			if fromFieldElemValue.IsZero() {
+				return nil
+			}
+
+			return tag.DefaultOnAssignParsedFieldTagFunc(fromFieldElemValue, retFieldElementValue, assignTag)
+		})
+}
+
 func Field[T any](dto DTO, fieldName string) T {
 	var zero T
 

+ 3 - 20
examples/assign_tag/main.go

@@ -31,8 +31,8 @@ type ClassDomain struct {
 func main() {
 	class := new(ClassDomain)
 
-	err := tag.CustomAssignTo(&UpdateClassJsonBody{}, class,
-		func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *tag.AssignTag) error {
+	err := tag.UseAssignTag(&UpdateClassJsonBody{}, class,
+		func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, assignTag *tag.AssignTag) error {
 			fmt.Println("Field Name:", fromFieldName)
 			fmt.Println("Type:", fromFieldElemValue.Type().String())
 			if fromFieldElemValue.Kind() == reflect.String {
@@ -40,7 +40,7 @@ func main() {
 			} else {
 				fmt.Printf("%+v\n", fromFieldElemValue.Interface())
 			}
-			fmt.Printf("%+v\n", tag)
+			fmt.Printf("%+v\n", assignTag)
 			fmt.Println()
 
 			return nil
@@ -48,21 +48,4 @@ func main() {
 	if err != nil {
 		panic(err)
 	}
-
-	now := time.Now()
-
-	jsonBody := &UpdateClassJsonBody{
-		JsonBodyID: JsonBodyID{
-			ID: "test_id",
-		},
-		Name:        "test",
-		CreatedTime: &now,
-	}
-
-	err = tag.AssignTo(jsonBody, class)
-	if err != nil {
-		panic(err)
-	}
-
-	fmt.Printf("%+v\n", class)
 }

+ 3 - 4
examples/binding/main.go

@@ -7,7 +7,6 @@ import (
 	"git.sxidc.com/go-framework/baize/application"
 	"git.sxidc.com/go-framework/baize/binding"
 	"git.sxidc.com/go-framework/baize/domain"
-	"git.sxidc.com/go-framework/baize/tag"
 	"git.sxidc.com/go-tools/utils/strutils"
 	DEATH "github.com/vrecan/death"
 	"syscall"
@@ -71,7 +70,7 @@ func main() {
 		DTO:          &CreateClassJsonBody{},
 		FormDomainObjectsFunc: func(c *api.Context, dto binding.DTO) ([]domain.Object, error) {
 			class := new(Class)
-			err := tag.AssignTo(dto, class)
+			err := binding.AssignDTOToDomainObject(dto, class)
 			if err != nil {
 				return nil, err
 			}
@@ -147,7 +146,7 @@ func main() {
 		DTO:          &QueryClassesQueryParams{},
 		FormDomainObjectsFunc: func(c *api.Context, dto binding.DTO) ([]domain.Object, error) {
 			class := new(Class)
-			err := tag.AssignTo(dto, class)
+			err := binding.AssignDTOToDomainObject(dto, class)
 
 			if err != nil {
 				return nil, err
@@ -222,7 +221,7 @@ func main() {
 		DTO:          &GetClassQueryParams{},
 		FormDomainObjectsFunc: func(c *api.Context, dto binding.DTO) ([]domain.Object, error) {
 			class := new(Class)
-			err := tag.AssignTo(dto, class)
+			err := binding.AssignDTOToDomainObject(dto, class)
 			if err != nil {
 				return nil, err
 			}

+ 2 - 2
examples/sql_mapping_tag/main.go

@@ -32,7 +32,7 @@ type Class struct {
 }
 
 func main() {
-	err := tag.BuildExecuteParams(&Class{}, func(fieldName string, entityFieldElemValue reflect.Value, tag *tag.SqlMappingTag) error {
+	err := tag.UseSqlMappingTag(&Class{}, func(fieldName string, entityFieldElemValue reflect.Value, sqlMappingTag *tag.SqlMappingTag) error {
 		fmt.Println("Field Name:", fieldName)
 		fmt.Println("Type:", entityFieldElemValue.Type().String())
 		if entityFieldElemValue.Kind() == reflect.String {
@@ -40,7 +40,7 @@ func main() {
 		} else {
 			fmt.Printf("%+v\n", entityFieldElemValue.Interface())
 		}
-		fmt.Printf("%+v\n", tag)
+		fmt.Printf("%+v\n", sqlMappingTag)
 		fmt.Println()
 
 		return nil

+ 51 - 0
examples/sql_result_tag/main.go

@@ -0,0 +1,51 @@
+package main
+
+import (
+	"fmt"
+	"git.sxidc.com/go-framework/baize/tag"
+	"reflect"
+	"time"
+)
+
+type IDField struct {
+	ID string
+}
+
+type TimeFields struct {
+	CreatedTime     *time.Time
+	LastUpdatedTime time.Time
+}
+
+type GraduatedTimeTestStruct struct {
+	Field *string `sqlresult:"column:graduated_time;parseTime:2006-01-02 15:04:05"`
+}
+
+type Class struct {
+	IDField
+	Name          string `sqlresult:"aes:@MKU^AHYCN$:j76J<TAHCVD#$XZSWQ@L;"`
+	StudentNum    int    `sqlresult:"column:student_num_alias"`
+	GraduatedTime *time.Time
+	StudentIDs    []string `sqlresult:"column:student_ids;splitWith:'\n'"`
+	TimeFields
+	Ignored string `sqlresult:"-"`
+	*GraduatedTimeTestStruct
+}
+
+func main() {
+	err := tag.UseSqlResultTag(&Class{}, func(fieldName string, entityFieldElemValue reflect.Value, sqlResultTag *tag.SqlResultTag) error {
+		fmt.Println("Field Name:", fieldName)
+		fmt.Println("Type:", entityFieldElemValue.Type().String())
+		if entityFieldElemValue.Kind() == reflect.String {
+			fmt.Printf("\"%+v\"\n", entityFieldElemValue.Interface())
+		} else {
+			fmt.Printf("%+v\n", entityFieldElemValue.Interface())
+		}
+		fmt.Printf("%+v\n", sqlResultTag)
+		fmt.Println()
+
+		return nil
+	})
+	if err != nil {
+		panic(err)
+	}
+}

+ 67 - 77
tag/assign_struct.go → tag/assign.go

@@ -10,51 +10,41 @@ import (
 	"time"
 )
 
-type OnAssignParsedFieldTagFunc func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error
+type OnAssignParsedFieldTagFunc func(fromFieldName string, fromFieldElemValue reflect.Value, toFieldElementValue reflect.Value, assignTag *AssignTag) error
 
-func AssignTo(from any, to any) error {
-	return CustomAssignTo(from, to, func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error {
-		if fromFieldElemValue.IsZero() {
-			return nil
-		}
-
-		return assignField(fromFieldElemValue, retFieldElementValue, tag)
-	})
-}
-
-func CustomAssignTo(from any, to any, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
+func UseAssignTag(from any, to any, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
 	if from == nil || to == nil {
 		return nil
 	}
 
 	fromValue := reflect.ValueOf(from)
-	retValue := reflect.ValueOf(to)
+	toValue := reflect.ValueOf(to)
 
 	// 类型校验
 	if !reflectutils.IsValueStructOrStructPointer(fromValue) {
 		return fserr.New("参数不是结构或结构指针")
 	}
 
-	if !reflectutils.IsValueStructPointer(retValue) {
+	if !reflectutils.IsValueStructPointer(toValue) {
 		return fserr.New("返回类型不是结构指针")
 	}
 
 	fromElemValue := reflectutils.PointerValueElem(fromValue)
-	retElemValue := reflectutils.PointerValueElem(retValue)
+	toElemValue := reflectutils.PointerValueElem(toValue)
 
-	for i := 0; i < retElemValue.NumField(); i++ {
-		retField := retElemValue.Field(i)
-		if !retField.IsValid() {
+	for i := 0; i < toElemValue.NumField(); i++ {
+		toField := toElemValue.Field(i)
+		if !toField.IsValid() {
 			return fserr.New("被赋值的结构存在无效字段")
 		}
 
 		// 初始化空值指针
-		if retField.Kind() == reflect.Ptr && retField.IsNil() {
-			retField.Set(reflect.New(retField.Type().Elem()))
+		if toField.Kind() == reflect.Ptr && toField.IsNil() {
+			toField.Set(reflect.New(toField.Type().Elem()))
 		}
 	}
 
-	err := parseStructAssignTag(fromElemValue, &retElemValue, onParsedFieldTagFunc)
+	err := parseStructAssignTag(fromElemValue, &toElemValue, onParsedFieldTagFunc)
 	if err != nil {
 		return err
 	}
@@ -62,33 +52,33 @@ func CustomAssignTo(from any, to any, onParsedFieldTagFunc OnAssignParsedFieldTa
 	return nil
 }
 
-func assignField(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Value, tag *AssignTag) error {
+func DefaultOnAssignParsedFieldTagFunc(fromFieldElemValue reflect.Value, toFieldElemValue reflect.Value, assignTag *AssignTag) error {
 	fromKind := reflectutils.GroupValueKind(fromFieldElemValue)
-	retKind := reflectutils.GroupValueKind(retFieldElemValue)
+	toKind := reflectutils.GroupValueKind(toFieldElemValue)
 
 	var fromAny any
 	switch fromKind {
 	case reflect.Struct:
 		// time.Time类型的结构,接收字段是string类型,使用FormatTime的格式转换
-		if reflectutils.IsValueTime(fromFieldElemValue) && retKind == reflect.String {
-			fromString := fromFieldElemValue.Interface().(time.Time).Format(tag.FormatTime)
-			fromAny = assignTrimFromString(fromString, tag)
+		if reflectutils.IsValueTime(fromFieldElemValue) && toKind == reflect.String {
+			fromString := fromFieldElemValue.Interface().(time.Time).Format(assignTag.FormatTime)
+			fromAny = assignTrimFromString(fromString, assignTag)
 			break
 		}
 
 		// 不是time.Time类型的结构,接收字段是结构,执行结构到结构字段的赋值
-		if !reflectutils.IsValueTime(fromFieldElemValue) && retKind == reflect.Struct {
-			return parseStructAssignTag(fromFieldElemValue, &retFieldElemValue, func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error {
-				return assignField(fromFieldElemValue, retFieldElementValue, tag)
+		if !reflectutils.IsValueTime(fromFieldElemValue) && toKind == reflect.Struct {
+			return parseStructAssignTag(fromFieldElemValue, &toFieldElemValue, func(fromFieldName string, fromFieldElemValue reflect.Value, toFieldElementValue reflect.Value, tag *AssignTag) error {
+				return DefaultOnAssignParsedFieldTagFunc(fromFieldElemValue, toFieldElementValue, assignTag)
 			})
 		}
 
 		// 直接将整个结构进行字段赋值
 		fromAny = fromFieldElemValue.Interface()
 	case reflect.Slice:
-		if reflectutils.IsSliceValueOf(fromFieldElemValue, reflect.String) && retKind == reflect.String {
-			fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
-			fromAny = assignTrimFromString(fromString, tag)
+		if reflectutils.IsSliceValueOf(fromFieldElemValue, reflect.String) && toKind == reflect.String {
+			fromString := strings.Join(fromFieldElemValue.Interface().([]string), assignTag.JoinWith)
+			fromAny = assignTrimFromString(fromString, assignTag)
 			break
 		}
 
@@ -96,60 +86,60 @@ func assignField(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Val
 	case reflect.String:
 		fromString := fromFieldElemValue.String()
 
-		if reflectutils.IsValueTime(retFieldElemValue) {
-			retTimeField, err := time.ParseInLocation(tag.ParseTime, fromString, time.Local)
+		if reflectutils.IsValueTime(toFieldElemValue) {
+			toTimeField, err := time.ParseInLocation(assignTag.ParseTime, fromString, time.Local)
 			if err != nil {
 				return err
 			}
 
-			fromAny = retTimeField
+			fromAny = toTimeField
 			break
 		}
 
-		if reflectutils.IsSliceValueOf(retFieldElemValue, reflect.String) {
-			fromAny = strings.Split(fromString, tag.SplitWith)
+		if reflectutils.IsSliceValueOf(toFieldElemValue, reflect.String) {
+			fromAny = strings.Split(fromString, assignTag.SplitWith)
 			break
 		}
 
-		fromAny = assignTrimFromString(fromString, tag)
+		fromAny = assignTrimFromString(fromString, assignTag)
 	default:
 		fromAny = fromFieldElemValue.Interface()
 	}
 
-	switch retKind {
+	switch toKind {
 	case reflect.Int64:
-		return reflectutils.AssignInt64Value(fromAny, retFieldElemValue)
+		return reflectutils.AssignInt64Value(fromAny, toFieldElemValue)
 	case reflect.Uint64:
-		return reflectutils.AssignUint64Value(fromAny, retFieldElemValue)
+		return reflectutils.AssignUint64Value(fromAny, toFieldElemValue)
 	case reflect.Float64:
-		return reflectutils.AssignFloat64Value(fromAny, retFieldElemValue)
+		return reflectutils.AssignFloat64Value(fromAny, toFieldElemValue)
 	case reflect.Bool:
-		return reflectutils.AssignBoolValue(fromAny, retFieldElemValue)
+		return reflectutils.AssignBoolValue(fromAny, toFieldElemValue)
 	case reflect.String:
-		return reflectutils.AssignStringValue(fromAny, retFieldElemValue)
+		return reflectutils.AssignStringValue(fromAny, toFieldElemValue)
 	default:
-		retFieldElemValue.Set(reflect.ValueOf(fromAny))
+		toFieldElemValue.Set(reflect.ValueOf(fromAny))
 		return nil
 	}
 }
 
-func assignTrimFromString(fromString string, tag *AssignTag) string {
-	if strutils.IsStringNotEmpty(tag.Trim) {
-		return strings.Trim(fromString, tag.Trim)
+func assignTrimFromString(fromString string, assignTag *AssignTag) string {
+	if strutils.IsStringNotEmpty(assignTag.Trim) {
+		return strings.Trim(fromString, assignTag.Trim)
 	} else {
-		if strutils.IsStringNotEmpty(tag.TrimPrefix) {
-			return strings.TrimPrefix(fromString, tag.TrimPrefix)
+		if strutils.IsStringNotEmpty(assignTag.TrimPrefix) {
+			return strings.TrimPrefix(fromString, assignTag.TrimPrefix)
 		}
 
-		if strutils.IsStringNotEmpty(tag.TrimSuffix) {
-			return strings.TrimSuffix(fromString, tag.TrimSuffix)
+		if strutils.IsStringNotEmpty(assignTag.TrimSuffix) {
+			return strings.TrimSuffix(fromString, assignTag.TrimSuffix)
 		}
 	}
 
 	return fromString
 }
 
-func parseStructAssignTag(fromElemValue reflect.Value, retElemValue *reflect.Value, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
+func parseStructAssignTag(fromElemValue reflect.Value, toElemValue *reflect.Value, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
 	for i := 0; i < fromElemValue.NumField(); i++ {
 		fromField := fromElemValue.Type().Field(i)
 		fromFieldValue := fromElemValue.Field(i)
@@ -170,7 +160,7 @@ func parseStructAssignTag(fromElemValue reflect.Value, retElemValue *reflect.Val
 		// 结构类型的字段上没有添加Tag, 先尝试直接按照字段赋值
 		if strutils.IsStringEmpty(tagStr) && fromFieldElemValue.Kind() == reflect.Struct &&
 			!reflectutils.IsValueTime(fromFieldElemValue) {
-			err := parseStructAssignTag(fromFieldElemValue, retElemValue, onParsedFieldTagFunc)
+			err := parseStructAssignTag(fromFieldElemValue, toElemValue, onParsedFieldTagFunc)
 			if err != nil {
 				return err
 			}
@@ -178,41 +168,41 @@ func parseStructAssignTag(fromElemValue reflect.Value, retElemValue *reflect.Val
 			continue
 		}
 
-		tag, err := parseAssignTag(fromField, tagStr)
+		assignTag, err := parseAssignTag(fromField, tagStr)
 		if err != nil {
 			return err
 		}
 
-		if tag == nil {
+		if assignTag == nil {
 			continue
 		}
 
-		retFieldValue := retElemValue.FieldByName(tag.ToField)
+		toFieldValue := toElemValue.FieldByName(assignTag.ToField)
 
 		// 不存在对应的字段
-		if !retFieldValue.IsValid() {
+		if !toFieldValue.IsValid() {
 			continue
 		}
 
-		retFieldElemValue := retFieldValue
-		if retFieldValue.Kind() == reflect.Pointer {
-			if !retFieldValue.IsValid() {
+		toFieldElemValue := toFieldValue
+		if toFieldValue.Kind() == reflect.Pointer {
+			if !toFieldValue.IsValid() {
 				continue
 			}
 
-			if !retFieldValue.CanSet() {
+			if !toFieldValue.CanSet() {
 				continue
 			}
 
 			// 空值针,初始化
-			if retFieldValue.IsNil() {
-				retFieldValue.Set(reflect.New(retFieldValue.Type().Elem()))
+			if toFieldValue.IsNil() {
+				toFieldValue.Set(reflect.New(toFieldValue.Type().Elem()))
 			}
 
-			retFieldElemValue = retFieldValue.Elem()
+			toFieldElemValue = toFieldValue.Elem()
 		}
 
-		err = onParsedFieldTagFunc(fromField.Name, fromFieldElemValue, retFieldElemValue, tag)
+		err = onParsedFieldTagFunc(fromField.Name, fromFieldElemValue, toFieldElemValue, assignTag)
 		if err != nil {
 			return err
 		}
@@ -256,7 +246,7 @@ func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error
 		return nil, nil
 	}
 
-	tag := &AssignTag{
+	assignTag := &AssignTag{
 		ToField:    field.Name,
 		ParseTime:  time.DateTime,
 		FormatTime: time.DateTime,
@@ -268,7 +258,7 @@ func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error
 	}
 
 	if strutils.IsStringEmpty(tagStr) {
-		return tag, nil
+		return assignTag, nil
 	}
 
 	assignParts := strings.Split(tagStr, assignTagPartSeparator)
@@ -281,29 +271,29 @@ func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error
 
 			switch assignPartKeyValue[0] {
 			case assignToField:
-				tag.ToField = assignPartKeyValue[1]
+				assignTag.ToField = assignPartKeyValue[1]
 			case assignParseTime:
-				tag.ParseTime = assignPartKeyValue[1]
+				assignTag.ParseTime = assignPartKeyValue[1]
 			case assignFormatTime:
-				tag.FormatTime = assignPartKeyValue[1]
+				assignTag.FormatTime = assignPartKeyValue[1]
 			case assignJoinWith:
 				if strutils.IsStringEmpty(assignPartKeyValue[1]) {
 					return nil, fserr.New(assignJoinWith + "没有赋值分隔符")
 				}
 
-				tag.JoinWith = assignPartKeyValue[1]
+				assignTag.JoinWith = assignPartKeyValue[1]
 			case assignSplitWith:
 				if strutils.IsStringEmpty(assignPartKeyValue[1]) {
 					return nil, fserr.New(assignSplitWith + "没有赋值分隔符")
 				}
 
-				tag.SplitWith = assignPartKeyValue[1]
+				assignTag.SplitWith = assignPartKeyValue[1]
 			case assignTrim:
-				tag.Trim = assignPartKeyValue[1]
+				assignTag.Trim = assignPartKeyValue[1]
 			case assignTrimPrefix:
-				tag.TrimPrefix = assignPartKeyValue[1]
+				assignTag.TrimPrefix = assignPartKeyValue[1]
 			case assignTrimSuffix:
-				tag.TrimSuffix = assignPartKeyValue[1]
+				assignTag.TrimSuffix = assignPartKeyValue[1]
 			default:
 				err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0])
 				logger.GetInstance().Error(err)
@@ -312,5 +302,5 @@ func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error
 		}
 	}
 
-	return tag, nil
+	return assignTag, nil
 }

+ 25 - 25
tag/sql_mapping.go

@@ -10,9 +10,9 @@ import (
 	"strings"
 )
 
-type OnSqlMappingParsedFieldTagFunc func(fieldName string, entityFieldElemValue reflect.Value, tag *SqlMappingTag) error
+type OnSqlMappingParsedFieldTagFunc func(fieldName string, entityFieldElemValue reflect.Value, sqlMapping *SqlMappingTag) error
 
-func BuildExecuteParams(e any, onParsedFieldTagFunc OnSqlMappingParsedFieldTagFunc) error {
+func UseSqlMappingTag(e any, onParsedFieldTagFunc OnSqlMappingParsedFieldTagFunc) error {
 	if e == nil {
 		return nil
 	}
@@ -39,7 +39,7 @@ func parseEntitySqlMappingTag(entityElemValue reflect.Value, onParsedFieldTagFun
 		entityField := entityElemValue.Type().Field(i)
 		entityFieldValue := entityElemValue.Field(i)
 
-		// 无效值,不进行映射
+		// 无效值,不进行映射
 		if !entityFieldValue.IsValid() {
 			continue
 		}
@@ -52,12 +52,12 @@ func parseEntitySqlMappingTag(entityElemValue reflect.Value, onParsedFieldTagFun
 
 		tagStr := entityField.Tag.Get(sqlMappingTagKey)
 
-		tag, err := parseSqlMappingTag(entityField, tagStr)
+		sqlMapping, err := parseSqlMappingTag(entityField, tagStr)
 		if err != nil {
 			return err
 		}
 
-		if tag == nil {
+		if sqlMapping == nil {
 			continue
 		}
 
@@ -72,7 +72,7 @@ func parseEntitySqlMappingTag(entityElemValue reflect.Value, onParsedFieldTagFun
 			continue
 		}
 
-		err = onParsedFieldTagFunc(entityField.Name, entityFieldElemValue, tag)
+		err = onParsedFieldTagFunc(entityField.Name, entityFieldElemValue, sqlMapping)
 		if err != nil {
 			return err
 		}
@@ -119,7 +119,7 @@ func parseSqlMappingTag(field reflect.StructField, tagStr string) (*SqlMappingTa
 		return nil, nil
 	}
 
-	sqlColumn := &SqlMappingTag{
+	sqlMappingTag := &SqlMappingTag{
 		Name:           strcase.ToSnake(field.Name),
 		IsKey:          false,
 		CanUpdate:      true,
@@ -131,13 +131,13 @@ func parseSqlMappingTag(field reflect.StructField, tagStr string) (*SqlMappingTa
 		TrimSuffix:     "",
 	}
 
-	if sqlColumn.Name == sqlMappingDefaultKeyColumnName {
-		sqlColumn.IsKey = true
-		sqlColumn.CanUpdate = false
+	if sqlMappingTag.Name == sqlMappingDefaultKeyColumnName {
+		sqlMappingTag.IsKey = true
+		sqlMappingTag.CanUpdate = false
 	}
 
 	if strutils.IsStringEmpty(tagStr) {
-		return sqlColumn, nil
+		return sqlMappingTag, nil
 	}
 
 	sqlMappingParts := strings.Split(tagStr, sqlMappingTagPartSeparator)
@@ -154,42 +154,42 @@ func parseSqlMappingTag(field reflect.StructField, tagStr string) (*SqlMappingTa
 					return nil, errors.New("column没有赋值列名")
 				}
 
-				sqlColumn.Name = sqlMappingPartKeyValue[1]
+				sqlMappingTag.Name = sqlMappingPartKeyValue[1]
 			case sqlMappingKey:
-				sqlColumn.IsKey = true
-				sqlColumn.CanUpdate = false
+				sqlMappingTag.IsKey = true
+				sqlMappingTag.CanUpdate = false
 			case sqlMappingNotUpdate:
-				sqlColumn.CanUpdate = false
-				sqlColumn.CanUpdateClear = false
+				sqlMappingTag.CanUpdate = false
+				sqlMappingTag.CanUpdateClear = false
 			case sqlMappingUpdateClear:
-				if !sqlColumn.CanUpdate {
-					sqlColumn.CanUpdateClear = false
+				if !sqlMappingTag.CanUpdate {
+					sqlMappingTag.CanUpdateClear = false
 				} else {
-					sqlColumn.CanUpdateClear = true
+					sqlMappingTag.CanUpdateClear = true
 				}
 			case sqlMappingAes:
 				if len(sqlMappingPartKeyValue[1]) != 32 {
 					return nil, errors.New("AES密钥长度应该为32个字节")
 				}
 
-				sqlColumn.AESKey = sqlMappingPartKeyValue[1]
+				sqlMappingTag.AESKey = sqlMappingPartKeyValue[1]
 			case sqlMappingJoinWith:
 				if strutils.IsStringEmpty(sqlMappingPartKeyValue[1]) {
 					return nil, errors.New(sqlMappingJoinWith + "没有赋值分隔符")
 				}
 
-				sqlColumn.JoinWith = sqlMappingPartKeyValue[1]
+				sqlMappingTag.JoinWith = sqlMappingPartKeyValue[1]
 			case sqlMappingTrim:
-				sqlColumn.Trim = sqlMappingPartKeyValue[1]
+				sqlMappingTag.Trim = sqlMappingPartKeyValue[1]
 			case sqlMappingTrimPrefix:
-				sqlColumn.TrimPrefix = sqlMappingPartKeyValue[1]
+				sqlMappingTag.TrimPrefix = sqlMappingPartKeyValue[1]
 			case sqlMappingTrimSuffix:
-				sqlColumn.TrimSuffix = sqlMappingPartKeyValue[1]
+				sqlMappingTag.TrimSuffix = sqlMappingPartKeyValue[1]
 			default:
 				continue
 			}
 		}
 	}
 
-	return sqlColumn, nil
+	return sqlMappingTag, nil
 }

+ 154 - 0
tag/sql_result.go

@@ -0,0 +1,154 @@
+package tag
+
+import (
+	"errors"
+	"git.sxidc.com/go-tools/utils/reflectutils"
+	"git.sxidc.com/go-tools/utils/strutils"
+	"git.sxidc.com/service-supports/fserr"
+	"github.com/iancoleman/strcase"
+	"reflect"
+	"strings"
+)
+
+type OnSqlResultParsedFieldTagFunc func(fieldName string, entityFieldElemValue reflect.Value, sqlResult *SqlResultTag) error
+
+func UseSqlResultTag(e any, onParsedFieldTagFunc OnSqlResultParsedFieldTagFunc) error {
+	if e == nil {
+		return nil
+	}
+
+	entityValue := reflect.ValueOf(e)
+
+	// 类型校验
+	if !reflectutils.IsValueStructPointer(entityValue) {
+		return fserr.New("参数不是结构指针")
+	}
+
+	entityElemValue := reflectutils.PointerValueElem(entityValue)
+
+	err := parseEntitySqlResultTag(entityElemValue, onParsedFieldTagFunc)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func parseEntitySqlResultTag(entityElemValue reflect.Value, onParsedFieldTagFunc OnSqlResultParsedFieldTagFunc) error {
+	for i := 0; i < entityElemValue.NumField(); i++ {
+		entityField := entityElemValue.Type().Field(i)
+		entityFieldValue := entityElemValue.Field(i)
+
+		// 无效值,不进行映射
+		if !entityFieldValue.IsValid() {
+			continue
+		}
+
+		if entityFieldValue.Kind() == reflect.Pointer && entityFieldValue.IsNil() {
+			entityFieldValue.Set(reflect.New(entityField.Type.Elem()))
+		}
+
+		entityFieldElemValue := reflectutils.PointerValueElem(entityFieldValue)
+
+		tagStr := entityField.Tag.Get(sqlResultTagKey)
+
+		tag, err := parseSqlResultTag(entityField, tagStr)
+		if err != nil {
+			return err
+		}
+
+		if tag == nil {
+			continue
+		}
+
+		// 结构类型的字段,解析结构内部
+		if entityFieldElemValue.Kind() == reflect.Struct &&
+			!reflectutils.IsValueTime(entityFieldElemValue) {
+			err := parseEntitySqlResultTag(entityFieldElemValue, onParsedFieldTagFunc)
+			if err != nil {
+				return err
+			}
+
+			continue
+		}
+
+		err = onParsedFieldTagFunc(entityField.Name, entityFieldElemValue, tag)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+const (
+	sqlResultDefaultSplitWith         = "::"
+	sqlResultTagPartSeparator         = ";"
+	sqlResultTagPartKeyValueSeparator = ":"
+)
+
+const (
+	sqlResultTagKey    = "sqlresult"
+	sqlResultIgnore    = "-"
+	sqlResultColumn    = "column"
+	sqlResultParseTime = "parseTime"
+	sqlResultAes       = "aes"
+	sqlResultSplitWith = "splitWith"
+)
+
+type SqlResultTag struct {
+	Name      string
+	ParseTime string
+	AESKey    string
+	SplitWith string
+}
+
+func parseSqlResultTag(field reflect.StructField, tagStr string) (*SqlResultTag, error) {
+	if tagStr == sqlResultIgnore {
+		return nil, nil
+	}
+
+	sqlResultTag := &SqlResultTag{
+		Name:      strcase.ToSnake(field.Name),
+		ParseTime: "",
+		AESKey:    "",
+		SplitWith: sqlResultDefaultSplitWith,
+	}
+
+	if strutils.IsStringEmpty(tagStr) {
+		return sqlResultTag, nil
+	}
+
+	sqlResultParts := strings.Split(tagStr, sqlResultTagPartSeparator)
+	if sqlResultParts != nil || len(sqlResultParts) != 0 {
+		for _, sqlResultPart := range sqlResultParts {
+			sqlPartKeyValue := strings.SplitN(strings.TrimSpace(sqlResultPart), sqlResultTagPartKeyValueSeparator, 2)
+			if sqlPartKeyValue != nil && len(sqlPartKeyValue) == 2 && strutils.IsStringNotEmpty(sqlPartKeyValue[1]) {
+				sqlPartKeyValue[1] = strings.Trim(sqlPartKeyValue[1], "'")
+			}
+
+			switch sqlPartKeyValue[0] {
+			case sqlResultColumn:
+				sqlResultTag.Name = sqlPartKeyValue[1]
+			case sqlResultParseTime:
+				sqlResultTag.ParseTime = sqlPartKeyValue[1]
+			case sqlResultAes:
+				if len(sqlPartKeyValue[1]) != 32 {
+					return nil, errors.New("AES密钥长度应该为32个字节")
+				}
+
+				sqlResultTag.AESKey = sqlPartKeyValue[1]
+			case sqlResultSplitWith:
+				if strutils.IsStringEmpty(sqlPartKeyValue[1]) {
+					return nil, errors.New(sqlResultDefaultSplitWith + "没有赋值分隔符")
+				}
+
+				sqlResultTag.SplitWith = sqlPartKeyValue[1]
+			default:
+				continue
+			}
+		}
+	}
+
+	return sqlResultTag, nil
+}