|
12 | 12 | use super::{ColumnMetadataKey, ColumnName, DataType, MetadataValue, StructField, StructType}; |
13 | 13 | use std::collections::{HashMap, HashSet}; |
14 | 14 |
|
| 15 | +/// Feature gate for schema diff functionality. |
| 16 | +/// Set to `false` to ensure incomplete implementations don't activate until all PRs are merged. |
| 17 | +/// Will be removed in the final PR when all tests and implementation are complete. |
| 18 | +const SCHEMA_DIFF_ENABLED: bool = false; |
| 19 | + |
15 | 20 | /// Arguments for computing a schema diff |
16 | 21 | #[derive(Debug, Clone)] |
17 | 22 | pub(crate) struct SchemaDiffArgs<'a> { |
@@ -184,8 +189,18 @@ fn compute_schema_diff( |
184 | 189 | _before: &StructType, |
185 | 190 | _after: &StructType, |
186 | 191 | ) -> Result<SchemaDiff, SchemaDiffError> { |
187 | | - // Stub implementation - returns empty diff |
188 | | - // This allows PR 1 to compile and basic tests to run |
| 192 | + // Feature gate check - prevents activation of incomplete implementation |
| 193 | + // This gate will be removed in the final PR when all functionality is complete |
| 194 | + if !SCHEMA_DIFF_ENABLED { |
| 195 | + return Ok(SchemaDiff { |
| 196 | + added_fields: Vec::new(), |
| 197 | + removed_fields: Vec::new(), |
| 198 | + updated_fields: Vec::new(), |
| 199 | + has_breaking_changes: false, |
| 200 | + }); |
| 201 | + } |
| 202 | + |
| 203 | + // Stub implementation - actual implementation will be added in PR 2 |
189 | 204 | Ok(SchemaDiff { |
190 | 205 | added_fields: Vec::new(), |
191 | 206 | removed_fields: Vec::new(), |
@@ -257,4 +272,52 @@ mod tests { |
257 | 272 | // In PR 2, this will correctly be 3 (1 removed, 1 added, 1 updated) |
258 | 273 | assert_eq!(diff.change_count(), 0); // TEMPORARY: Will be 3 in PR 2 |
259 | 274 | } |
| 275 | + |
| 276 | + #[test] |
| 277 | + fn test_top_level_and_nested_change_filters() { |
| 278 | + // Test that top_level_changes and nested_changes correctly filter by path depth. |
| 279 | + // This test manually constructs a SchemaDiff to exercise the filtering logic. |
| 280 | + |
| 281 | + let top_level_field = create_field_with_id("name", DataType::STRING, false, 1); |
| 282 | + let nested_field = create_field_with_id("street", DataType::STRING, false, 2); |
| 283 | + let deeply_nested_field = create_field_with_id("city", DataType::STRING, false, 3); |
| 284 | + |
| 285 | + // Create a diff with mixed top-level and nested changes |
| 286 | + let diff = SchemaDiff { |
| 287 | + added_fields: vec![ |
| 288 | + FieldChange { |
| 289 | + field: top_level_field.clone(), |
| 290 | + path: ColumnName::new(["name"]), // Top-level (depth 1) |
| 291 | + }, |
| 292 | + FieldChange { |
| 293 | + field: nested_field.clone(), |
| 294 | + path: ColumnName::new(["address", "street"]), // Nested (depth 2) |
| 295 | + }, |
| 296 | + ], |
| 297 | + removed_fields: vec![FieldChange { |
| 298 | + field: deeply_nested_field.clone(), |
| 299 | + path: ColumnName::new(["user", "address", "city"]), // Deeply nested (depth 3) |
| 300 | + }], |
| 301 | + updated_fields: vec![], |
| 302 | + has_breaking_changes: false, |
| 303 | + }; |
| 304 | + |
| 305 | + // Test top_level_changes - should only return depth 1 fields |
| 306 | + let (top_added, top_removed, top_updated) = diff.top_level_changes(); |
| 307 | + assert_eq!(top_added.len(), 1); |
| 308 | + assert_eq!(top_added[0].path, ColumnName::new(["name"])); |
| 309 | + assert_eq!(top_removed.len(), 0); |
| 310 | + assert_eq!(top_updated.len(), 0); |
| 311 | + |
| 312 | + // Test nested_changes - should only return depth > 1 fields |
| 313 | + let (nested_added, nested_removed, nested_updated) = diff.nested_changes(); |
| 314 | + assert_eq!(nested_added.len(), 1); |
| 315 | + assert_eq!(nested_added[0].path, ColumnName::new(["address", "street"])); |
| 316 | + assert_eq!(nested_removed.len(), 1); |
| 317 | + assert_eq!( |
| 318 | + nested_removed[0].path, |
| 319 | + ColumnName::new(["user", "address", "city"]) |
| 320 | + ); |
| 321 | + assert_eq!(nested_updated.len(), 0); |
| 322 | + } |
260 | 323 | } |
0 commit comments