fix: Assigning nil value to *uuid.UUID field in Updates
This PR adds handling for the assignment of a nil value to a *uuid.UUID field (resolved as a reflect.Ptr to a reflect.Array), to ensure that the model object reflects the correct value after Updates() has completed. This PR also adds few supporting test cases for Updates() with a map and uuid.UUID column.
This commit is contained in:
		
							parent
							
								
									a9d27293de
								
							
						
					
					
						commit
						debc5f179e
					
				| @ -896,7 +896,9 @@ func (field *Field) setupValuerAndSetter() { | ||||
| 					if !reflectV.IsValid() { | ||||
| 						field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem()) | ||||
| 					} else if reflectV.Kind() == reflect.Ptr && reflectV.IsNil() { | ||||
| 						return | ||||
| 						if field.FieldType.Elem().Kind() == reflect.Array && field.OwnerSchema == nil { | ||||
| 							field.ReflectValueOf(ctx, value).Set(reflectV) | ||||
| 						} | ||||
| 					} else if reflectV.Type().AssignableTo(field.FieldType) { | ||||
| 						field.ReflectValueOf(ctx, value).Set(reflectV) | ||||
| 					} else if reflectV.Kind() == reflect.Ptr { | ||||
|  | ||||
| @ -101,12 +101,12 @@ func TestConnPoolWrapper(t *testing.T) { | ||||
| 		db: nativeDB, | ||||
| 		expect: []string{ | ||||
| 			"SELECT VERSION()", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`) VALUES (?,?,?,?,?,?,?,?,?)", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`,`user_uuid`) VALUES (?,?,?,?,?,?,?,?,?,?)", | ||||
| 			"SELECT * FROM `users` WHERE name = ? AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT ?", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`) VALUES (?,?,?,?,?,?,?,?,?)", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`,`user_uuid`) VALUES (?,?,?,?,?,?,?,?,?,?)", | ||||
| 			"SELECT * FROM `users` WHERE name = ? AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT ?", | ||||
| 			"SELECT * FROM `users` WHERE name = ? AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT ?", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`) VALUES (?,?,?,?,?,?,?,?,?)", | ||||
| 			"INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`,`user_uuid`) VALUES (?,?,?,?,?,?,?,?,?,?)", | ||||
| 			"SELECT * FROM `users` WHERE name = ? AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT ?", | ||||
| 			"SELECT * FROM `users` WHERE name = ? AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT ?", | ||||
| 		}, | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/google/uuid" | ||||
| 	"gorm.io/gorm" | ||||
| 	. "gorm.io/gorm/utils/tests" | ||||
| ) | ||||
| @ -114,6 +115,7 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) { | ||||
| 		ContentPtr  *Content | ||||
| 		Birthday    time.Time | ||||
| 		BirthdayPtr *time.Time | ||||
| 		AuthorUUID  *uuid.UUID | ||||
| 	} | ||||
| 
 | ||||
| 	type HNPost struct { | ||||
|  | ||||
| @ -7,6 +7,7 @@ require ( | ||||
| 	github.com/jinzhu/now v1.1.5 | ||||
| 	github.com/lib/pq v1.10.9 | ||||
| 	github.com/stretchr/testify v1.9.0 | ||||
| 	gorm.io/datatypes v1.2.2 | ||||
| 	gorm.io/driver/mysql v1.5.7 | ||||
| 	gorm.io/driver/postgres v1.5.10 | ||||
| 	gorm.io/driver/sqlite v1.5.6 | ||||
|  | ||||
| @ -158,7 +158,7 @@ func TestDryRun(t *testing.T) { | ||||
| 	dryRunDB := DB.Session(&gorm.Session{DryRun: true}) | ||||
| 
 | ||||
| 	stmt := dryRunDB.Create(&user).Statement | ||||
| 	if stmt.SQL.String() == "" || len(stmt.Vars) != 9 { | ||||
| 	if stmt.SQL.String() == "" || len(stmt.Vars) != 10 { | ||||
| 		t.Errorf("Failed to generate sql, got %v", stmt.SQL.String()) | ||||
| 	} | ||||
| 
 | ||||
| @ -403,7 +403,7 @@ func TestToSQL(t *testing.T) { | ||||
| 	sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { | ||||
| 		return tx.Model(&User{}).Create(user) | ||||
| 	}) | ||||
| 	assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) | ||||
| 	assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active","user_uuid") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false,NULL) RETURNING "id"`, sql) | ||||
| 
 | ||||
| 	// save
 | ||||
| 	user = &User{Name: "foo", Age: 20} | ||||
| @ -412,7 +412,7 @@ func TestToSQL(t *testing.T) { | ||||
| 	sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { | ||||
| 		return tx.Model(&User{}).Save(user) | ||||
| 	}) | ||||
| 	assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) | ||||
| 	assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active","user_uuid") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false,NULL) RETURNING "id"`, sql) | ||||
| 
 | ||||
| 	// updates
 | ||||
| 	user = &User{Name: "bar", Age: 22} | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"gorm.io/datatypes" | ||||
| 	"gorm.io/gorm" | ||||
| 	"gorm.io/gorm/clause" | ||||
| 	"gorm.io/gorm/utils" | ||||
| @ -183,6 +184,38 @@ func TestUpdates(t *testing.T) { | ||||
| 
 | ||||
| 	user3.Age += 100 | ||||
| 	AssertObjEqual(t, user4, user3, "UpdatedAt", "Age") | ||||
| 
 | ||||
| 	// Updates() with map and datatypes.UUID - Case 1 - Update with UUID value
 | ||||
| 	uuidVal := datatypes.NewUUIDv4() | ||||
| 	tx := DB.Model(&user4) | ||||
| 	uuidErr := tx.Updates(map[string]interface{}{"user_uuid": uuidVal}).Error | ||||
| 	if uuidErr != nil { | ||||
| 		t.Errorf("No error should occur while updating with UUID value, but got %v", uuidErr) | ||||
| 	} | ||||
| 	// Expecting the model object (user4) to reflect the UUID value assignment.
 | ||||
| 	AssertEqual(t, user4.UserUUID, uuidVal) | ||||
| 
 | ||||
| 	// Updates() with map and datatypes.UUID - Case 2 - Update with UUID nil pointer
 | ||||
| 	var nilUUIDPtr *datatypes.UUID = nil | ||||
| 	uuidErr = tx.Updates(map[string]interface{}{"user_uuid": nilUUIDPtr}).Error | ||||
| 	if uuidErr != nil { | ||||
| 		t.Errorf("No error should occur while updating with nil UUID pointer, but got %v", uuidErr) | ||||
| 	} | ||||
| 	// Expecting the model object (user4) to reflect the UUID nil pointer assignment.
 | ||||
| 	AssertEqual(t, user4.UserUUID, nilUUIDPtr) | ||||
| 
 | ||||
| 	// Updates() with map and datatypes.UUID - Case 3 - Update with a non-nil UUID pointer
 | ||||
| 	uuidVal2 := datatypes.NewUUIDv1() | ||||
| 	if uuidErr != nil { | ||||
| 		t.Errorf("No error should occur while generating UUID, but got %v", uuidErr) | ||||
| 	} | ||||
| 	var nonNilUUIDPtr *datatypes.UUID = &uuidVal2 | ||||
| 	uuidErr = tx.Updates(map[string]interface{}{"user_uuid": nonNilUUIDPtr}).Error | ||||
| 	if uuidErr != nil { | ||||
| 		t.Errorf("No error should occur while updating with non-nil UUID pointer, but got %v", uuidErr) | ||||
| 	} | ||||
| 	// Expecting the model object (user4) to reflect the non-nil UUID pointer assignment.
 | ||||
| 	AssertEqual(t, user4.UserUUID, nonNilUUIDPtr) | ||||
| } | ||||
| 
 | ||||
| func TestUpdateColumn(t *testing.T) { | ||||
|  | ||||
| @ -4,6 +4,7 @@ import ( | ||||
| 	"database/sql" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"gorm.io/datatypes" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
| 
 | ||||
| @ -30,6 +31,7 @@ type User struct { | ||||
| 	Languages []Language `gorm:"many2many:UserSpeak;"` | ||||
| 	Friends   []*User    `gorm:"many2many:user_friends;"` | ||||
| 	Active    bool | ||||
| 	UserUUID  *datatypes.UUID | ||||
| } | ||||
| 
 | ||||
| type Account struct { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Omkar P
						Omkar P