Your Question
refer to the pr #6219
the test from tests/embedded_struct_test.go works fine.
but after i added one field with data type int, the test will failed.
from
type Author struct {
ID string
Name string
Email string
}
to
type Author struct {
ID string
Name string
Email string
Age int
}
the output will show: Expected to get back a nil Author but got: &{ 0}
Expected answer
the author should also be nil.
More information
I test int & uint types, here is the result
| data type | int64 | int32 | int16 | int8 | int | uint64 | uint32 | uint16 | uint8 | uint |
|---|---|---|---|---|---|---|---|---|---|---|
| test result | pass | failed | failed | failed | failed | pass | failed | failed | failed | failed |
Comment From: hykuan
maybe we need to add something like this ?
from gorm.io/gorm/schema/field.go
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
switch data := v.(type) {
case **int64:
if data != nil && *data != nil {
field.ReflectValueOf(ctx, value).SetInt(**data)
}
+ case **int:
+ if data != nil && *data != nil {
+ field.ReflectValueOf(ctx, value).SetInt(int64(**data))
+ }
Comment From: a631807682
PR welcome
Comment From: aclich
Hi I'm facing similar issue too. After tested, found it was cause by the following datatypes - interface{} (custom data types) - interface{} (custom data types) - time.time
I add those types in tests/embedded_struct_test.go, and it will also make the test failed. Like following example
type Content struct {
Content interface{} `gorm:"type:String"`
}
func (c Content) Value() (driver.Value, error) {
return json.Marshal(c)
}
func (c *Content) Scan(src interface{}) error {
...
}
type Author struct {
ID string
Name string
Email string
Age int
Content Content
ContentPtr *Content
BirthDay time.Time
BirthDayPtr *time.Time
}
I've trying to change the reflect logic on struct scanner & pointer scanner to resolve this problem. Not sure if it's gorm wants?
gorm.io/gorm/schema/field.go
diff --git a/schema/field.go b/schema/field.go
index 7d1a178..dd08e05 100644
--- a/schema/field.go
+++ b/schema/field.go
@@ -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()
Comment From: a631807682
@aclich You are welcome to create a PR. If you can confirm that this is a bug and provide a unit test, we will review it.