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 { | ||||
| 	if field.DBDataType != "" { | ||||
| 		return field.DBDataType | ||||
| 	} | ||||
| 
 | ||||
| 	fieldValue := reflect.New(field.IndirectFieldType) | ||||
| 	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok { | ||||
| 		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 { | ||||
| 				field := stmt.Schema.FieldsByDBName[dbName] | ||||
| 				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)) | ||||
| 				createTableSQL += "," | ||||
| 			} | ||||
|  | ||||
| @ -38,7 +38,6 @@ type Field struct { | ||||
| 	DBName                string | ||||
| 	BindNames             []string | ||||
| 	DataType              DataType | ||||
| 	DBDataType            string | ||||
| 	PrimaryKey            bool | ||||
| 	AutoIncrement         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 valuer, isValueOf := fieldValue.Interface().(driver.Valuer); isValueOf { | ||||
| 	valuer, isValuer := fieldValue.Interface().(driver.Valuer) | ||||
| 	if isValuer { | ||||
| 		var overrideFieldValue bool | ||||
| 		if v, err := valuer.Value(); v != nil && err == nil { | ||||
| 			overrideFieldValue = true | ||||
| @ -176,10 +176,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { | ||||
| 		field.Comment = val | ||||
| 	} | ||||
| 
 | ||||
| 	if val, ok := field.TagSettings["TYPE"]; ok { | ||||
| 		field.DBDataType = val | ||||
| 	} | ||||
| 
 | ||||
| 	switch reflect.Indirect(fieldValue).Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		field.DataType = Bool | ||||
| @ -227,6 +223,10 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { | ||||
| 		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 strings.ToUpper(v) == "NANO" { | ||||
| 			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
 | ||||
| 	if _, ok := field.TagSettings["-"]; ok { | ||||
| 		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 | ||||
| 		field.Creatable = 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 { | ||||
| 			t.Errorf("schema %v failed to look up field with name %v", s, f.Name) | ||||
| 		} 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 field, ok := s.FieldsByDBName[f.DBName]; !ok || parsedField != field { | ||||
|  | ||||
| @ -1,6 +1,9 @@ | ||||
| package tests_test | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql/driver" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"gorm.io/gorm" | ||||
| @ -102,3 +105,45 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) { | ||||
| 		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/jinzhu/now v1.1.1 | ||||
| 	github.com/lib/pq v1.6.0 | ||||
| 	gorm.io/driver/mysql v0.0.0-20200609004954-b8310c61c3f2 | ||||
| 	gorm.io/driver/postgres v0.0.0-20200602015520-15fcc29eb286 | ||||
| 	gorm.io/driver/sqlite v1.0.0 | ||||
| 	gorm.io/driver/sqlserver v0.0.0-20200610080012-25da0c25e81d | ||||
| 	gorm.io/driver/mysql v0.2.0 | ||||
| 	gorm.io/driver/postgres v0.2.0 | ||||
| 	gorm.io/driver/sqlite v1.0.2 | ||||
| 	gorm.io/driver/sqlserver v0.2.0 | ||||
| 	gorm.io/gorm v0.0.0-00010101000000-000000000000 | ||||
| ) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu