mirror of https://github.com/go-gorm/gorm.git
Test embedded struct implements Scan & Value interface
This commit is contained in:
parent
6b2f37189e
commit
96368eb967
|
@ -44,10 +44,6 @@ func (m Migrator) RunWithValue(value interface{}, fc func(*gorm.Statement) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Migrator) DataTypeOf(field *schema.Field) string {
|
func (m Migrator) DataTypeOf(field *schema.Field) string {
|
||||||
if field.DBDataType != "" {
|
|
||||||
return field.DBDataType
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValue := reflect.New(field.IndirectFieldType)
|
fieldValue := reflect.New(field.IndirectFieldType)
|
||||||
if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
|
if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
|
||||||
if dataType := dataTyper.GormDBDataType(m.DB, field); dataType != "" {
|
if dataType := dataTyper.GormDBDataType(m.DB, field); dataType != "" {
|
||||||
|
@ -155,7 +151,7 @@ func (m Migrator) CreateTable(values ...interface{}) error {
|
||||||
for _, dbName := range stmt.Schema.DBNames {
|
for _, dbName := range stmt.Schema.DBNames {
|
||||||
field := stmt.Schema.FieldsByDBName[dbName]
|
field := stmt.Schema.FieldsByDBName[dbName]
|
||||||
createTableSQL += fmt.Sprintf("? ?")
|
createTableSQL += fmt.Sprintf("? ?")
|
||||||
hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(field.DBDataType), "PRIMARY KEY")
|
hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(string(field.DataType)), "PRIMARY KEY")
|
||||||
values = append(values, clause.Column{Name: dbName}, m.FullDataTypeOf(field))
|
values = append(values, clause.Column{Name: dbName}, m.FullDataTypeOf(field))
|
||||||
createTableSQL += ","
|
createTableSQL += ","
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ type Field struct {
|
||||||
DBName string
|
DBName string
|
||||||
BindNames []string
|
BindNames []string
|
||||||
DataType DataType
|
DataType DataType
|
||||||
DBDataType string
|
|
||||||
PrimaryKey bool
|
PrimaryKey bool
|
||||||
AutoIncrement bool
|
AutoIncrement bool
|
||||||
Creatable bool
|
Creatable bool
|
||||||
|
@ -104,7 +103,8 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if field is valuer, used its value or first fields as data type
|
// if field is valuer, used its value or first fields as data type
|
||||||
if valuer, isValueOf := fieldValue.Interface().(driver.Valuer); isValueOf {
|
valuer, isValuer := fieldValue.Interface().(driver.Valuer)
|
||||||
|
if isValuer {
|
||||||
var overrideFieldValue bool
|
var overrideFieldValue bool
|
||||||
if v, err := valuer.Value(); v != nil && err == nil {
|
if v, err := valuer.Value(); v != nil && err == nil {
|
||||||
overrideFieldValue = true
|
overrideFieldValue = true
|
||||||
|
@ -176,10 +176,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
field.Comment = val
|
field.Comment = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := field.TagSettings["TYPE"]; ok {
|
|
||||||
field.DBDataType = val
|
|
||||||
}
|
|
||||||
|
|
||||||
switch reflect.Indirect(fieldValue).Kind() {
|
switch reflect.Indirect(fieldValue).Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
field.DataType = Bool
|
field.DataType = Bool
|
||||||
|
@ -227,6 +223,10 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
field.DataType = DataType(dataTyper.GormDataType())
|
field.DataType = DataType(dataTyper.GormDataType())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := field.TagSettings["TYPE"]; ok {
|
||||||
|
field.DataType = DataType(val)
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := field.TagSettings["AUTOCREATETIME"]; ok || (field.Name == "CreatedAt" && (field.DataType == Time || field.DataType == Int || field.DataType == Uint)) {
|
if v, ok := field.TagSettings["AUTOCREATETIME"]; ok || (field.Name == "CreatedAt" && (field.DataType == Time || field.DataType == Int || field.DataType == Uint)) {
|
||||||
if strings.ToUpper(v) == "NANO" {
|
if strings.ToUpper(v) == "NANO" {
|
||||||
field.AutoCreateTime = UnixNanosecond
|
field.AutoCreateTime = UnixNanosecond
|
||||||
|
@ -256,10 +256,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.DataType == "" && field.DBDataType != "" {
|
|
||||||
field.DataType = String
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup permission
|
// setup permission
|
||||||
if _, ok := field.TagSettings["-"]; ok {
|
if _, ok := field.TagSettings["-"]; ok {
|
||||||
field.Creatable = false
|
field.Creatable = false
|
||||||
|
@ -293,7 +289,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := field.TagSettings["EMBEDDED"]; ok || fieldStruct.Anonymous {
|
if _, ok := field.TagSettings["EMBEDDED"]; ok || (fieldStruct.Anonymous && !isValuer) {
|
||||||
var err error
|
var err error
|
||||||
field.Creatable = false
|
field.Creatable = false
|
||||||
field.Updatable = false
|
field.Updatable = false
|
||||||
|
|
|
@ -52,7 +52,7 @@ func checkSchemaField(t *testing.T, s *schema.Schema, f *schema.Field, fc func(*
|
||||||
if parsedField, ok := s.FieldsByName[f.Name]; !ok {
|
if parsedField, ok := s.FieldsByName[f.Name]; !ok {
|
||||||
t.Errorf("schema %v failed to look up field with name %v", s, f.Name)
|
t.Errorf("schema %v failed to look up field with name %v", s, f.Name)
|
||||||
} else {
|
} else {
|
||||||
tests.AssertObjEqual(t, parsedField, f, "Name", "DBName", "BindNames", "DataType", "DBDataType", "PrimaryKey", "AutoIncrement", "Creatable", "Updatable", "Readable", "HasDefaultValue", "DefaultValue", "NotNull", "Unique", "Comment", "Size", "Precision", "Tag", "TagSettings")
|
tests.AssertObjEqual(t, parsedField, f, "Name", "DBName", "BindNames", "DataType", "PrimaryKey", "AutoIncrement", "Creatable", "Updatable", "Readable", "HasDefaultValue", "DefaultValue", "NotNull", "Unique", "Comment", "Size", "Precision", "Tag", "TagSettings")
|
||||||
|
|
||||||
if f.DBName != "" {
|
if f.DBName != "" {
|
||||||
if field, ok := s.FieldsByDBName[f.DBName]; !ok || parsedField != field {
|
if field, ok := s.FieldsByDBName[f.DBName]; !ok || parsedField != field {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package tests_test
|
package tests_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -102,3 +105,45 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) {
|
||||||
t.Errorf("Should find correct value for embedded pointer type")
|
t.Errorf("Should find correct value for embedded pointer type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = value
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmbeddedScanValuer(t *testing.T) {
|
||||||
|
type HNPost struct {
|
||||||
|
gorm.Model
|
||||||
|
Content
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Migrator().DropTable(&HNPost{})
|
||||||
|
if err := DB.Migrator().AutoMigrate(&HNPost{}); err != nil {
|
||||||
|
t.Fatalf("failed to auto migrate, got error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hnPost := HNPost{Content: Content{Content: "hello world"}}
|
||||||
|
|
||||||
|
if err := DB.Create(&hnPost).Error; err != nil {
|
||||||
|
t.Errorf("Failed to create got error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ require (
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/jinzhu/now v1.1.1
|
github.com/jinzhu/now v1.1.1
|
||||||
github.com/lib/pq v1.6.0
|
github.com/lib/pq v1.6.0
|
||||||
gorm.io/driver/mysql v0.0.0-20200609004954-b8310c61c3f2
|
gorm.io/driver/mysql v0.2.0
|
||||||
gorm.io/driver/postgres v0.0.0-20200602015520-15fcc29eb286
|
gorm.io/driver/postgres v0.2.0
|
||||||
gorm.io/driver/sqlite v1.0.0
|
gorm.io/driver/sqlite v1.0.2
|
||||||
gorm.io/driver/sqlserver v0.0.0-20200610080012-25da0c25e81d
|
gorm.io/driver/sqlserver v0.2.0
|
||||||
gorm.io/gorm v0.0.0-00010101000000-000000000000
|
gorm.io/gorm v0.0.0-00010101000000-000000000000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue