Skip to main content

sz_orm_core/
migration_branch.rs

1//! 迁移版本分支模块(v4.1.0,`migration-branch` feature gate)
2//!
3//! 提供多分支并行开发迁移管理:分支创建、合并冲突检测、版本拓扑。
4
5use std::collections::{HashMap, HashSet};
6
7/// 迁移分支
8#[derive(Debug, Clone)]
9pub struct MigrationBranch {
10    /// 分支名
11    pub name: String,
12    /// 基线版本(从哪个版本分叉)
13    pub base_version: String,
14    /// 分支上的迁移版本列表
15    pub versions: Vec<String>,
16    /// 是否已合并
17    pub merged: bool,
18}
19
20impl MigrationBranch {
21    /// 创建新分支
22    pub fn new(name: String, base_version: String) -> Self {
23        Self {
24            name,
25            base_version,
26            versions: Vec::new(),
27            merged: false,
28        }
29    }
30
31    /// 添加迁移版本
32    pub fn add_version(&mut self, version: String) {
33        self.versions.push(version);
34    }
35
36    /// 标记为已合并
37    pub fn mark_merged(&mut self) {
38        self.merged = true;
39    }
40}
41
42/// 合并冲突
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct MergeConflict {
45    /// 冲突类型
46    pub conflict_type: ConflictType,
47    /// 冲突版本
48    pub version: String,
49    /// 源分支
50    pub source_branch: String,
51    /// 描述
52    pub description: String,
53}
54
55/// 冲突类型
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum ConflictType {
58    /// 版本号冲突
59    VersionConflict,
60    /// 依赖冲突
61    DependencyConflict,
62    /// Schema 冲突
63    SchemaConflict,
64}
65
66/// 分支管理器
67pub struct MigrationBranchManager {
68    /// 主干版本
69    main_versions: Vec<String>,
70    /// 分支表
71    branches: HashMap<String, MigrationBranch>,
72}
73
74impl MigrationBranchManager {
75    /// 创建分支管理器
76    pub fn new() -> Self {
77        Self {
78            main_versions: Vec::new(),
79            branches: HashMap::new(),
80        }
81    }
82
83    /// 添加主干版本
84    pub fn add_main_version(&mut self, version: String) {
85        self.main_versions.push(version);
86    }
87
88    /// 创建分支
89    pub fn create_branch(&mut self, name: &str, base_version: &str) -> Result<(), String> {
90        if self.branches.contains_key(name) {
91            return Err(format!("分支 {} 已存在", name));
92        }
93        if !self.main_versions.contains(&base_version.to_string()) {
94            return Err(format!("基线版本 {} 不存在于主干", base_version));
95        }
96        self.branches.insert(
97            name.to_string(),
98            MigrationBranch::new(name.to_string(), base_version.to_string()),
99        );
100        Ok(())
101    }
102
103    /// 在分支上添加迁移版本
104    pub fn add_branch_version(&mut self, branch: &str, version: String) -> Result<(), String> {
105        let b = self
106            .branches
107            .get_mut(branch)
108            .ok_or_else(|| format!("分支 {} 不存在", branch))?;
109        if b.merged {
110            return Err(format!("分支 {} 已合并,不能添加版本", branch));
111        }
112        b.add_version(version);
113        Ok(())
114    }
115
116    /// 检测合并冲突
117    pub fn detect_conflicts(&self, branch: &str) -> Result<Vec<MergeConflict>, String> {
118        let b = self
119            .branches
120            .get(branch)
121            .ok_or_else(|| format!("分支 {} 不存在", branch))?;
122
123        let mut conflicts = Vec::new();
124        let main_set: HashSet<&String> = self.main_versions.iter().collect();
125
126        for version in &b.versions {
127            if main_set.contains(version) {
128                conflicts.push(MergeConflict {
129                    conflict_type: ConflictType::VersionConflict,
130                    version: version.clone(),
131                    source_branch: branch.to_string(),
132                    description: format!("版本 {} 与主干版本冲突", version),
133                });
134            }
135        }
136
137        for (other_name, other_branch) in &self.branches {
138            if other_name == branch {
139                continue;
140            }
141            let other_set: HashSet<&String> = other_branch.versions.iter().collect();
142            for version in &b.versions {
143                if other_set.contains(version) {
144                    conflicts.push(MergeConflict {
145                        conflict_type: ConflictType::VersionConflict,
146                        version: version.clone(),
147                        source_branch: branch.to_string(),
148                        description: format!("版本 {} 与分支 {} 冲突", version, other_name),
149                    });
150                }
151            }
152        }
153
154        Ok(conflicts)
155    }
156
157    /// 合并分支到主干
158    pub fn merge_branch(&mut self, branch: &str) -> Result<Vec<String>, String> {
159        let conflicts = self.detect_conflicts(branch)?;
160        if !conflicts.is_empty() {
161            return Err(format!("合并失败:检测到 {} 个冲突", conflicts.len()));
162        }
163
164        let b = self
165            .branches
166            .get_mut(branch)
167            .ok_or_else(|| format!("分支 {} 不存在", branch))?;
168        if b.merged {
169            return Err(format!("分支 {} 已合并", branch));
170        }
171
172        let merged_versions = b.versions.clone();
173        for version in &merged_versions {
174            self.main_versions.push(version.clone());
175        }
176        b.mark_merged();
177        Ok(merged_versions)
178    }
179
180    /// 获取分支列表
181    pub fn branches(&self) -> Vec<&MigrationBranch> {
182        self.branches.values().collect()
183    }
184
185    /// 获取主干版本数
186    pub fn main_version_count(&self) -> usize {
187        self.main_versions.len()
188    }
189}
190
191impl Default for MigrationBranchManager {
192    fn default() -> Self {
193        Self::new()
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200
201    #[test]
202    fn test_create_branch() {
203        let mut manager = MigrationBranchManager::new();
204        manager.add_main_version("v1".to_string());
205        manager.add_main_version("v2".to_string());
206
207        assert!(manager.create_branch("feature-a", "v1").is_ok());
208        assert!(manager.create_branch("feature-a", "v2").is_err());
209        assert!(manager.create_branch("feature-b", "v3").is_err());
210    }
211
212    #[test]
213    fn test_add_branch_version() {
214        let mut manager = MigrationBranchManager::new();
215        manager.add_main_version("v1".to_string());
216        manager.create_branch("feature-a", "v1").unwrap();
217
218        assert!(manager
219            .add_branch_version("feature-a", "v1.1".to_string())
220            .is_ok());
221        assert!(manager
222            .add_branch_version("nonexistent", "v1.2".to_string())
223            .is_err());
224    }
225
226    #[test]
227    fn test_detect_no_conflicts() {
228        let mut manager = MigrationBranchManager::new();
229        manager.add_main_version("v1".to_string());
230        manager.add_main_version("v2".to_string());
231        manager.create_branch("feature-a", "v1").unwrap();
232        manager
233            .add_branch_version("feature-a", "v1.1".to_string())
234            .unwrap();
235
236        let conflicts = manager.detect_conflicts("feature-a").unwrap();
237        assert!(conflicts.is_empty());
238    }
239
240    #[test]
241    fn test_detect_version_conflict_with_main() {
242        let mut manager = MigrationBranchManager::new();
243        manager.add_main_version("v1".to_string());
244        manager.add_main_version("v2".to_string());
245        manager.create_branch("feature-a", "v1").unwrap();
246        manager
247            .add_branch_version("feature-a", "v2".to_string())
248            .unwrap();
249
250        let conflicts = manager.detect_conflicts("feature-a").unwrap();
251        assert_eq!(conflicts.len(), 1);
252        assert_eq!(conflicts[0].conflict_type, ConflictType::VersionConflict);
253    }
254
255    #[test]
256    fn test_detect_conflict_between_branches() {
257        let mut manager = MigrationBranchManager::new();
258        manager.add_main_version("v1".to_string());
259        manager.create_branch("feature-a", "v1").unwrap();
260        manager.create_branch("feature-b", "v1").unwrap();
261        manager
262            .add_branch_version("feature-a", "v1.1".to_string())
263            .unwrap();
264        manager
265            .add_branch_version("feature-b", "v1.1".to_string())
266            .unwrap();
267
268        let conflicts = manager.detect_conflicts("feature-a").unwrap();
269        assert_eq!(conflicts.len(), 1);
270        assert!(conflicts[0].description.contains("feature-b"));
271    }
272
273    #[test]
274    fn test_merge_branch_success() {
275        let mut manager = MigrationBranchManager::new();
276        manager.add_main_version("v1".to_string());
277        manager.create_branch("feature-a", "v1").unwrap();
278        manager
279            .add_branch_version("feature-a", "v1.1".to_string())
280            .unwrap();
281        manager
282            .add_branch_version("feature-a", "v1.2".to_string())
283            .unwrap();
284
285        let merged = manager.merge_branch("feature-a").unwrap();
286        assert_eq!(merged.len(), 2);
287        assert_eq!(manager.main_version_count(), 3);
288    }
289
290    #[test]
291    fn test_merge_branch_with_conflicts() {
292        let mut manager = MigrationBranchManager::new();
293        manager.add_main_version("v1".to_string());
294        manager.add_main_version("v2".to_string());
295        manager.create_branch("feature-a", "v1").unwrap();
296        manager
297            .add_branch_version("feature-a", "v2".to_string())
298            .unwrap();
299
300        let result = manager.merge_branch("feature-a");
301        assert!(result.is_err());
302    }
303
304    #[test]
305    fn test_merge_already_merged() {
306        let mut manager = MigrationBranchManager::new();
307        manager.add_main_version("v1".to_string());
308        manager.create_branch("feature-a", "v1").unwrap();
309        manager
310            .add_branch_version("feature-a", "v1.1".to_string())
311            .unwrap();
312
313        manager.merge_branch("feature-a").unwrap();
314        let result = manager.merge_branch("feature-a");
315        assert!(result.is_err());
316    }
317
318    #[test]
319    fn test_add_version_after_merge() {
320        let mut manager = MigrationBranchManager::new();
321        manager.add_main_version("v1".to_string());
322        manager.create_branch("feature-a", "v1").unwrap();
323        manager
324            .add_branch_version("feature-a", "v1.1".to_string())
325            .unwrap();
326        manager.merge_branch("feature-a").unwrap();
327
328        let result = manager.add_branch_version("feature-a", "v1.2".to_string());
329        assert!(result.is_err());
330    }
331}