重构 #4
| @@ -346,10 +346,6 @@ func (r *gormPlanRepository) reconcileSubPlans(tx *gorm.DB, plan *models.Plan) e | |||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		// 递归协调子计划节点 |  | ||||||
| 		if err := r.reconcilePlanNode(tx, link.ChildPlan); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var linksToDelete []uint | 	var linksToDelete []uint | ||||||
|   | |||||||
| @@ -836,206 +836,6 @@ func TestUpdatePlan_Reconciliation(t *testing.T) { | |||||||
| 				assert.Equal(t, int64(1), taskCount, "新任务应被创建") | 				assert.Equal(t, int64(1), taskCount, "新任务应被创建") | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			name: "递归更新-深层节点的变更", |  | ||||||
| 			setupDB: func(db *gorm.DB) uint { |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C", ContentType: models.PlanContentTypeTasks}) |  | ||||||
| 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 101}, ParentPlanID: 1, ChildPlanID: 2, ExecutionOrder: 1}) |  | ||||||
| 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 102}, ParentPlanID: 2, ChildPlanID: 3, ExecutionOrder: 1}) |  | ||||||
| 				return 1 |  | ||||||
| 			}, |  | ||||||
| 			buildInput: func(db *gorm.DB) *models.Plan { |  | ||||||
| 				planC := &models.Plan{Model: gorm.Model{ID: 3}, Name: "C Updated", ContentType: models.PlanContentTypeTasks} |  | ||||||
| 				planB := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 2}, |  | ||||||
| 					Name:        "B", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{Model: gorm.Model{ID: 102}, ParentPlanID: 2, ChildPlanID: 3, ChildPlan: planC, ExecutionOrder: 2}}, |  | ||||||
| 				} |  | ||||||
| 				planA := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 1}, |  | ||||||
| 					Name:        "A Updated", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{Model: gorm.Model{ID: 101}, ParentPlanID: 1, ChildPlanID: 2, ChildPlan: planB, ExecutionOrder: 1}}, |  | ||||||
| 				} |  | ||||||
| 				return planA |  | ||||||
| 			}, |  | ||||||
| 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { |  | ||||||
| 				var finalA, finalC models.Plan |  | ||||||
| 				var finalLinkB models.SubPlan |  | ||||||
|  |  | ||||||
| 				db.First(&finalA, 1) |  | ||||||
| 				assert.Equal(t, "A Updated", finalA.Name) |  | ||||||
|  |  | ||||||
| 				db.First(&finalLinkB, 102) |  | ||||||
| 				assert.Equal(t, 2, finalLinkB.ExecutionOrder) |  | ||||||
|  |  | ||||||
| 				db.First(&finalC, 3) |  | ||||||
| 				assert.Equal(t, "C Updated", finalC.Name) |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			name: "递归更新-深层节点的类型转换(C从SubPlans变为Tasks)", |  | ||||||
| 			setupDB: func(db *gorm.DB) uint { |  | ||||||
| 				// 初始状态: A -> B -> C -> D |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C", ContentType: models.PlanContentTypeSubPlans}) // C的初始类型 |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D"}) |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 2}) |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 3}) |  | ||||||
| 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 99}, ParentPlanID: 3, ChildPlanID: 4}) // C->D 的关联 |  | ||||||
| 				return 1 |  | ||||||
| 			}, |  | ||||||
| 			buildInput: func(db *gorm.DB) *models.Plan { |  | ||||||
| 				// 更新操作: C的类型变为Tasks,并增加一个新Task |  | ||||||
| 				planC := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 3}, |  | ||||||
| 					Name:        "C", |  | ||||||
| 					ContentType: models.PlanContentTypeTasks, // 类型变更 |  | ||||||
| 					Tasks:       []models.Task{{Name: "C's New Task"}}, |  | ||||||
| 				} |  | ||||||
| 				planB := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 2}, |  | ||||||
| 					Name:        "B", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 3, ChildPlan: planC}}, |  | ||||||
| 				} |  | ||||||
| 				planA := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 1}, |  | ||||||
| 					Name:        "A", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 2, ChildPlan: planB}}, |  | ||||||
| 				} |  | ||||||
| 				return planA |  | ||||||
| 			}, |  | ||||||
| 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { |  | ||||||
| 				// 1. 验证 C->D 的旧关联已被删除 |  | ||||||
| 				var linkCount int64 |  | ||||||
| 				db.Model(&models.SubPlan{}).Where("id = ?", 99).Count(&linkCount) |  | ||||||
| 				assert.Equal(t, int64(0), linkCount, "C的旧子计划关联应被清理") |  | ||||||
|  |  | ||||||
| 				// 2. 验证 C 的新Task已被创建 |  | ||||||
| 				var task models.Task |  | ||||||
| 				err := db.Where("plan_id = ?", 3).First(&task).Error |  | ||||||
| 				assert.NoError(t, err, "C的新任务应该被创建") |  | ||||||
| 				assert.Equal(t, "C's New Task", task.Name) |  | ||||||
|  |  | ||||||
| 				// 3. 验证 D 计划本身依然存在 |  | ||||||
| 				var planDCount int64 |  | ||||||
| 				db.Model(&models.Plan{}).Where("id = ?", 4).Count(&planDCount) |  | ||||||
| 				assert.Equal(t, int64(1), planDCount, "计划D本身不应被删除") |  | ||||||
| 			}, |  | ||||||
| 		}, { |  | ||||||
| 			name: "递归更新-中间层分支替换(A->B变为A->D)", |  | ||||||
| 			setupDB: func(db *gorm.DB) uint { |  | ||||||
| 				// 初始状态: A -> B -> C |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C"}) |  | ||||||
| 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 101}, ParentPlanID: 1, ChildPlanID: 2}) // A->B |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 3})                             // B->C |  | ||||||
|  |  | ||||||
| 				// 准备用于替换的分支: D -> E |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 5}, Name: "E"}) |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 4, ChildPlanID: 5}) // D->E |  | ||||||
| 				return 1 |  | ||||||
| 			}, |  | ||||||
| 			buildInput: func(db *gorm.DB) *models.Plan { |  | ||||||
| 				// 更新操作: A的子计划从 B 替换为 D |  | ||||||
| 				planE := &models.Plan{Model: gorm.Model{ID: 5}, Name: "E Updated"} // 同时更新深层节点 |  | ||||||
| 				planD := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 4}, |  | ||||||
| 					Name:        "D", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 5, ChildPlan: planE}}, |  | ||||||
| 				} |  | ||||||
| 				planA := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 1}, |  | ||||||
| 					Name:        "A", |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD}}, // 新关联 A->D |  | ||||||
| 				} |  | ||||||
| 				return planA |  | ||||||
| 			}, |  | ||||||
| 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { |  | ||||||
| 				// 1. 验证 A->B 的旧关联已被删除 |  | ||||||
| 				var linkCount int64 |  | ||||||
| 				db.Model(&models.SubPlan{}).Where("id = ?", 101).Count(&linkCount) |  | ||||||
| 				assert.Equal(t, int64(0), linkCount, "A->B 的旧关联应被删除") |  | ||||||
|  |  | ||||||
| 				// 2. 验证 A->D 的新关联已创建 |  | ||||||
| 				var newLink models.SubPlan |  | ||||||
| 				err := db.Where("parent_plan_id = ? AND child_plan_id = ?", 1, 4).First(&newLink).Error |  | ||||||
| 				assert.NoError(t, err, "A->D 的新关联应被创建") |  | ||||||
|  |  | ||||||
| 				// 3. 验证 B, C, D, E 计划本身都依然存在 |  | ||||||
| 				var planCount int64 |  | ||||||
| 				db.Model(&models.Plan{}).Where("id IN ?", []uint{2, 3, 4, 5}).Count(&planCount) |  | ||||||
| 				assert.Equal(t, int64(4), planCount, "所有被引用或解引用的计划本身都不应被删除") |  | ||||||
|  |  | ||||||
| 				// 4. 验证对新分支深层节点的递归更新已生效 |  | ||||||
| 				var finalE models.Plan |  | ||||||
| 				db.First(&finalE, 5) |  | ||||||
| 				assert.Equal(t, "E Updated", finalE.Name) |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			name: "递归更新-菱形依赖下的冲突更新", |  | ||||||
| 			setupDB: func(db *gorm.DB) uint { |  | ||||||
| 				// 初始状态: A -> B -> D, A -> C -> D |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C", ContentType: models.PlanContentTypeSubPlans}) |  | ||||||
| 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Original)"}) // D的初始名字 |  | ||||||
| 				// 创建关联 |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 2, ExecutionOrder: 1}) // A->B |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 3, ExecutionOrder: 2}) // A->C |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 4})                    // B->D |  | ||||||
| 				db.Create(&models.SubPlan{ParentPlanID: 3, ChildPlanID: 4})                    // C->D |  | ||||||
| 				return 1 |  | ||||||
| 			}, |  | ||||||
| 			buildInput: func(db *gorm.DB) *models.Plan { |  | ||||||
| 				// 在一次调用中,通过不同路径对 D 进行不同的更新 |  | ||||||
| 				planD_fromB := &models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Updated from B)"} |  | ||||||
| 				planD_fromC := &models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Updated from C)"} |  | ||||||
|  |  | ||||||
| 				planB := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 2}, |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD_fromB}}, |  | ||||||
| 				} |  | ||||||
| 				planC := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 3}, |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD_fromC}}, |  | ||||||
| 				} |  | ||||||
| 				planA := &models.Plan{ |  | ||||||
| 					Model:       gorm.Model{ID: 1}, |  | ||||||
| 					ContentType: models.PlanContentTypeSubPlans, |  | ||||||
| 					SubPlans: []models.SubPlan{ |  | ||||||
| 						{ChildPlanID: 2, ChildPlan: planB, ExecutionOrder: 1}, |  | ||||||
| 						{ChildPlanID: 3, ChildPlan: planC, ExecutionOrder: 2}, // C 在 B 之后 |  | ||||||
| 					}, |  | ||||||
| 				} |  | ||||||
| 				return planA |  | ||||||
| 			}, |  | ||||||
| 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { |  | ||||||
| 				// 验证:D 的最终名字应该符合“最后一次更新获胜”的原则 |  | ||||||
| 				// 由于 planC 在 planB 之后被处理,D 的名字应该是 "D (Updated from C)" |  | ||||||
| 				var finalD models.Plan |  | ||||||
| 				db.First(&finalD, 4) |  | ||||||
| 				assert.Equal(t, "D (Updated from C)", finalD.Name, "共享下游节点的更新应以后一次执行为准") |  | ||||||
|  |  | ||||||
| 				// 确保所有关联依然存在 |  | ||||||
| 				var linkCount int64 |  | ||||||
| 				db.Model(&models.SubPlan{}).Where("child_plan_id = ?", 4).Count(&linkCount) |  | ||||||
| 				assert.Equal(t, int64(2), linkCount, "D 的两个上游关联都应继续存在") |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, tc := range testCases { | 	for _, tc := range testCases { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user