Ver código fonte

feat: support uuid.UUID in mapping (#2537)

Kevin Wan 2 anos atrás
pai
commit
f9beab1095
2 arquivos alterados com 54 adições e 2 exclusões
  1. 31 0
      core/mapping/unmarshaler.go
  2. 23 2
      core/mapping/unmarshaler_test.go

+ 31 - 0
core/mapping/unmarshaler.go

@@ -1,6 +1,7 @@
 package mapping
 
 import (
+	"encoding"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -318,6 +319,28 @@ func (u *Unmarshaler) processFieldStructWithMap(field reflect.StructField, value
 	return nil
 }
 
+func (u *Unmarshaler) processFieldTextUnmarshaler(field reflect.StructField, value reflect.Value,
+	mapValue interface{}) (bool, error) {
+	var tval encoding.TextUnmarshaler
+	var ok bool
+
+	if field.Type.Kind() == reflect.Ptr {
+		tval, ok = value.Interface().(encoding.TextUnmarshaler)
+	} else {
+		tval, ok = value.Addr().Interface().(encoding.TextUnmarshaler)
+	}
+	if ok {
+		switch mv := mapValue.(type) {
+		case string:
+			return true, tval.UnmarshalText([]byte(mv))
+		case []byte:
+			return true, tval.UnmarshalText(mv)
+		}
+	}
+
+	return false, nil
+}
+
 func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect.Value,
 	m Valuer, fullName string) error {
 	key, opts, err := u.parseOptionsWithContext(field, m, fullName)
@@ -348,8 +371,16 @@ func (u *Unmarshaler) processNamedFieldWithValue(field reflect.StructField, valu
 		return fmt.Errorf("field %s mustn't be nil", key)
 	}
 
+	if !value.CanSet() {
+		return fmt.Errorf("field %s is not settable", key)
+	}
+
 	maybeNewValue(field, value)
 
+	if yes, err := u.processFieldTextUnmarshaler(field, value, mapValue); yes {
+		return err
+	}
+
 	fieldKind := Deref(field.Type).Kind()
 	switch fieldKind {
 	case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:

+ 23 - 2
core/mapping/unmarshaler_test.go

@@ -8,6 +8,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/google/uuid"
 	"github.com/stretchr/testify/assert"
 	"github.com/zeromicro/go-zero/core/stringx"
 )
@@ -537,10 +538,12 @@ func TestUnmarshalStringMapFromUnsupportedType(t *testing.T) {
 
 func TestUnmarshalStringMapFromNotSettableValue(t *testing.T) {
 	var v struct {
-		sort map[string]string `key:"sort"`
+		sort  map[string]string  `key:"sort"`
+		psort *map[string]string `key:"sort"`
 	}
 	m := map[string]interface{}{
-		"sort": `{"value":"ascend","emptyStr":""}`,
+		"sort":  `{"value":"ascend","emptyStr":""}`,
+		"psort": `{"value":"ascend","emptyStr":""}`,
 	}
 
 	ast := assert.New(t)
@@ -3018,6 +3021,24 @@ func TestUnmarshalJsonReaderArrayString(t *testing.T) {
 	assert.NotNil(t, err)
 }
 
+func TestGoogleUUID(t *testing.T) {
+	var val struct {
+		Uid  uuid.UUID  `json:"uid,optional"`
+		Uidp *uuid.UUID `json:"uidp,optional"`
+	}
+	assert.NoError(t, UnmarshalJsonBytes([]byte(`{
+	"uid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
+	"uidp": "6ba7b810-9dad-11d1-80b4-00c04fd430c9"}`), &val))
+	assert.Equal(t, "6ba7b810-9dad-11d1-80b4-00c04fd430c8", val.Uid.String())
+	assert.Equal(t, "6ba7b810-9dad-11d1-80b4-00c04fd430c9", val.Uidp.String())
+	assert.NoError(t, UnmarshalJsonMap(map[string]interface{}{
+		"uid":  []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c1"),
+		"uidp": []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c2"),
+	}, &val))
+	assert.Equal(t, "6ba7b810-9dad-11d1-80b4-00c04fd430c1", val.Uid.String())
+	assert.Equal(t, "6ba7b810-9dad-11d1-80b4-00c04fd430c2", val.Uidp.String())
+}
+
 func BenchmarkDefaultValue(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var a struct {