From 369027a6aea960d9fd489d9bdf237d61f40d962d Mon Sep 17 00:00:00 2001 From: lscieux Date: Thu, 4 Feb 2016 21:19:29 +0100 Subject: [PATCH] Fix a reflection panic with nested preloads --- preload.go | 3 +++ preload_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/preload.go b/preload.go index ebbbeb32..d9f4e9c5 100644 --- a/preload.go +++ b/preload.go @@ -157,6 +157,9 @@ func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) for j := 0; j < objects.Len(); j++ { object := reflect.Indirect(objects.Index(j)) if equalAsString(getRealValue(object, relation.AssociationForeignFieldNames), value) { + if object.Kind() == reflect.Ptr { + object = object.Elem() + } f := object.FieldByName(field.Name) f.Set(reflect.Append(f, result)) break diff --git a/preload_test.go b/preload_test.go index 010682fd..7f4b8fdb 100644 --- a/preload_test.go +++ b/preload_test.go @@ -1075,6 +1075,64 @@ func TestNestedManyToManyPreload2(t *testing.T) { } } +func TestNestedManyToManyPreload3(t *testing.T) { + type ( + Level4 struct { + ID uint + Value string + Level3ID uint + } + Level3 struct { + ID uint + Value string + Level4s []*Level4 + } + Level2 struct { + ID uint + Value string + Level3s []*Level3 `gorm:"many2many:level2_level3;"` + } + Level1 struct { + ID uint + Value string + Level2s []*Level2 `gorm:"many2many:level1_level2;"` + } + ) + + DB.DropTableIfExists(&Level1{}) + DB.DropTableIfExists(&Level2{}) + DB.DropTableIfExists(&Level3{}) + DB.DropTableIfExists(&Level4{}) + DB.DropTableIfExists("level1_level2") + DB.DropTableIfExists("level2_level3") + + dummy := Level1{ + Value: "Level1", + Level2s: []*Level2{&Level2{ + Value: "Level2", + Level3s: []*Level3{&Level3{ + Value: "Level3", + Level4s: []*Level4{&Level4{ + Value: "Level4", + }}, + }}, + }}, + } + + if err := DB.AutoMigrate(&Level4{}, &Level3{}, &Level2{}, &Level1{}).Error; err != nil { + t.Error(err) + } + + if err := DB.Save(&dummy).Error; err != nil { + t.Error(err) + } + + var level1 Level1 + if err := DB.Preload("Level2s").Preload("Level2s.Level3s").Preload("Level2s.Level3s.Level4s").First(&level1).Error; err != nil { + t.Error(err) + } +} + func TestNilPointerSlice(t *testing.T) { type ( Level3 struct {