@@ -40,13 +40,15 @@ package tests
4040
4141import  (
4242	"database/sql" 
43+ 	"errors" 
4344	"testing" 
4445
4546	"time" 
4647
4748	. "github.com/oracle-samples/gorm-oracle/tests/utils" 
4849
4950	"gorm.io/gorm" 
51+ 	"gorm.io/gorm/clause" 
5052	"gorm.io/gorm/utils/tests" 
5153)
5254
@@ -128,6 +130,87 @@ func TestUpdateHasOne(t *testing.T) {
128130		CheckPetSkipUpdatedAt (t , pet4 , pet )
129131	})
130132
133+ 	t .Run ("ReplaceAssociation" , func (t  * testing.T ) {
134+ 		user  :=  * GetUser ("replace-has-one" , Config {})
135+ 
136+ 		if  err  :=  DB .Create (& user ).Error ; err  !=  nil  {
137+ 			t .Fatalf ("errors happened when create user: %v" , err )
138+ 		}
139+ 
140+ 		acc1  :=  Account {AccountNumber : "first-account" }
141+ 		user .Account  =  acc1 
142+ 
143+ 		if  err  :=  DB .Save (& user ).Error ; err  !=  nil  {
144+ 			t .Fatalf ("errors happened when saving user with first account: %v" , err )
145+ 		}
146+ 
147+ 		acc2  :=  Account {AccountNumber : "second-account" }
148+ 		user .Account  =  acc2 
149+ 		if  err  :=  DB .Session (& gorm.Session {FullSaveAssociations : true }).Save (& user ).Error ; err  !=  nil  {
150+ 			t .Fatalf ("errors happened when replacing association: %v" , err )
151+ 		}
152+ 
153+ 		var  result  User 
154+ 		DB .Preload ("Account" ).First (& result , user .ID )
155+ 		if  result .Account .AccountNumber  !=  "second-account"  {
156+ 			t .Fatalf ("expected replaced account to have AccountNumber 'second-account', got %v" , result .Account .AccountNumber )
157+ 		}
158+ 	})
159+ 
160+ 	t .Run ("ClearHasOneAssociation" , func (t  * testing.T ) {
161+ 		user  :=  * GetUser ("nullify-has-one" , Config {})
162+ 
163+ 		if  err  :=  DB .Create (& user ).Error ; err  !=  nil  {
164+ 			t .Fatalf ("errors happened when create user: %v" , err )
165+ 		}
166+ 
167+ 		user .Account  =  Account {AccountNumber : "to-be-nullified" }
168+ 		if  err  :=  DB .Save (& user ).Error ; err  !=  nil  {
169+ 			t .Fatalf ("errors happened when saving user: %v" , err )
170+ 		}
171+ 
172+ 		DB .Model (& user ).Association ("Account" ).Clear ()
173+ 
174+ 		var  result  User 
175+ 		DB .Preload ("Account" ).First (& result , user .ID )
176+ 		if  result .Account .AccountNumber  !=  ""  {
177+ 			t .Fatalf ("expected account to be nullified/empty, got %v" , result .Account .AccountNumber )
178+ 		}
179+ 	})
180+ 
181+ 	t .Run ("ClearPolymorphicAssociation" , func (t  * testing.T ) {
182+ 		pet  :=  Pet {Name : "clear-poly" }
183+ 		pet .Toy  =  Toy {Name : "polytoy" }
184+ 		DB .Create (& pet )
185+ 
186+ 		DB .Model (& pet ).Association ("Toy" ).Clear ()
187+ 
188+ 		var  pet2  Pet 
189+ 		DB .Preload ("Toy" ).First (& pet2 , pet .ID )
190+ 		if  pet2 .Toy .Name  !=  ""  {
191+ 			t .Fatalf ("expected Toy cleared, got %v" , pet2 .Toy .Name )
192+ 		}
193+ 	})
194+ 
195+ 	t .Run ("UpdateWithoutAssociation" , func (t  * testing.T ) {
196+ 		user  :=  * GetUser ("no-assoc-update" , Config {})
197+ 		if  err  :=  DB .Create (& user ).Error ; err  !=  nil  {
198+ 			t .Fatalf ("errors happened when create user: %v" , err )
199+ 		}
200+ 		newName  :=  user .Name  +  "-updated" 
201+ 		if  err  :=  DB .Model (& user ).Update ("name" , newName ).Error ; err  !=  nil  {
202+ 			t .Fatalf ("errors happened when updating only parent: %v" , err )
203+ 		}
204+ 		var  result  User 
205+ 		DB .Preload ("Account" ).First (& result , user .ID )
206+ 		if  result .Name  !=  newName  {
207+ 			t .Fatalf ("user name not updated as expected" )
208+ 		}
209+ 		if  result .Account .ID  !=  0  {
210+ 			t .Fatalf ("expected no Account associated, got ID %v" , result .Account .ID )
211+ 		}
212+ 	})
213+ 
131214	t .Run ("Restriction" , func (t  * testing.T ) {
132215		type  CustomizeAccount  struct  {
133216			gorm.Model 
@@ -175,4 +258,201 @@ func TestUpdateHasOne(t *testing.T) {
175258		tests .AssertEqual (t , account2 .Number , number )
176259		tests .AssertEqual (t , account2 .Number2 , cusUser .Account .Number2 )
177260	})
261+ 
262+ 	t .Run ("AssociationWithoutPreload" , func (t  * testing.T ) {
263+ 		user  :=  * GetUser ("no-preload" , Config {})
264+ 		user .Account  =  Account {AccountNumber : "np-account" }
265+ 		DB .Create (& user )
266+ 
267+ 		var  result  User 
268+ 		DB .First (& result , user .ID ) // no preload 
269+ 		if  result .Account .AccountNumber  !=  ""  {
270+ 			t .Fatalf ("expected Account field empty without preload, got %v" , result .Account .AccountNumber )
271+ 		}
272+ 
273+ 		var  acc  Account 
274+ 		DB .First (& acc , "\" user_id\"  = ?" , user .ID )
275+ 		if  acc .AccountNumber  !=  "np-account"  {
276+ 			t .Fatalf ("account not found as expected" )
277+ 		}
278+ 	})
279+ 
280+ 	t .Run ("SkipFullSaveAssociations" , func (t  * testing.T ) {
281+ 		user  :=  * GetUser ("skip-fsa" , Config {})
282+ 		user .Account  =  Account {AccountNumber : "skipfsa" }
283+ 		DB .Create (& user )
284+ 
285+ 		user .Account .AccountNumber  =  "should-not-update" 
286+ 		if  err  :=  DB .Session (& gorm.Session {FullSaveAssociations : false }).Save (& user ).Error ; err  !=  nil  {
287+ 			t .Fatalf ("error saving with FSA false: %v" , err )
288+ 		}
289+ 
290+ 		var  acc  Account 
291+ 		DB .First (& acc , "\" user_id\"  = ?" , user .ID )
292+ 		if  acc .AccountNumber  !=  "skipfsa"  {
293+ 			t .Fatalf ("account should not have updated, got %v" , acc .AccountNumber )
294+ 		}
295+ 	})
296+ 
297+ 	t .Run ("HasOneZeroForeignKey" , func (t  * testing.T ) {
298+ 		now  :=  time .Now ()
299+ 		user  :=  User {Name : "zero-value-clear" , Age : 18 , Birthday : & now }
300+ 		DB .Create (& user )
301+ 
302+ 		account  :=  Account {AccountNumber : "to-clear" , UserID : sql.NullInt64 {Int64 : int64 (user .ID ), Valid : true }}
303+ 		DB .Create (& account )
304+ 
305+ 		account .UserID  =  sql.NullInt64 {Int64 : 0 , Valid : false }
306+ 		DB .Model (& account ).Select ("UserID" ).Updates (account )
307+ 
308+ 		var  result  User 
309+ 		DB .Preload ("Account" ).First (& result , user .ID )
310+ 		if  result .Account .AccountNumber  !=  ""  {
311+ 			t .Fatalf ("expected account cleared, got %v" , result .Account .AccountNumber )
312+ 		}
313+ 	})
314+ 
315+ 	t .Run ("PolymorphicZeroForeignKey" , func (t  * testing.T ) {
316+ 		pet  :=  Pet {Name : "poly-zero" }
317+ 		pet .Toy  =  Toy {Name : "polytoy-zero" }
318+ 		DB .Create (& pet )
319+ 
320+ 		pet .Toy .OwnerID  =  "" 
321+ 		DB .Model (& pet .Toy ).Select ("OwnerID" ).Updates (& pet .Toy )
322+ 
323+ 		var  pet2  Pet 
324+ 		DB .Preload ("Toy" ).First (& pet2 , pet .ID )
325+ 		if  pet2 .Toy .Name  !=  ""  {
326+ 			t .Fatalf ("expected polymorphic association cleared, got %v" , pet2 .Toy .Name )
327+ 		}
328+ 	})
329+ 
330+ 	t .Run ("InvalidForeignKey" , func (t  * testing.T ) {
331+ 		acc  :=  Account {AccountNumber : "badfk" , UserID : sql.NullInt64 {Int64 : 99999999 , Valid : true }}
332+ 		err  :=  DB .Create (& acc ).Error 
333+ 		if  err  ==  nil  {
334+ 			t .Fatalf ("expected foreign key constraint error, got nil" )
335+ 		}
336+ 	})
337+ 
338+ 	t .Run ("UpdateWithSelectOmit" , func (t  * testing.T ) {
339+ 		user  :=  * GetUser ("select-omit" , Config {})
340+ 		user .Account  =  Account {AccountNumber : "selomit" }
341+ 		DB .Create (& user )
342+ 
343+ 		user .Name  =  "selomit-updated" 
344+ 		user .Account .AccountNumber  =  "selomit-updated" 
345+ 		if  err  :=  DB .Select ("Name" ).Omit ("Account" ).Save (& user ).Error ; err  !=  nil  {
346+ 			t .Fatalf ("error on select/omit: %v" , err )
347+ 		}
348+ 
349+ 		var  acc  Account 
350+ 		DB .First (& acc , "\" user_id\"  = ?" , user .ID )
351+ 		if  acc .AccountNumber  !=  "selomit"  {
352+ 			t .Fatalf ("account should not update with Omit(Account), got %v" , acc .AccountNumber )
353+ 		}
354+ 	})
355+ 
356+ 	t .Run ("NestedUpdate" , func (t  * testing.T ) {
357+ 		user  :=  * GetUser ("nested-update" , Config {})
358+ 		user .Account  =  Account {AccountNumber : "nested" }
359+ 		DB .Create (& user )
360+ 
361+ 		user .Name  =  "nested-updated" 
362+ 		user .Account .AccountNumber  =  "nested-updated" 
363+ 		if  err  :=  DB .Session (& gorm.Session {FullSaveAssociations : true }).Updates (& user ).Error ; err  !=  nil  {
364+ 			t .Fatalf ("nested update failed: %v" , err )
365+ 		}
366+ 
367+ 		var  result  User 
368+ 		DB .Preload ("Account" ).First (& result , user .ID )
369+ 		if  result .Name  !=  "nested-updated"  ||  result .Account .AccountNumber  !=  "nested-updated"  {
370+ 			t .Fatalf ("nested update didn't apply: %v / %v" , result .Name , result .Account .AccountNumber )
371+ 		}
372+ 	})
373+ 
374+ 	t .Run ("EmptyStructNoFullSave" , func (t  * testing.T ) {
375+ 		user  :=  * GetUser ("empty-nofsa" , Config {})
376+ 		user .Account  =  Account {AccountNumber : "keep" }
377+ 		DB .Create (& user )
378+ 
379+ 		user .Account  =  Account {}
380+ 		if  err  :=  DB .Save (& user ).Error ; err  !=  nil  {
381+ 			t .Fatalf ("save failed: %v" , err )
382+ 		}
383+ 
384+ 		var  result  User 
385+ 		DB .Preload ("Account" ).First (& result , user .ID )
386+ 		if  result .Account .AccountNumber  !=  "keep"  {
387+ 			t .Fatalf ("account should not be cleared without FullSaveAssociations" )
388+ 		}
389+ 	})
390+ 
391+ 	t .Run ("DeleteParentCascade" , func (t  * testing.T ) {
392+ 		type  AccountCascadeDelete  struct  {
393+ 			gorm.Model 
394+ 			AccountNumber  string 
395+ 			UserID         uint 
396+ 		}
397+ 
398+ 		type  UserCascadeDelete  struct  {
399+ 			gorm.Model 
400+ 			Name     string 
401+ 			Account  AccountCascadeDelete  `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE;"` 
402+ 		}
403+ 
404+ 		DB .Migrator ().DropTable (& AccountCascadeDelete {}, & UserCascadeDelete {})
405+ 		if  err  :=  DB .AutoMigrate (& UserCascadeDelete {}, & AccountCascadeDelete {}); err  !=  nil  {
406+ 			t .Fatalf ("failed to migrate: %v" , err )
407+ 		}
408+ 
409+ 		user  :=  UserCascadeDelete {
410+ 			Name : "delete-parent" ,
411+ 			Account : AccountCascadeDelete {
412+ 				AccountNumber : "cascade" ,
413+ 			},
414+ 		}
415+ 
416+ 		if  err  :=  DB .Create (& user ).Error ; err  !=  nil  {
417+ 			t .Fatalf ("failed to create user: %v" , err )
418+ 		}
419+ 
420+ 		if  err  :=  DB .Unscoped ().Delete (& user ).Error ; err  !=  nil  {
421+ 			t .Fatalf ("delete parent failed: %v" , err )
422+ 		}
423+ 
424+ 		var  acc  AccountCascadeDelete 
425+ 		err  :=  DB .First (& acc , "\" user_id\"  = ?" , user .ID ).Error 
426+ 		if  ! errors .Is (err , gorm .ErrRecordNotFound ) {
427+ 			t .Fatalf ("expected account deleted, got %v" , acc )
428+ 		}
429+ 	})
430+ 
431+ 	t .Run ("OmitAllAssociations" , func (t  * testing.T ) {
432+ 		user  :=  * GetUser ("omit-assoc" , Config {})
433+ 		user .Account  =  Account {AccountNumber : "original-child" }
434+ 		if  err  :=  DB .Create (& user ).Error ; err  !=  nil  {
435+ 			t .Fatalf ("failed to create user: %v" , err )
436+ 		}
437+ 
438+ 		newName  :=  "parent-updated" 
439+ 		user .Name  =  newName 
440+ 		user .Account .AccountNumber  =  "child-updated" 
441+ 
442+ 		if  err  :=  DB .Model (& user ).Omit (clause .Associations ).Updates (user ).Error ; err  !=  nil  {
443+ 			t .Fatalf ("update with omit associations failed: %v" , err )
444+ 		}
445+ 
446+ 		var  result  User 
447+ 		DB .Preload ("Account" ).First (& result , user .ID )
448+ 
449+ 		if  result .Name  !=  newName  {
450+ 			t .Fatalf ("expected parent name updated to %v, got %v" , newName , result .Name )
451+ 		}
452+ 
453+ 		if  result .Account .AccountNumber  !=  "original-child"  {
454+ 			t .Fatalf ("expected child to remain unchanged, got %v" , result .Account .AccountNumber )
455+ 		}
456+ 	})
457+ 
178458}
0 commit comments