Fix nested embedded struct, close #3278
This commit is contained in:
		
							parent
							
								
									9fcc337bd1
								
							
						
					
					
						commit
						dc48e04896
					
				| @ -301,14 +301,12 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { | ||||
| 			field.Updatable = false | ||||
| 			field.Readable = false | ||||
| 
 | ||||
| 			cacheStore := schema.cacheStore | ||||
| 			if _, embedded := schema.cacheStore.Load("embedded_cache_store"); !embedded { | ||||
| 				cacheStore = &sync.Map{} | ||||
| 				cacheStore.Store("embedded_cache_store", true) | ||||
| 			} | ||||
| 			cacheStore := &sync.Map{} | ||||
| 			cacheStore.Store(embeddedCacheKey, true) | ||||
| 			if field.EmbeddedSchema, err = Parse(fieldValue.Interface(), cacheStore, schema.namer); err != nil { | ||||
| 				schema.err = err | ||||
| 			} | ||||
| 
 | ||||
| 			for _, ef := range field.EmbeddedSchema.Fields { | ||||
| 				ef.Schema = schema | ||||
| 				ef.OwnerSchema = field.EmbeddedSchema | ||||
|  | ||||
| @ -41,7 +41,7 @@ type AdvancedDataTypeUser struct { | ||||
| } | ||||
| 
 | ||||
| type BaseModel struct { | ||||
| 	ID        uint `gorm:"primarykey"` | ||||
| 	ID        uint | ||||
| 	CreatedAt time.Time | ||||
| 	CreatedBy *int | ||||
| 	Created   *VersionUser `gorm:"foreignKey:CreatedBy"` | ||||
| @ -51,8 +51,7 @@ type BaseModel struct { | ||||
| 
 | ||||
| type VersionModel struct { | ||||
| 	BaseModel | ||||
| 	Version   int | ||||
| 	CompanyID int | ||||
| 	Version int | ||||
| } | ||||
| 
 | ||||
| type VersionUser struct { | ||||
|  | ||||
| @ -212,29 +212,30 @@ func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, loaded := cacheStore.LoadOrStore(modelType, schema); !loaded { | ||||
| 		// parse relations for unidentified fields
 | ||||
| 		for _, field := range schema.Fields { | ||||
| 			if field.DataType == "" && field.Creatable { | ||||
| 				if schema.parseRelation(field); schema.err != nil { | ||||
| 					return schema, schema.err | ||||
| 		if _, embedded := schema.cacheStore.Load(embeddedCacheKey); !embedded { | ||||
| 			for _, field := range schema.Fields { | ||||
| 				if field.DataType == "" && field.Creatable { | ||||
| 					if schema.parseRelation(field); schema.err != nil { | ||||
| 						return schema, schema.err | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			fieldValue := reflect.New(field.IndirectFieldType) | ||||
| 			if fc, ok := fieldValue.Interface().(CreateClausesInterface); ok { | ||||
| 				field.Schema.CreateClauses = append(field.Schema.CreateClauses, fc.CreateClauses(field)...) | ||||
| 			} | ||||
| 				fieldValue := reflect.New(field.IndirectFieldType) | ||||
| 				if fc, ok := fieldValue.Interface().(CreateClausesInterface); ok { | ||||
| 					field.Schema.CreateClauses = append(field.Schema.CreateClauses, fc.CreateClauses(field)...) | ||||
| 				} | ||||
| 
 | ||||
| 			if fc, ok := fieldValue.Interface().(QueryClausesInterface); ok { | ||||
| 				field.Schema.QueryClauses = append(field.Schema.QueryClauses, fc.QueryClauses(field)...) | ||||
| 			} | ||||
| 				if fc, ok := fieldValue.Interface().(QueryClausesInterface); ok { | ||||
| 					field.Schema.QueryClauses = append(field.Schema.QueryClauses, fc.QueryClauses(field)...) | ||||
| 				} | ||||
| 
 | ||||
| 			if fc, ok := fieldValue.Interface().(UpdateClausesInterface); ok { | ||||
| 				field.Schema.UpdateClauses = append(field.Schema.UpdateClauses, fc.UpdateClauses(field)...) | ||||
| 			} | ||||
| 				if fc, ok := fieldValue.Interface().(UpdateClausesInterface); ok { | ||||
| 					field.Schema.UpdateClauses = append(field.Schema.UpdateClauses, fc.UpdateClauses(field)...) | ||||
| 				} | ||||
| 
 | ||||
| 			if fc, ok := fieldValue.Interface().(DeleteClausesInterface); ok { | ||||
| 				field.Schema.DeleteClauses = append(field.Schema.DeleteClauses, fc.DeleteClauses(field)...) | ||||
| 				if fc, ok := fieldValue.Interface().(DeleteClausesInterface); ok { | ||||
| 					field.Schema.DeleteClauses = append(field.Schema.DeleteClauses, fc.DeleteClauses(field)...) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -162,7 +162,23 @@ func TestCustomizeTableName(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestNestedModel(t *testing.T) { | ||||
| 	if _, err := schema.Parse(&VersionUser{}, &sync.Map{}, schema.NamingStrategy{}); err != nil { | ||||
| 	versionUser, err := schema.Parse(&VersionUser{}, &sync.Map{}, schema.NamingStrategy{}) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("failed to parse nested user, got error %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	fields := []schema.Field{ | ||||
| 		{Name: "ID", DBName: "id", BindNames: []string{"VersionModel", "BaseModel", "ID"}, DataType: schema.Uint, PrimaryKey: true, Size: 64, HasDefaultValue: true, AutoIncrement: true}, | ||||
| 		{Name: "CreatedBy", DBName: "created_by", BindNames: []string{"VersionModel", "BaseModel", "CreatedBy"}, DataType: schema.Int, Size: 64}, | ||||
| 		{Name: "Version", DBName: "version", BindNames: []string{"VersionModel", "Version"}, DataType: schema.Int, Size: 64}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, f := range fields { | ||||
| 		checkSchemaField(t, versionUser, &f, func(f *schema.Field) { | ||||
| 			f.Creatable = true | ||||
| 			f.Updatable = true | ||||
| 			f.Readable = true | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -9,6 +9,8 @@ import ( | ||||
| 	"gorm.io/gorm/utils" | ||||
| ) | ||||
| 
 | ||||
| var embeddedCacheKey = "embedded_cache_store" | ||||
| 
 | ||||
| func ParseTagSetting(str string, sep string) map[string]string { | ||||
| 	settings := map[string]string{} | ||||
| 	names := strings.Split(str, sep) | ||||
|  | ||||
| @ -160,9 +160,9 @@ func TestEmbeddedRelations(t *testing.T) { | ||||
| 		Advanced bool | ||||
| 	} | ||||
| 
 | ||||
| 	DB.Debug().Migrator().DropTable(&AdvancedUser{}) | ||||
| 	DB.Migrator().DropTable(&AdvancedUser{}) | ||||
| 
 | ||||
| 	if err := DB.Debug().AutoMigrate(&AdvancedUser{}); err != nil { | ||||
| 	if err := DB.AutoMigrate(&AdvancedUser{}); err != nil { | ||||
| 		t.Errorf("Failed to auto migrate advanced user, got error %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -76,7 +76,7 @@ func AssertEqual(t *testing.T, got, expect interface{}) { | ||||
| 					} | ||||
| 				} else { | ||||
| 					name := reflect.ValueOf(got).Type().Elem().Name() | ||||
| 					t.Errorf("%v expects length: %v, got %v", name, reflect.ValueOf(expect).Len(), reflect.ValueOf(got).Len()) | ||||
| 					t.Errorf("%v expects length: %v, got %v (expects: %+v, got %+v)", name, reflect.ValueOf(expect).Len(), reflect.ValueOf(got).Len(), expect, got) | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu