diff --git a/schema/schema.go b/schema/schema.go index a9c53b70..0665f321 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -115,7 +115,6 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam value = reflect.New(value.Type().Elem()) } - modelValue := reflect.Indirect(value) modelType := reflect.Indirect(value).Type() if modelType.Kind() == reflect.Interface { @@ -150,6 +149,7 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam return s, s.err } + modelValue := reflect.New(modelType) tableName := namer.TableName(modelType.Name()) if tabler, ok := modelValue.Interface().(Tabler); ok { tableName = tabler.TableName() @@ -166,7 +166,7 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam schema := &Schema{ Name: modelType.Name(), - ModelValue: modelValue, + ModelValue: reflect.Indirect(value), ModelType: modelType, Table: tableName, FieldsByName: map[string]*Field{}, diff --git a/tests/interface_test.go b/tests/interface_test.go new file mode 100644 index 00000000..a484a5b5 --- /dev/null +++ b/tests/interface_test.go @@ -0,0 +1,23 @@ +package tests_test + +import ( + "testing" + + "gorm.io/gorm/utils/tests" + . "gorm.io/gorm/utils/tests" +) + +func TestInterface(t *testing.T) { + vehicleWrite := &tests.Vehicle{Meta: &tests.MotorMeta{Power: "electric"}} + + if err := DB.Create(vehicleWrite).Error; err != nil { + t.Fatalf("fail to create region %v", err) + } + + vehicleRead := &tests.Vehicle{Meta: &tests.MotorMeta{}} + if err := DB.Debug().First(vehicleRead, "id = ?", vehicleWrite.ID).Error; err != nil { + t.Fatalf("fail to find vehicle %v", err) + } else { + AssertEqual(t, vehicleWrite.Meta.(*tests.MotorMeta).Power, vehicleRead.Meta.(*tests.MotorMeta).Power) + } +} diff --git a/tests/tests_test.go b/tests/tests_test.go index 90eb847f..daf52980 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -11,6 +11,7 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/driver/sqlserver" + "gorm.io/gorm" "gorm.io/gorm/logger" . "gorm.io/gorm/utils/tests" @@ -107,7 +108,7 @@ func OpenTestConnection() (db *gorm.DB, err error) { func RunMigrations() { var err error - allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}, &Order{}, &Parent{}, &Child{}} + allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}, &Order{}, &Parent{}, &Child{}, &Vehicle{Meta: &MotorMeta{}}} rand.Seed(time.Now().UnixNano()) rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] }) diff --git a/utils/tests/models.go b/utils/tests/models.go index ec1651a3..94c190b2 100644 --- a/utils/tests/models.go +++ b/utils/tests/models.go @@ -2,6 +2,10 @@ package tests import ( "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" "time" "gorm.io/gorm" @@ -94,3 +98,62 @@ type Child struct { ParentID *uint Parent *Parent } + +type Meta interface { + Scan(src interface{}) error + Value() (driver.Value, error) + GormDataType() string +} +type MotorMeta struct { + Power string +} + +func (meta *MotorMeta) Scan(src interface{}) error { + bytes, ok := src.([]byte) + if !ok { + return errors.New(fmt.Sprint("Failed to unmarshal JSON value:", src)) + } + result := MotorMeta{} + err := json.Unmarshal(bytes, &result) + *meta = result + return err +} +func (meta *MotorMeta) Value() (driver.Value, error) { + if meta == nil { + return nil, nil + } + res, err := json.Marshal(meta) + return string(res), err +} +func (MotorMeta) GormDataType() string { + return "json" +} + +type ManualMeta struct { +} + +func (meta *ManualMeta) Scan(src interface{}) error { + bytes, ok := src.([]byte) + if !ok { + return errors.New(fmt.Sprint("Failed to unmarshal JSON value:", src)) + } + result := ManualMeta{} + err := json.Unmarshal(bytes, &result) + *meta = result + return err +} +func (meta *ManualMeta) Value() (driver.Value, error) { + if meta == nil { + return nil, nil + } + res, err := json.Marshal(meta) + return string(res), err +} +func (ManualMeta) GormDataType() string { + return "json" +} + +type Vehicle struct { + gorm.Model + Meta Meta +}