fix: use reflect.Append when preloading nested associations (#7014)
Co-authored-by: Emilien Kofman <emilien.kofman@miimosa.com>
This commit is contained in:
		
							parent
							
								
									78c6dfd712
								
							
						
					
					
						commit
						05167fd591
					
				| @ -125,13 +125,15 @@ func preloadEntryPoint(db *gorm.DB, joins []string, relationships *schema.Relati | |||||||
| 				case reflect.Slice, reflect.Array: | 				case reflect.Slice, reflect.Array: | ||||||
| 					if rv.Len() > 0 { | 					if rv.Len() > 0 { | ||||||
| 						reflectValue := rel.FieldSchema.MakeSlice().Elem() | 						reflectValue := rel.FieldSchema.MakeSlice().Elem() | ||||||
| 						reflectValue.SetLen(rv.Len()) |  | ||||||
| 						for i := 0; i < rv.Len(); i++ { | 						for i := 0; i < rv.Len(); i++ { | ||||||
| 							frv := rel.Field.ReflectValueOf(db.Statement.Context, rv.Index(i)) | 							frv := rel.Field.ReflectValueOf(db.Statement.Context, rv.Index(i)) | ||||||
| 							if frv.Kind() != reflect.Ptr { | 							if frv.Kind() != reflect.Ptr { | ||||||
| 								reflectValue.Index(i).Set(frv.Addr()) | 								reflectValue = reflect.Append(reflectValue, frv.Addr()) | ||||||
| 							} else { | 							} else { | ||||||
| 								reflectValue.Index(i).Set(frv) | 								if frv.IsNil() { | ||||||
|  | 									continue | ||||||
|  | 								} | ||||||
|  | 								reflectValue = reflect.Append(reflectValue, frv) | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -67,9 +67,10 @@ func (schema Schema) String() string { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (schema Schema) MakeSlice() reflect.Value { | func (schema Schema) MakeSlice() reflect.Value { | ||||||
| 	slice := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(schema.ModelType)), 0, 20) | 	slice := reflect.MakeSlice(reflect.SliceOf(reflect.PointerTo(schema.ModelType)), 0, 20) | ||||||
| 	results := reflect.New(slice.Type()) | 	results := reflect.New(slice.Type()) | ||||||
| 	results.Elem().Set(slice) | 	results.Elem().Set(slice) | ||||||
|  | 
 | ||||||
| 	return results | 	return results | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,10 +1,12 @@ | |||||||
| package tests_test | package tests_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| 	. "gorm.io/gorm/utils/tests" | 	. "gorm.io/gorm/utils/tests" | ||||||
| ) | ) | ||||||
| @ -402,3 +404,75 @@ func TestNestedJoins(t *testing.T) { | |||||||
| 		CheckPet(t, *user.Manager.NamedPet, *users2[idx].Manager.NamedPet) | 		CheckPet(t, *user.Manager.NamedPet, *users2[idx].Manager.NamedPet) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestJoinsPreload_Issue7013(t *testing.T) { | ||||||
|  | 	manager := &User{Name: "Manager"} | ||||||
|  | 	DB.Create(manager) | ||||||
|  | 
 | ||||||
|  | 	var userIDs []uint | ||||||
|  | 	for i := 0; i < 21; i++ { | ||||||
|  | 		user := &User{Name: fmt.Sprintf("User%d", i), ManagerID: &manager.ID} | ||||||
|  | 		DB.Create(user) | ||||||
|  | 		userIDs = append(userIDs, user.ID) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var entries []User | ||||||
|  | 	assert.NotPanics(t, func() { | ||||||
|  | 		assert.NoError(t, | ||||||
|  | 			DB.Debug().Preload("Manager.Team"). | ||||||
|  | 				Joins("Manager.Company"). | ||||||
|  | 				Find(&entries).Error) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestJoinsPreload_Issue7013_RelationEmpty(t *testing.T) { | ||||||
|  | 	type ( | ||||||
|  | 		Furniture struct { | ||||||
|  | 			gorm.Model | ||||||
|  | 			OwnerID *uint | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		Owner struct { | ||||||
|  | 			gorm.Model | ||||||
|  | 			Furnitures []Furniture | ||||||
|  | 			CompanyID  *uint | ||||||
|  | 			Company    Company | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		Building struct { | ||||||
|  | 			gorm.Model | ||||||
|  | 			Name    string | ||||||
|  | 			OwnerID *uint | ||||||
|  | 			Owner   Owner | ||||||
|  | 		} | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	DB.Migrator().DropTable(&Building{}, &Owner{}, &Furniture{}) | ||||||
|  | 	DB.Migrator().AutoMigrate(&Building{}, &Owner{}, &Furniture{}) | ||||||
|  | 
 | ||||||
|  | 	home := &Building{Name: "relation_empty"} | ||||||
|  | 	DB.Create(home) | ||||||
|  | 
 | ||||||
|  | 	var entries []Building | ||||||
|  | 	assert.NotPanics(t, func() { | ||||||
|  | 		assert.NoError(t, | ||||||
|  | 			DB.Debug().Preload("Owner.Furnitures"). | ||||||
|  | 				Joins("Owner.Company"). | ||||||
|  | 				Find(&entries).Error) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	AssertEqual(t, entries, []Building{{Model: home.Model, Name: "relation_empty", Owner: Owner{Company: Company{}}}}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestJoinsPreload_Issue7013_NoEntries(t *testing.T) { | ||||||
|  | 	var entries []User | ||||||
|  | 	assert.NotPanics(t, func() { | ||||||
|  | 		assert.NoError(t, | ||||||
|  | 			DB.Debug().Preload("Manager.Team"). | ||||||
|  | 				Joins("Manager.Company"). | ||||||
|  | 				Where("false"). | ||||||
|  | 				Find(&entries).Error) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	AssertEqual(t, len(entries), 0) | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Emilien
						Emilien