feat: BeforeUpdate hook supports update using struct
This commit is contained in:
		
							parent
							
								
									4a50b36f63
								
							
						
					
					
						commit
						feacf577b3
					
				| @ -32,22 +32,50 @@ func SetupUpdateReflectValue(db *gorm.DB) { | ||||
| // BeforeUpdate before update hooks
 | ||||
| func BeforeUpdate(db *gorm.DB) { | ||||
| 	if db.Error == nil && db.Statement.Schema != nil && !db.Statement.SkipHooks && (db.Statement.Schema.BeforeSave || db.Statement.Schema.BeforeUpdate) { | ||||
| 		callMethod(db, func(value interface{}, tx *gorm.DB) (called bool) { | ||||
| 		callMethod(db, func(value interface{}, tx *gorm.DB) bool { | ||||
| 			var ( | ||||
| 				beforeSaveInterface   BeforeSaveInterface | ||||
| 				isBeforeSaveHook      bool | ||||
| 				beforeUpdateInterface BeforeUpdateInterface | ||||
| 				isBeforeUpdateHook    bool | ||||
| 			) | ||||
| 			if db.Statement.Schema.BeforeSave { | ||||
| 				if i, ok := value.(BeforeSaveInterface); ok { | ||||
| 					called = true | ||||
| 					db.AddError(i.BeforeSave(tx)) | ||||
| 				} | ||||
| 				beforeSaveInterface, isBeforeSaveHook = value.(BeforeSaveInterface) | ||||
| 			} | ||||
| 
 | ||||
| 			if db.Statement.Schema.BeforeUpdate { | ||||
| 				if i, ok := value.(BeforeUpdateInterface); ok { | ||||
| 					called = true | ||||
| 					db.AddError(i.BeforeUpdate(tx)) | ||||
| 				beforeUpdateInterface, isBeforeUpdateHook = value.(BeforeUpdateInterface) | ||||
| 			} | ||||
| 			if !isBeforeSaveHook && !isBeforeUpdateHook { | ||||
| 				return false | ||||
| 			} | ||||
| 
 | ||||
| 			// save a snapshot of the struct before the hook was called
 | ||||
| 			rv := reflect.Indirect(reflect.ValueOf(value)) | ||||
| 			rvSnapshot := reflect.New(rv.Type()).Elem() | ||||
| 			rvSnapshot.Set(rv) | ||||
| 
 | ||||
| 			if isBeforeSaveHook { | ||||
| 				db.AddError(beforeSaveInterface.BeforeSave(tx)) | ||||
| 			} | ||||
| 			if isBeforeUpdateHook { | ||||
| 				db.AddError(beforeUpdateInterface.BeforeUpdate(tx)) | ||||
| 			} | ||||
| 
 | ||||
| 			for _, field := range db.Statement.Schema.Fields { | ||||
| 				if field.PrimaryKey { | ||||
| 					continue | ||||
| 				} | ||||
| 				dbFieldName, ok := field.TagSettings["COLUMN"] | ||||
| 				if !ok { | ||||
| 					continue | ||||
| 				} | ||||
| 				// compare with the snapshot and update the field if there is a difference
 | ||||
| 				if !reflect.DeepEqual(rv.FieldByName(field.Name).Interface(), rvSnapshot.FieldByName(field.Name).Interface()) { | ||||
| 					db.Statement.SetColumn(dbFieldName, rv.FieldByName(field.Name).Interface()) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			return called | ||||
| 			return true | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -609,3 +609,44 @@ func TestPropagateUnscoped(t *testing.T) { | ||||
| 		t.Fatalf("unscoped did not propagate") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type StructUpdate struct { | ||||
| 	ID      uint   `gorm:"column:id;primary_key"` | ||||
| 	Version int    `gorm:"column:version"` | ||||
| 	Name    string `gorm:"column:name"` | ||||
| } | ||||
| 
 | ||||
| func (StructUpdate) TableName() string { | ||||
| 	return "struct_updates" | ||||
| } | ||||
| 
 | ||||
| func (su *StructUpdate) BeforeUpdate(*gorm.DB) error { | ||||
| 	su.Version++ | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func TestBeforeUpdateWithStructColumn(t *testing.T) { | ||||
| 	DB.Migrator().DropTable(&StructUpdate{}) | ||||
| 	DB.AutoMigrate(&StructUpdate{}) | ||||
| 
 | ||||
| 	su := StructUpdate{ | ||||
| 		ID:      1, | ||||
| 		Version: 1, | ||||
| 	} | ||||
| 	err := DB.Create(&su).Error | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("create struct failed: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	err = DB.Model(&su).Update("name", "demoManito").Error | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("update struct failed: %v", err) | ||||
| 	} | ||||
| 	if su.Version != 2 { | ||||
| 		t.Fatalf("update version failed: %v", su.Version) | ||||
| 	} | ||||
| 	err = DB.Find(&su, "id = ?", 1).Error | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("find struct failed: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 demoManito
						demoManito