重构 #4
| @@ -346,10 +346,6 @@ func (r *gormPlanRepository) reconcileSubPlans(tx *gorm.DB, plan *models.Plan) e | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		// 递归协调子计划节点 | ||||
| 		if err := r.reconcilePlanNode(tx, link.ChildPlan); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var linksToDelete []uint | ||||
|   | ||||
| @@ -836,206 +836,6 @@ func TestUpdatePlan_Reconciliation(t *testing.T) { | ||||
| 				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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user