fix: 🐛 embedded struct test failed with custom datatypes (#6311)

* fix: 🐛 embedded struct test failed with custom datatypes

Fix the pointer embedded struct within custom datatypes and *time.time
should be nil issue.

* fix: 🐛 change test case to avoid mssql driver issue

change test cases from bytes to string to avoid mssql driver issue
This commit is contained in:
aclich 2023-05-15 09:59:26 +08:00 committed by GitHub
parent e61b98d696
commit 63534145fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 23 deletions

View File

@ -846,7 +846,7 @@ func (field *Field) setupValuerAndSetter() {
field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
switch data := v.(type) {
case **time.Time:
if data != nil {
if data != nil && *data != nil {
field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(*data))
}
case time.Time:
@ -882,14 +882,12 @@ func (field *Field) setupValuerAndSetter() {
reflectV := reflect.ValueOf(v)
if !reflectV.IsValid() {
field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
} else if reflectV.Kind() == reflect.Ptr && reflectV.IsNil() {
return
} else if reflectV.Type().AssignableTo(field.FieldType) {
field.ReflectValueOf(ctx, value).Set(reflectV)
} else if reflectV.Kind() == reflect.Ptr {
if reflectV.IsNil() || !reflectV.IsValid() {
field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
} else {
return field.Set(ctx, value, reflectV.Elem().Interface())
}
return field.Set(ctx, value, reflectV.Elem().Interface())
} else {
fieldValue := field.ReflectValueOf(ctx, value)
if fieldValue.IsNil() {
@ -910,14 +908,12 @@ func (field *Field) setupValuerAndSetter() {
reflectV := reflect.ValueOf(v)
if !reflectV.IsValid() {
field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
} else if reflectV.Kind() == reflect.Ptr && reflectV.IsNil() {
return
} else if reflectV.Type().AssignableTo(field.FieldType) {
field.ReflectValueOf(ctx, value).Set(reflectV)
} else if reflectV.Kind() == reflect.Ptr {
if reflectV.IsNil() || !reflectV.IsValid() {
field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
} else {
return field.Set(ctx, value, reflectV.Elem().Interface())
}
return field.Set(ctx, value, reflectV.Elem().Interface())
} else {
if valuer, ok := v.(driver.Valuer); ok {
v, _ = valuer.Value()

View File

@ -4,7 +4,9 @@ import (
"database/sql/driver"
"encoding/json"
"errors"
"reflect"
"testing"
"time"
"gorm.io/gorm"
. "gorm.io/gorm/utils/tests"
@ -104,10 +106,14 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) {
}
type Author struct {
ID string
Name string
Email string
Age int
ID string
Name string
Email string
Age int
Content Content
ContentPtr *Content
Birthday time.Time
BirthdayPtr *time.Time
}
type HNPost struct {
@ -135,6 +141,48 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) {
if hnPost.Author != nil {
t.Errorf("Expected to get back a nil Author but got: %v", hnPost.Author)
}
now := time.Now().Round(time.Second)
NewPost := HNPost{
BasePost: &BasePost{Title: "embedded_pointer_type2"},
Author: &Author{
Name: "test",
Content: Content{"test"},
ContentPtr: nil,
Birthday: now,
BirthdayPtr: nil,
},
}
DB.Create(&NewPost)
hnPost = HNPost{}
if err := DB.First(&hnPost, "title = ?", NewPost.Title).Error; err != nil {
t.Errorf("No error should happen when find embedded pointer type, but got %v", err)
}
if hnPost.Title != NewPost.Title {
t.Errorf("Should find correct value for embedded pointer type")
}
if hnPost.Author.Name != NewPost.Author.Name {
t.Errorf("Expected to get Author name %v but got: %v", NewPost.Author.Name, hnPost.Author.Name)
}
if !reflect.DeepEqual(NewPost.Author.Content, hnPost.Author.Content) {
t.Errorf("Expected to get Author content %v but got: %v", NewPost.Author.Content, hnPost.Author.Content)
}
if hnPost.Author.ContentPtr != nil {
t.Errorf("Expected to get nil Author contentPtr but got: %v", hnPost.Author.ContentPtr)
}
if NewPost.Author.Birthday.UnixMilli() != hnPost.Author.Birthday.UnixMilli() {
t.Errorf("Expected to get Author birthday with %+v but got: %+v", NewPost.Author.Birthday, hnPost.Author.Birthday)
}
if hnPost.Author.BirthdayPtr != nil {
t.Errorf("Expected to get nil Author birthdayPtr but got: %+v", hnPost.Author.BirthdayPtr)
}
}
type Content struct {
@ -142,18 +190,26 @@ type Content struct {
}
func (c Content) Value() (driver.Value, error) {
return json.Marshal(c)
// mssql driver with issue on handling null bytes https://github.com/denisenkom/go-mssqldb/issues/530,
b, err := json.Marshal(c)
return string(b[:]), err
}
func (c *Content) Scan(src interface{}) error {
b, ok := src.([]byte)
if !ok {
return errors.New("Embedded.Scan byte assertion failed")
}
var value Content
if err := json.Unmarshal(b, &value); err != nil {
return err
str, ok := src.(string)
if !ok {
byt, ok := src.([]byte)
if !ok {
return errors.New("Embedded.Scan byte assertion failed")
}
if err := json.Unmarshal(byt, &value); err != nil {
return err
}
} else {
if err := json.Unmarshal([]byte(str), &value); err != nil {
return err
}
}
*c = value