Skip to content

Commit da1a1f2

Browse files
Merge pull request #51 from oracle-samples/update_belongs_to_test
Add belongs-to and has-many test coverage
2 parents b8d78f4 + adcc2b1 commit da1a1f2

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

tests/update_belongs_to_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,99 @@ func TestUpdateBelongsTo(t *testing.T) {
9696
}
9797
CheckUserSkipUpdatedAt(t, user, user5)
9898
}
99+
100+
func TestUpdateBelongsToWithReturning(t *testing.T) {
101+
user := *GetUser("update-belongs-to-returning", Config{})
102+
103+
// Test that RETURNING clauses work properly when updating with associations
104+
if err := DB.Create(&user).Error; err != nil {
105+
t.Fatalf("errors happened when create: %v", err)
106+
}
107+
108+
originalUpdatedAt := user.UpdatedAt
109+
user.Company = Company{Name: "returning-test-company"}
110+
user.Manager = &User{Name: "returning-test-manager"}
111+
112+
// Save and verify that UpdatedAt was properly returned from db
113+
if err := DB.Save(&user).Error; err != nil {
114+
t.Fatalf("errors happened when update with returning: %v", err)
115+
}
116+
117+
// Verify RETURNING clause populated the UpdatedAt field
118+
if !user.UpdatedAt.After(originalUpdatedAt) {
119+
t.Errorf("expected UpdatedAt to be updated via RETURNING clause")
120+
}
121+
122+
// Verify the associations were created properly
123+
var result User
124+
if err := DB.Preload("Company").Preload("Manager").First(&result, user.ID).Error; err != nil {
125+
t.Fatalf("failed to load user with associations: %v", err)
126+
}
127+
128+
if result.Company.Name != "returning-test-company" {
129+
t.Errorf("expected company name to be saved correctly")
130+
}
131+
if result.Manager.Name != "returning-test-manager" {
132+
t.Errorf("expected manager name to be saved correctly")
133+
}
134+
}
135+
136+
func TestUpdateBelongsToWithNullValues(t *testing.T) {
137+
user := *GetUser("update-belongs-to-null", Config{})
138+
139+
// Create user with associations
140+
user.Company = Company{Name: "initial-company"}
141+
user.Manager = &User{Name: "initial-manager"}
142+
143+
if err := DB.Create(&user).Error; err != nil {
144+
t.Fatalf("errors happened when create: %v", err)
145+
}
146+
147+
// Verify associations were created
148+
if user.CompanyID == nil {
149+
t.Fatalf("expected CompanyID to be set after create")
150+
}
151+
if user.ManagerID == nil {
152+
t.Fatalf("expected ManagerID to be set after create")
153+
}
154+
155+
// Test setting foreign keys to NULL - clear both the foreign keys AND the association objects
156+
user.CompanyID = nil // Clear foreign key
157+
user.ManagerID = nil // Clear foreign key
158+
user.Company = Company{} // Clear association object (zero value)
159+
user.Manager = nil // Clear association pointer
160+
161+
if err := DB.Model(&user).Updates(map[string]interface{}{
162+
"company_id": nil,
163+
"manager_id": nil,
164+
}).Error; err != nil {
165+
t.Fatalf("errors happened when setting associations to null: %v", err)
166+
}
167+
168+
var result User
169+
if err := DB.First(&result, user.ID).Error; err != nil {
170+
t.Fatalf("failed to load user: %v", err)
171+
}
172+
173+
// Verify foreign keys are properly NULL
174+
if result.CompanyID != nil {
175+
t.Errorf("expected CompanyID to be NULL, got %v", *result.CompanyID)
176+
}
177+
if result.ManagerID != nil {
178+
t.Errorf("expected ManagerID to be NULL, got %v", *result.ManagerID)
179+
}
180+
181+
// Try to load with preload to ensure NULL handling works
182+
var resultWithPreload User
183+
if err := DB.Preload("Company").Preload("Manager").First(&resultWithPreload, user.ID).Error; err != nil {
184+
t.Fatalf("failed to load user with preload: %v", err)
185+
}
186+
187+
// When foreign keys are NULL, preloaded associations should be zero values
188+
if resultWithPreload.Company.ID != 0 {
189+
t.Errorf("expected Company to be zero value when foreign key is NULL")
190+
}
191+
if resultWithPreload.Manager != nil {
192+
t.Errorf("expected Manager to be nil when foreign key is NULL")
193+
}
194+
}

tests/update_has_many_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,51 @@ func TestUpdateHasManyAssociations(t *testing.T) {
120120
CheckUserSkipUpdatedAt(t, user4, user)
121121
})
122122
}
123+
124+
func TestHasManyWithReturning(t *testing.T) {
125+
user := *GetUser("returning-has-many", Config{})
126+
127+
if err := DB.Create(&user).Error; err != nil {
128+
t.Fatalf("failed to create user: %v", err)
129+
}
130+
131+
initialPets := []*Pet{
132+
{Name: "returning-pet1"},
133+
{Name: "returning-pet2"},
134+
}
135+
136+
user.Pets = initialPets
137+
138+
// This should trigger RETURNING clauses for the new pets
139+
if err := DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&user).Error; err != nil {
140+
t.Fatalf("failed to save user with pets: %v", err)
141+
}
142+
143+
// Verify RETURNING populated IDs and timestamps for pets
144+
for _, pet := range user.Pets {
145+
if pet.ID == 0 {
146+
t.Errorf("pet ID should be populated via RETURNING clause")
147+
}
148+
if pet.CreatedAt.IsZero() {
149+
t.Errorf("pet CreatedAt should be populated via RETURNING clause")
150+
}
151+
if pet.UserID == nil || *pet.UserID != user.ID {
152+
t.Errorf("pet UserID should be set correctly")
153+
}
154+
}
155+
156+
// try updating existing pets with RETURNING
157+
for _, pet := range user.Pets {
158+
originalUpdatedAt := pet.UpdatedAt
159+
pet.Name += "-updated"
160+
161+
if err := DB.Save(pet).Error; err != nil {
162+
t.Fatalf("failed to update pet: %v", err)
163+
}
164+
165+
// Verify RETURNING updated the UpdatedAt timestamp
166+
if !pet.UpdatedAt.After(originalUpdatedAt) {
167+
t.Errorf("pet UpdatedAt should be updated via RETURNING clause")
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)