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 fb9233011d209174e8223e970f0f732412852908
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
 | // create valuer, setter when parse struct
 | ||||||
| func (field *Field) setupValuerAndSetter() { | func (field *Field) setupValuerAndSetter() { | ||||||
| 	// Setup NewValuePool
 | 	// Setup NewValuePool
 | ||||||
| 	var fieldValue = reflect.New(field.FieldType).Interface() | 	field.setupNewValuePool() | ||||||
| 	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)) |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	// ValueOf returns field's value and if it is zero
 | 	// ValueOf returns field's value and if it is zero
 | ||||||
| 	fieldIndex := field.StructField.Index[0] | 	fieldIndex := field.StructField.Index[0] | ||||||
| @ -512,7 +480,7 @@ func (field *Field) setupValuerAndSetter() { | |||||||
| 				s = field.Serializer | 				s = field.Serializer | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			return serializer{ | 			return &serializer{ | ||||||
| 				Field:           field, | 				Field:           field, | ||||||
| 				SerializeValuer: s, | 				SerializeValuer: s, | ||||||
| 				Destination:     v, | 				Destination:     v, | ||||||
| @ -943,7 +911,9 @@ func (field *Field) setupValuerAndSetter() { | |||||||
| 
 | 
 | ||||||
| 		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) { | 		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) { | ||||||
| 			if s, ok := v.(*serializer); ok { | 			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 { | 					if sameElemType { | ||||||
| 						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem()) | 						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem()) | ||||||
| 						s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface) | 						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) { | func TestJoinWithSoftDeleted(t *testing.T) { | ||||||
| 	DB = DB.Debug() |  | ||||||
| 
 |  | ||||||
| 	user := GetUser("TestJoinWithSoftDeletedUser", Config{Account: true, NamedPet: true}) | 	user := GetUser("TestJoinWithSoftDeletedUser", Config{Account: true, NamedPet: true}) | ||||||
| 	DB.Create(&user) | 	DB.Create(&user) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst re | |||||||
| 	case string: | 	case string: | ||||||
| 		*es = EncryptedString(strings.TrimPrefix(value, "hello")) | 		*es = EncryptedString(strings.TrimPrefix(value, "hello")) | ||||||
| 	default: | 	default: | ||||||
| 		return fmt.Errorf("unsupported data %v", dbValue) | 		return fmt.Errorf("unsupported data %#v", dbValue) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @ -83,4 +83,53 @@ func TestSerializer(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	AssertEqual(t, result, data) | 	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 ag9920
						ag9920