sql_splitter/convert/
warnings.rs1#[derive(Debug, Clone, PartialEq)]
8pub enum ConvertWarning {
9 UnsupportedFeature {
11 feature: String,
12 suggestion: Option<String>,
13 },
14 LossyConversion {
16 from_type: String,
17 to_type: String,
18 table: Option<String>,
19 column: Option<String>,
20 },
21 SkippedStatement {
23 reason: String,
24 statement_preview: String,
25 },
26 CopyNotConverted { table: String },
28}
29
30impl std::fmt::Display for ConvertWarning {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 ConvertWarning::UnsupportedFeature {
34 feature,
35 suggestion,
36 } => {
37 write!(f, "Unsupported feature: {}", feature)?;
38 if let Some(s) = suggestion {
39 write!(f, " ({})", s)?;
40 }
41 Ok(())
42 }
43 ConvertWarning::LossyConversion {
44 from_type,
45 to_type,
46 table,
47 column,
48 } => {
49 write!(f, "Lossy conversion: {} → {}", from_type, to_type)?;
50 if let Some(t) = table {
51 write!(f, " in table {}", t)?;
52 if let Some(c) = column {
53 write!(f, ".{}", c)?;
54 }
55 }
56 Ok(())
57 }
58 ConvertWarning::SkippedStatement {
59 reason,
60 statement_preview,
61 } => {
62 write!(f, "Skipped: {} ({})", reason, statement_preview)
63 }
64 ConvertWarning::CopyNotConverted { table } => {
65 write!(
66 f,
67 "COPY statement for table '{}' not converted - requires INSERT conversion",
68 table
69 )
70 }
71 }
72 }
73}
74
75#[derive(Debug, Default)]
77pub struct WarningCollector {
78 warnings: Vec<ConvertWarning>,
79 max_warnings: usize,
80}
81
82impl WarningCollector {
83 pub fn new() -> Self {
84 Self {
85 warnings: Vec::new(),
86 max_warnings: 100, }
88 }
89
90 pub fn with_limit(limit: usize) -> Self {
91 Self {
92 warnings: Vec::new(),
93 max_warnings: limit,
94 }
95 }
96
97 pub fn add(&mut self, warning: ConvertWarning) {
99 if self.warnings.len() < self.max_warnings {
100 if !self.warnings.iter().any(|w| Self::is_similar(w, &warning)) {
102 self.warnings.push(warning);
103 }
104 }
105 }
106
107 fn is_similar(a: &ConvertWarning, b: &ConvertWarning) -> bool {
109 match (a, b) {
110 (
111 ConvertWarning::UnsupportedFeature { feature: f1, .. },
112 ConvertWarning::UnsupportedFeature { feature: f2, .. },
113 ) => f1 == f2,
114 (
115 ConvertWarning::LossyConversion {
116 from_type: f1,
117 to_type: t1,
118 ..
119 },
120 ConvertWarning::LossyConversion {
121 from_type: f2,
122 to_type: t2,
123 ..
124 },
125 ) => f1 == f2 && t1 == t2,
126 _ => false,
127 }
128 }
129
130 pub fn warnings(&self) -> &[ConvertWarning] {
132 &self.warnings
133 }
134
135 pub fn has_warnings(&self) -> bool {
137 !self.warnings.is_empty()
138 }
139
140 pub fn count(&self) -> usize {
142 self.warnings.len()
143 }
144
145 pub fn print_summary(&self) {
147 if self.warnings.is_empty() {
148 return;
149 }
150
151 eprintln!("\nConversion warnings ({}):", self.warnings.len());
152 for warning in &self.warnings {
153 eprintln!(" ⚠ {}", warning);
154 }
155
156 if self.warnings.len() >= self.max_warnings {
157 eprintln!(" ... (additional warnings truncated)");
158 }
159 }
160}