Skip to content

Commit 6085afd

Browse files
murali-dbclaude
andcommitted
Add nested array nullability change tests
Add comprehensive test cases for nested array nullability changes: - test_nested_array_nullability_loosened: outer array element nullability loosened - test_nested_array_nullability_tightened: outer array element nullability tightened - test_nested_array_inner_nullability_loosened: inner array element nullability loosened - test_nested_array_inner_nullability_tightened: inner array element nullability tightened These tests verify that nested array nullability changes are correctly detected and classified as breaking or non-breaking changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a30f427 commit 6085afd

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

kernel/src/schema/diff.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,174 @@ mod tests {
13861386
assert!(diff.has_breaking_changes()); // Type change is breaking
13871387
}
13881388

1389+
#[test]
1390+
fn test_nested_array_nullability_loosened() {
1391+
// Test: array<array<int> not null> -> array<array<int>>
1392+
// Outer array element nullability loosened (safe change)
1393+
let before = StructType::new_unchecked([create_field_with_id(
1394+
"matrix",
1395+
DataType::Array(Box::new(ArrayType::new(
1396+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))),
1397+
false, // Outer array elements are non-nullable
1398+
))),
1399+
false,
1400+
1,
1401+
)]);
1402+
1403+
let after = StructType::new_unchecked([create_field_with_id(
1404+
"matrix",
1405+
DataType::Array(Box::new(ArrayType::new(
1406+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))),
1407+
true, // Outer array elements now nullable
1408+
))),
1409+
false,
1410+
1,
1411+
)]);
1412+
1413+
let diff = SchemaDiffArgs {
1414+
before: &before,
1415+
after: &after,
1416+
}
1417+
.compute_diff()
1418+
.unwrap();
1419+
1420+
assert_eq!(diff.added_fields.len(), 0);
1421+
assert_eq!(diff.removed_fields.len(), 0);
1422+
assert_eq!(diff.updated_fields.len(), 1);
1423+
assert_eq!(diff.updated_fields[0].path, ColumnName::new(["matrix"]));
1424+
assert_eq!(
1425+
diff.updated_fields[0].change_type,
1426+
FieldChangeType::ContainerNullabilityLoosened
1427+
);
1428+
assert!(!diff.has_breaking_changes()); // Loosening is safe
1429+
}
1430+
1431+
#[test]
1432+
fn test_nested_array_nullability_tightened() {
1433+
// Test: array<array<int>> -> array<array<int> not null>
1434+
// Outer array element nullability tightened (breaking change)
1435+
let before = StructType::new_unchecked([create_field_with_id(
1436+
"matrix",
1437+
DataType::Array(Box::new(ArrayType::new(
1438+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))),
1439+
true, // Outer array elements are nullable
1440+
))),
1441+
false,
1442+
1,
1443+
)]);
1444+
1445+
let after = StructType::new_unchecked([create_field_with_id(
1446+
"matrix",
1447+
DataType::Array(Box::new(ArrayType::new(
1448+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))),
1449+
false, // Outer array elements now non-nullable
1450+
))),
1451+
false,
1452+
1,
1453+
)]);
1454+
1455+
let diff = SchemaDiffArgs {
1456+
before: &before,
1457+
after: &after,
1458+
}
1459+
.compute_diff()
1460+
.unwrap();
1461+
1462+
assert_eq!(diff.added_fields.len(), 0);
1463+
assert_eq!(diff.removed_fields.len(), 0);
1464+
assert_eq!(diff.updated_fields.len(), 1);
1465+
assert_eq!(diff.updated_fields[0].path, ColumnName::new(["matrix"]));
1466+
assert_eq!(
1467+
diff.updated_fields[0].change_type,
1468+
FieldChangeType::ContainerNullabilityTightened
1469+
);
1470+
assert!(diff.has_breaking_changes()); // Tightening is breaking
1471+
}
1472+
1473+
#[test]
1474+
fn test_nested_array_inner_nullability_loosened() {
1475+
// Test: array<array<int not null>> -> array<array<int>>
1476+
// Inner array element nullability loosened (safe change)
1477+
let before = StructType::new_unchecked([create_field_with_id(
1478+
"matrix",
1479+
DataType::Array(Box::new(ArrayType::new(
1480+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))), // Inner elements non-nullable
1481+
false,
1482+
))),
1483+
false,
1484+
1,
1485+
)]);
1486+
1487+
let after = StructType::new_unchecked([create_field_with_id(
1488+
"matrix",
1489+
DataType::Array(Box::new(ArrayType::new(
1490+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, true))), // Inner elements now nullable
1491+
false,
1492+
))),
1493+
false,
1494+
1,
1495+
)]);
1496+
1497+
let diff = SchemaDiffArgs {
1498+
before: &before,
1499+
after: &after,
1500+
}
1501+
.compute_diff()
1502+
.unwrap();
1503+
1504+
assert_eq!(diff.added_fields.len(), 0);
1505+
assert_eq!(diff.removed_fields.len(), 0);
1506+
assert_eq!(diff.updated_fields.len(), 1);
1507+
assert_eq!(diff.updated_fields[0].path, ColumnName::new(["matrix"]));
1508+
assert_eq!(
1509+
diff.updated_fields[0].change_type,
1510+
FieldChangeType::ContainerNullabilityLoosened
1511+
);
1512+
assert!(!diff.has_breaking_changes()); // Loosening is safe
1513+
}
1514+
1515+
#[test]
1516+
fn test_nested_array_inner_nullability_tightened() {
1517+
// Test: array<array<int>> -> array<array<int not null>>
1518+
// Inner array element nullability tightened (breaking change)
1519+
let before = StructType::new_unchecked([create_field_with_id(
1520+
"matrix",
1521+
DataType::Array(Box::new(ArrayType::new(
1522+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, true))), // Inner elements nullable
1523+
false,
1524+
))),
1525+
false,
1526+
1,
1527+
)]);
1528+
1529+
let after = StructType::new_unchecked([create_field_with_id(
1530+
"matrix",
1531+
DataType::Array(Box::new(ArrayType::new(
1532+
DataType::Array(Box::new(ArrayType::new(DataType::INTEGER, false))), // Inner elements now non-nullable
1533+
false,
1534+
))),
1535+
false,
1536+
1,
1537+
)]);
1538+
1539+
let diff = SchemaDiffArgs {
1540+
before: &before,
1541+
after: &after,
1542+
}
1543+
.compute_diff()
1544+
.unwrap();
1545+
1546+
assert_eq!(diff.added_fields.len(), 0);
1547+
assert_eq!(diff.removed_fields.len(), 0);
1548+
assert_eq!(diff.updated_fields.len(), 1);
1549+
assert_eq!(diff.updated_fields[0].path, ColumnName::new(["matrix"]));
1550+
assert_eq!(
1551+
diff.updated_fields[0].change_type,
1552+
FieldChangeType::ContainerNullabilityTightened
1553+
);
1554+
assert!(diff.has_breaking_changes()); // Tightening is breaking
1555+
}
1556+
13891557
#[test]
13901558
fn test_map_value_struct_field_changes() {
13911559
let before = StructType::new_unchecked([create_field_with_id(

0 commit comments

Comments
 (0)