rusty_schema_diff/migration.rs
1//! Migration plan generation and management
2//!
3//! This module provides types and functionality for generating and managing
4//! schema migration plans.
5
6use serde::{Serialize, Deserialize};
7use crate::analyzer::SchemaChange;
8
9/// Represents a plan for migrating between schema versions
10///
11/// A migration plan contains all the necessary changes required to evolve
12/// from one schema version to another, along with impact analysis.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct MigrationPlan {
15 /// Version of the source schema
16 pub source_version: String,
17
18 /// Version of the target schema
19 pub target_version: String,
20
21 /// List of changes required for migration
22 pub changes: Vec<SchemaChange>,
23
24 /// Impact score (0-100) indicating the magnitude of changes
25 pub impact_score: u8,
26
27 /// Indicates whether this migration contains breaking changes
28 pub is_breaking: bool,
29}
30
31impl MigrationPlan {
32 /// Creates a new migration plan
33 ///
34 /// # Arguments
35 /// * `source_version` - Version identifier of the source schema
36 /// * `target_version` - Version identifier of the target schema
37 /// * `changes` - List of schema changes required for migration
38 ///
39 /// # Returns
40 /// A new MigrationPlan instance with calculated impact scores
41 pub fn new(source_version: String, target_version: String, changes: Vec<SchemaChange>) -> Self {
42 let impact_score = Self::calculate_impact(&changes);
43 let is_breaking = Self::detect_breaking_changes(&changes);
44
45 Self {
46 source_version,
47 target_version,
48 changes,
49 impact_score,
50 is_breaking,
51 }
52 }
53
54 /// Calculates the impact score of the migration
55 ///
56 /// # Arguments
57 /// * `changes` - List of schema changes to analyze
58 ///
59 /// # Returns
60 /// An impact score between 0 and 100
61 fn calculate_impact(changes: &[SchemaChange]) -> u8 {
62 // Simple scoring algorithm
63 let score = changes.iter().map(|change| match change.change_type {
64 crate::analyzer::ChangeType::Addition => 25,
65 crate::analyzer::ChangeType::Removal => 100,
66 crate::analyzer::ChangeType::Modification => 50,
67 crate::analyzer::ChangeType::Rename => 30,
68 }).max().unwrap_or(0);
69
70 score.min(100) as u8
71 }
72
73 /// Detects if the migration contains breaking changes
74 ///
75 /// # Arguments
76 /// * `changes` - List of schema changes to analyze
77 ///
78 /// # Returns
79 /// true if breaking changes are detected, false otherwise
80 fn detect_breaking_changes(changes: &[SchemaChange]) -> bool {
81 changes.iter().any(|change| matches!(
82 change.change_type,
83 crate::analyzer::ChangeType::Removal | crate::analyzer::ChangeType::Modification
84 ))
85 }
86
87 /// Gets a list of breaking changes in the migration plan
88 ///
89 /// # Returns
90 /// A vector of references to breaking changes
91 pub fn breaking_changes(&self) -> Vec<&SchemaChange> {
92 self.changes.iter()
93 .filter(|change| matches!(
94 change.change_type,
95 crate::analyzer::ChangeType::Removal | crate::analyzer::ChangeType::Modification
96 ))
97 .collect()
98 }
99}