0x4a52466c696e74 2 ヶ月 前
コミット
8c4e93fa34
4 ファイル変更94 行追加19 行削除
  1. 43 0
      field_converter.go
  2. 17 10
      fielder.go
  3. 22 1
      serialize.go
  4. 12 8
      z_test.go

+ 43 - 0
field_converter.go

@@ -0,0 +1,43 @@
+package rest
+
+import (
+	"fmt"
+	"time"
+)
+
+var (
+	fieldConverters = make(map[string]*FieldConverter)
+)
+
+type FieldConverter struct {
+	Pack   func(any) any
+	Unpack func(any) (any, error)
+}
+
+func RegisterFieldConverter(name string, converter *FieldConverter) {
+	fieldConverters[name] = converter
+}
+
+func init() {
+	RegisterFieldConverter(
+		"time.Time",
+		&FieldConverter{
+			Pack: func(v any) any {
+				t := v.(time.Time)
+				return t.Format("02.01.2006 15:04")
+			},
+			Unpack: func(val any) (any, error) {
+				ts, check := val.(string)
+				if !check {
+					return nil, fmt.Errorf("expected string")
+				}
+				layout := "02.01.2006 15:04"
+				parsedTime, err := time.Parse(layout, ts)
+				if err != nil {
+					return nil, err
+				}
+				return parsedTime, nil
+			},
+		},
+	)
+}

+ 17 - 10
fielder.go

@@ -169,6 +169,11 @@ func parseName(val reflect.Value) (res *Field, err error) {
 	return
 }
 
+func StructTypeName(val reflect.Value) string {
+	t := val.Type()
+	return t.PkgPath() + "." + t.Name()
+}
+
 func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names FieldList) (res reflect.Value, err IErrorArgs) {
 	switch val.Kind() {
 	case reflect.Ptr, reflect.Interface:
@@ -193,6 +198,11 @@ func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names Fie
 				return reflect.ValueOf(rVal), nil
 			}
 		}
+		// check public fields exists
+		if val.NumField() == 0 {
+			res = reflect.ValueOf(fmt.Sprint(val.Interface()))
+			return
+		}
 		// parse struct public fields
 		if len(names) == 0 {
 			names = fieldsDefault(val.Type())
@@ -225,7 +235,13 @@ func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names Fie
 				return false
 			}
 			if fVal.IsValid() {
-				jm[name.Name] = fVal.Interface()
+				stn := StructTypeName(field)
+				con, check := fieldConverters[stn]
+				if check {
+					jm[name.Name] = con.Pack(field.Interface())
+				} else {
+					jm[name.Name] = fVal.Interface()
+				}
 			} else {
 				jm[name.Name] = nil
 			}
@@ -360,12 +376,3 @@ func OutFields(req IRequestIn, obj any, files RequestFiles, names FieldList) IRe
 	}
 	return req.OutSuccess(m, files)
 }
-
-/*
-func OutFieldsReq(req IRequestIn, obj any, files RequestFiles, names FieldList) IRequestOut {
-	if len(names) == 0 {
-		names = req.Fields()
-	}
-	return OutFields(req, obj, files, names)
-}
-*/

+ 22 - 1
serialize.go

@@ -35,6 +35,22 @@ func parseVal(from, to reflect.Value, fieldName string) IErrorArgs {
 func parseType(from, to reflect.Value, fieldName string) IErrorArgs {
 	from = realValue(from)
 	to = realValue(to)
+	tn := StructTypeName(to)
+	cv, check := fieldConverters[tn]
+	if check {
+		val, err := cv.Unpack(from.Interface())
+		if err != nil {
+			return NewError(
+				"FieldValue",
+				json.Map{
+					"field": fieldName,
+					"error": err.Error(),
+				},
+			)
+		}
+		to.Set(reflect.ValueOf(val))
+		return nil
+	}
 	switch to.Kind() {
 	case reflect.Interface:
 		if from.Kind() != reflect.Invalid {
@@ -165,7 +181,12 @@ loop:
 		if rVal.Kind() == reflect.Interface {
 			rVal = rVal.Elem()
 		}
-		iFieldName := fmt.Sprintf("%v.%v", fieldName, fType.Name)
+		var iFieldName string
+		if fieldName == "" {
+			iFieldName = fType.Name
+		} else {
+			iFieldName = fmt.Sprintf("%v.%v", fieldName, fType.Name)
+		}
 		if err := parseType(rVal, fVal.Addr(), iFieldName); err != nil {
 			return err
 		}

+ 12 - 8
z_test.go

@@ -269,8 +269,9 @@ func TestTime(t *testing.T) {
 }
 
 type LObj struct {
-	ID   int64  `rest:"default"`
-	Name string `rest:"default"`
+	ID      int64     `rest:"default"`
+	Name    string    `rest:"default"`
+	Created time.Time `rest:"default"`
 }
 
 type LList struct {
@@ -296,8 +297,9 @@ func TestFielderList(t *testing.T) {
 	obj := &LList{
 		Result: []*LObj{
 			{
-				ID:   1,
-				Name: "Val 1",
+				ID:      1,
+				Name:    "Val 1",
+				Created: time.Now(),
 			},
 			{
 				ID:   2,
@@ -394,8 +396,9 @@ func TestFieldNames(t *testing.T) {
 }
 
 type User struct {
-	ID   int
-	Name string
+	ID      int
+	Name    string
+	Created time.Time
 }
 
 type AuthEmail struct {
@@ -430,8 +433,9 @@ func TestSerializeEmail(t *testing.T) {
 		"email":     "flint@77i.su",
 		"themeName": "th-name",
 		"UUser": json.Map{
-			"ID":   100,
-			"Name": "User 100",
+			"ID":      100,
+			"Name":    "User 100",
+			"Created": "10.11.1983 03:12K",
 		},
 	}