Finish Serializer

This commit is contained in:
Jinzhu 2022-02-15 21:29:29 +08:00
parent 5f6d85c00a
commit a1dc940af3
3 changed files with 48 additions and 11 deletions

View File

@ -432,7 +432,7 @@ func (field *Field) setupValuerAndSetter() {
New: func() interface{} { New: func() interface{} {
return &Serializer{ return &Serializer{
Field: field, Field: field,
Interface: reflect.New(reflect.ValueOf(field.Serializer).Type()).Interface().(SerializerInterface), Interface: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
} }
}, },
} }
@ -489,14 +489,14 @@ func (field *Field) setupValuerAndSetter() {
return value, zero return value, zero
} }
serializer, ok := value.(SerializerInterface) serializer, ok := value.(SerializerValuerInterface)
if !ok { if !ok {
serializer = field.Serializer serializer = field.Serializer
} }
return Serializer{ return Serializer{
Field: field, Field: field,
Interface: serializer, Valuer: serializer,
Destination: v, Destination: v,
Context: ctx, Context: ctx,
fieldValue: value, fieldValue: value,
@ -564,6 +564,9 @@ func (field *Field) setupValuerAndSetter() {
if reflectV.Kind() == reflect.Ptr { if reflectV.Kind() == reflect.Ptr {
if reflectV.IsNil() { if reflectV.IsNil() {
field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem()) field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
} else if reflectV.Type().Elem().AssignableTo(field.FieldType) {
field.ReflectValueOf(ctx, value).Set(reflectV.Elem())
return
} else { } else {
err = setter(ctx, value, reflectV.Elem().Interface()) err = setter(ctx, value, reflectV.Elem().Interface())
} }
@ -585,7 +588,7 @@ func (field *Field) setupValuerAndSetter() {
if serializer, ok := v.(*Serializer); ok { if serializer, ok := v.(*Serializer); ok {
serializer.Interface.Scan(ctx, field, value, serializer.value) serializer.Interface.Scan(ctx, field, value, serializer.value)
fallbackSetter(ctx, value, serializer.Interface, field.Set) fallbackSetter(ctx, value, serializer.Interface, field.Set)
serializer.Interface = reflect.New(reflect.ValueOf(field.Serializer).Type()).Interface().(SerializerInterface) serializer.Interface = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
} }
return nil return nil
} }

View File

@ -26,6 +26,7 @@ type FieldNewValuePool interface {
type Serializer struct { type Serializer struct {
Field *Field Field *Field
Interface SerializerInterface Interface SerializerInterface
Valuer SerializerValuerInterface
Destination reflect.Value Destination reflect.Value
Context context.Context Context context.Context
value interface{} value interface{}
@ -40,12 +41,17 @@ func (s *Serializer) Scan(value interface{}) error {
// Value implements driver.Valuer interface // Value implements driver.Valuer interface
func (s Serializer) Value() (driver.Value, error) { func (s Serializer) Value() (driver.Value, error) {
return s.Interface.Value(s.Context, s.Field, s.Destination, s.fieldValue) return s.Valuer.Value(s.Context, s.Field, s.Destination, s.fieldValue)
} }
// SerializerInterface serializer interface // SerializerInterface serializer interface
type SerializerInterface interface { type SerializerInterface interface {
Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
SerializerValuerInterface
}
// SerializerValuerInterface serializer valuer interface
type SerializerValuerInterface interface {
Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
} }

View File

@ -1,29 +1,55 @@
package tests_test package tests_test
import ( import (
"bytes"
"context"
"fmt"
"reflect"
"strings"
"testing" "testing"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/schema"
. "gorm.io/gorm/utils/tests" . "gorm.io/gorm/utils/tests"
) )
type SerializerStruct struct { type SerializerStruct struct {
gorm.Model gorm.Model
Name []byte `gorm:"json"` Name []byte `gorm:"json"`
Roles Roles `gorm:"json"` Roles Roles `gorm:"json"`
EncryptedString EncryptedString
} }
type Roles []string type Roles []string
type EncryptedString string
func TestSerializerJSON(t *testing.T) { func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
switch value := dbValue.(type) {
case []byte:
*es = EncryptedString(bytes.TrimPrefix(value, []byte("hello")))
case string:
*es = EncryptedString(strings.TrimPrefix(value, "hello"))
default:
return fmt.Errorf("unsupported data %v", dbValue)
}
return nil
}
// Value implements serializer interface
func (es EncryptedString) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
return "hello" + string(es), nil
}
func TestSerializer(t *testing.T) {
DB.Migrator().DropTable(&SerializerStruct{}) DB.Migrator().DropTable(&SerializerStruct{})
if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil { if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil {
t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err) t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err)
} }
data := SerializerStruct{ data := SerializerStruct{
Name: []byte("jinzhu"), Name: []byte("jinzhu"),
Roles: []string{"r1", "r2"}, Roles: []string{"r1", "r2"},
EncryptedString: EncryptedString("pass"),
} }
if err := DB.Create(&data).Error; err != nil { if err := DB.Create(&data).Error; err != nil {
@ -31,7 +57,9 @@ func TestSerializerJSON(t *testing.T) {
} }
var result SerializerStruct var result SerializerStruct
DB.First(&result, data.ID) if err := DB.First(&result, data.ID).Error; err != nil {
t.Fatalf("failed to query data, got error %v", err)
}
AssertEqual(t, result, data) AssertEqual(t, result, data)
} }