mirror of https://github.com/go-gorm/gorm.git
fix: serializer use default valueOf in assignInterfacesToValue, close #5168
commit 58e1b2bffbc216f2862d040fb545a8a486e473b6
Author: Jinzhu <wosmvp@gmail.com>
Date: Fri Mar 18 17:06:43 2022 +0800
Refactor #5168
commit fb9233011d
Author: ag9920 <alexgong7@outlook.com>
Date: Thu Mar 17 21:23:28 2022 +0800
fix: serializer use default valueOf in assignInterfacesToValue
This commit is contained in:
parent
e6f7da0e0d
commit
3c00980e01
|
@ -435,39 +435,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
// create valuer, setter when parse struct
|
||||
func (field *Field) setupValuerAndSetter() {
|
||||
// Setup NewValuePool
|
||||
var fieldValue = reflect.New(field.FieldType).Interface()
|
||||
if field.Serializer != nil {
|
||||
field.NewValuePool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &serializer{
|
||||
Field: field,
|
||||
Serializer: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if _, ok := fieldValue.(sql.Scanner); !ok {
|
||||
// set default NewValuePool
|
||||
switch field.IndirectFieldType.Kind() {
|
||||
case reflect.String:
|
||||
field.NewValuePool = stringPool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
field.NewValuePool = intPool
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
field.NewValuePool = uintPool
|
||||
case reflect.Float32, reflect.Float64:
|
||||
field.NewValuePool = floatPool
|
||||
case reflect.Bool:
|
||||
field.NewValuePool = boolPool
|
||||
default:
|
||||
if field.IndirectFieldType == TimeReflectType {
|
||||
field.NewValuePool = timePool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if field.NewValuePool == nil {
|
||||
field.NewValuePool = poolInitializer(reflect.PtrTo(field.IndirectFieldType))
|
||||
}
|
||||
field.setupNewValuePool()
|
||||
|
||||
// ValueOf returns field's value and if it is zero
|
||||
fieldIndex := field.StructField.Index[0]
|
||||
|
@ -512,7 +480,7 @@ func (field *Field) setupValuerAndSetter() {
|
|||
s = field.Serializer
|
||||
}
|
||||
|
||||
return serializer{
|
||||
return &serializer{
|
||||
Field: field,
|
||||
SerializeValuer: s,
|
||||
Destination: v,
|
||||
|
@ -943,7 +911,9 @@ func (field *Field) setupValuerAndSetter() {
|
|||
|
||||
field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
|
||||
if s, ok := v.(*serializer); ok {
|
||||
if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil {
|
||||
if s.fieldValue != nil {
|
||||
err = oldFieldSetter(ctx, value, s.fieldValue)
|
||||
} else if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil {
|
||||
if sameElemType {
|
||||
field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem())
|
||||
s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
|
||||
|
@ -959,3 +929,43 @@ func (field *Field) setupValuerAndSetter() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (field *Field) setupNewValuePool() {
|
||||
var fieldValue = reflect.New(field.FieldType).Interface()
|
||||
if field.Serializer != nil {
|
||||
field.NewValuePool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &serializer{
|
||||
Field: field,
|
||||
Serializer: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if _, ok := fieldValue.(sql.Scanner); !ok {
|
||||
field.setupDefaultNewValuePool()
|
||||
}
|
||||
|
||||
if field.NewValuePool == nil {
|
||||
field.NewValuePool = poolInitializer(reflect.PtrTo(field.IndirectFieldType))
|
||||
}
|
||||
}
|
||||
|
||||
func (field *Field) setupDefaultNewValuePool() {
|
||||
// set default NewValuePool
|
||||
switch field.IndirectFieldType.Kind() {
|
||||
case reflect.String:
|
||||
field.NewValuePool = stringPool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
field.NewValuePool = intPool
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
field.NewValuePool = uintPool
|
||||
case reflect.Float32, reflect.Float64:
|
||||
field.NewValuePool = floatPool
|
||||
case reflect.Bool:
|
||||
field.NewValuePool = boolPool
|
||||
default:
|
||||
if field.IndirectFieldType == TimeReflectType {
|
||||
field.NewValuePool = timePool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,8 +202,6 @@ func TestJoinCount(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestJoinWithSoftDeleted(t *testing.T) {
|
||||
DB = DB.Debug()
|
||||
|
||||
user := GetUser("TestJoinWithSoftDeletedUser", Config{Account: true, NamedPet: true})
|
||||
DB.Create(&user)
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst re
|
|||
case string:
|
||||
*es = EncryptedString(strings.TrimPrefix(value, "hello"))
|
||||
default:
|
||||
return fmt.Errorf("unsupported data %v", dbValue)
|
||||
return fmt.Errorf("unsupported data %#v", dbValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -83,4 +83,53 @@ func TestSerializer(t *testing.T) {
|
|||
}
|
||||
|
||||
AssertEqual(t, result, data)
|
||||
|
||||
}
|
||||
|
||||
func TestSerializerAssignFirstOrCreate(t *testing.T) {
|
||||
DB.Migrator().DropTable(&SerializerStruct{})
|
||||
if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil {
|
||||
t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err)
|
||||
}
|
||||
|
||||
createdAt := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
data := SerializerStruct{
|
||||
Name: []byte("ag9920"),
|
||||
Roles: []string{"r1", "r2"},
|
||||
Contracts: map[string]interface{}{"name": "jing1", "age": 11},
|
||||
EncryptedString: EncryptedString("pass"),
|
||||
CreatedTime: createdAt.Unix(),
|
||||
JobInfo: Job{
|
||||
Title: "programmer",
|
||||
Number: 9920,
|
||||
Location: "Shadyside",
|
||||
IsIntern: false,
|
||||
},
|
||||
}
|
||||
|
||||
// first time insert record
|
||||
out := SerializerStruct{}
|
||||
if err := DB.Assign(data).FirstOrCreate(&out).Error; err != nil {
|
||||
t.Fatalf("failed to FirstOrCreate Assigned data, got error %v", err)
|
||||
}
|
||||
|
||||
var result SerializerStruct
|
||||
if err := DB.First(&result, out.ID).Error; err != nil {
|
||||
t.Fatalf("failed to query data, got error %v", err)
|
||||
}
|
||||
AssertEqual(t, result, out)
|
||||
|
||||
//update record
|
||||
data.Roles = append(data.Roles, "r3")
|
||||
data.JobInfo.Location = "Gates Hillman Complex"
|
||||
if err := DB.Assign(data).FirstOrCreate(&out).Error; err != nil {
|
||||
t.Fatalf("failed to FirstOrCreate Assigned data, got error %v", err)
|
||||
}
|
||||
if err := DB.First(&result, out.ID).Error; err != nil {
|
||||
t.Fatalf("failed to query data, got error %v", err)
|
||||
}
|
||||
|
||||
AssertEqual(t, result.Roles, data.Roles)
|
||||
AssertEqual(t, result.JobInfo.Location, data.JobInfo.Location)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue