Skip to content

Commit dc4a4aa

Browse files
murali-dbclaude
andcommitted
Add cursed double-nesting test cases to schema diff tests
Added three complex test cases to test_cursed_deeply_nested_complex_types: - Case 3: array<array<struct>> - doubly nested array with struct elements - Case 4: map<array<struct>, array<struct>> - map with arrays of structs - Case 5: map<struct, map<struct, struct>> - map with nested map and structs These tests verify field changes are correctly detected through extremely complex nested structures with proper path construction and breaking change detection. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6085afd commit dc4a4aa

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed

kernel/src/schema/diff.rs

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,5 +2293,257 @@ mod tests {
22932293
);
22942294

22952295
assert!(!diff2.has_breaking_changes()); // Just a rename
2296+
2297+
// Case 3: array<array<struct<x int>>> - doubly nested array with struct
2298+
let before3 = StructType::new_unchecked([create_field_with_id(
2299+
"matrix",
2300+
DataType::Array(Box::new(ArrayType::new(
2301+
DataType::Array(Box::new(ArrayType::new(
2302+
DataType::try_struct_type([create_field_with_id(
2303+
"x",
2304+
DataType::INTEGER,
2305+
false,
2306+
2,
2307+
)])
2308+
.unwrap(),
2309+
false,
2310+
))),
2311+
false,
2312+
))),
2313+
false,
2314+
1,
2315+
)]);
2316+
2317+
let after3 = StructType::new_unchecked([create_field_with_id(
2318+
"matrix",
2319+
DataType::Array(Box::new(ArrayType::new(
2320+
DataType::Array(Box::new(ArrayType::new(
2321+
DataType::try_struct_type([
2322+
create_field_with_id("renamed_x", DataType::INTEGER, false, 2), // Renamed!
2323+
create_field_with_id("y", DataType::INTEGER, true, 3), // Added!
2324+
])
2325+
.unwrap(),
2326+
false,
2327+
))),
2328+
false,
2329+
))),
2330+
false,
2331+
1,
2332+
)]);
2333+
2334+
let diff3 = SchemaDiffArgs {
2335+
before: &before3,
2336+
after: &after3,
2337+
}
2338+
.compute_diff()
2339+
.unwrap();
2340+
2341+
assert_eq!(diff3.added_fields.len(), 1);
2342+
assert_eq!(diff3.removed_fields.len(), 0);
2343+
assert_eq!(diff3.updated_fields.len(), 1);
2344+
assert_eq!(
2345+
diff3.added_fields[0].path,
2346+
ColumnName::new(["matrix", "element", "element", "y"])
2347+
);
2348+
assert_eq!(
2349+
diff3.updated_fields[0].path,
2350+
ColumnName::new(["matrix", "element", "element", "renamed_x"])
2351+
);
2352+
assert_eq!(
2353+
diff3.updated_fields[0].change_type,
2354+
FieldChangeType::Renamed
2355+
);
2356+
assert!(!diff3.has_breaking_changes()); // Rename and added nullable field
2357+
2358+
// Case 4: map<array<struct<a int>>, array<struct<b int>>> - map with arrays of structs
2359+
let before4 = StructType::new_unchecked([create_field_with_id(
2360+
"complex_map",
2361+
DataType::Map(Box::new(MapType::new(
2362+
DataType::Array(Box::new(ArrayType::new(
2363+
DataType::try_struct_type([create_field_with_id(
2364+
"key_field",
2365+
DataType::INTEGER,
2366+
false,
2367+
2,
2368+
)])
2369+
.unwrap(),
2370+
false,
2371+
))),
2372+
DataType::Array(Box::new(ArrayType::new(
2373+
DataType::try_struct_type([create_field_with_id(
2374+
"value_field",
2375+
DataType::STRING,
2376+
false,
2377+
3,
2378+
)])
2379+
.unwrap(),
2380+
false,
2381+
))),
2382+
false,
2383+
))),
2384+
false,
2385+
1,
2386+
)]);
2387+
2388+
let after4 = StructType::new_unchecked([create_field_with_id(
2389+
"complex_map",
2390+
DataType::Map(Box::new(MapType::new(
2391+
DataType::Array(Box::new(ArrayType::new(
2392+
DataType::try_struct_type([
2393+
create_field_with_id("renamed_key_field", DataType::INTEGER, false, 2), // Renamed!
2394+
])
2395+
.unwrap(),
2396+
false,
2397+
))),
2398+
DataType::Array(Box::new(ArrayType::new(
2399+
DataType::try_struct_type([
2400+
create_field_with_id("renamed_value_field", DataType::STRING, false, 3), // Renamed!
2401+
])
2402+
.unwrap(),
2403+
false,
2404+
))),
2405+
false,
2406+
))),
2407+
false,
2408+
1,
2409+
)]);
2410+
2411+
let diff4 = SchemaDiffArgs {
2412+
before: &before4,
2413+
after: &after4,
2414+
}
2415+
.compute_diff()
2416+
.unwrap();
2417+
2418+
assert_eq!(diff4.added_fields.len(), 0);
2419+
assert_eq!(diff4.removed_fields.len(), 0);
2420+
assert_eq!(diff4.updated_fields.len(), 2);
2421+
2422+
let paths: HashSet<ColumnName> = diff4
2423+
.updated_fields
2424+
.iter()
2425+
.map(|u| u.path.clone())
2426+
.collect();
2427+
assert!(paths.contains(&ColumnName::new([
2428+
"complex_map",
2429+
"key",
2430+
"element",
2431+
"renamed_key_field"
2432+
])));
2433+
assert!(paths.contains(&ColumnName::new([
2434+
"complex_map",
2435+
"value",
2436+
"element",
2437+
"renamed_value_field"
2438+
])));
2439+
assert!(!diff4.has_breaking_changes()); // Just renames
2440+
2441+
// Case 5: map<struct<id int>, map<struct<key int>, struct<data string>>> - map with nested map and structs
2442+
let before5 = StructType::new_unchecked([create_field_with_id(
2443+
"nested_maps",
2444+
DataType::Map(Box::new(MapType::new(
2445+
DataType::try_struct_type([create_field_with_id(
2446+
"outer_key",
2447+
DataType::INTEGER,
2448+
false,
2449+
2,
2450+
)])
2451+
.unwrap(),
2452+
DataType::Map(Box::new(MapType::new(
2453+
DataType::try_struct_type([create_field_with_id(
2454+
"inner_key",
2455+
DataType::INTEGER,
2456+
false,
2457+
3,
2458+
)])
2459+
.unwrap(),
2460+
DataType::try_struct_type([
2461+
create_field_with_id("data", DataType::STRING, false, 4),
2462+
create_field_with_id("removed", DataType::INTEGER, true, 5),
2463+
])
2464+
.unwrap(),
2465+
false,
2466+
))),
2467+
false,
2468+
))),
2469+
false,
2470+
1,
2471+
)]);
2472+
2473+
let after5 = StructType::new_unchecked([create_field_with_id(
2474+
"nested_maps",
2475+
DataType::Map(Box::new(MapType::new(
2476+
DataType::try_struct_type([create_field_with_id(
2477+
"renamed_outer_key", // Renamed!
2478+
DataType::INTEGER,
2479+
false,
2480+
2,
2481+
)])
2482+
.unwrap(),
2483+
DataType::Map(Box::new(MapType::new(
2484+
DataType::try_struct_type([create_field_with_id(
2485+
"renamed_inner_key", // Renamed!
2486+
DataType::INTEGER,
2487+
false,
2488+
3,
2489+
)])
2490+
.unwrap(),
2491+
DataType::try_struct_type([
2492+
create_field_with_id("renamed_data", DataType::STRING, false, 4), // Renamed!
2493+
create_field_with_id("added", DataType::LONG, true, 6), // Added!
2494+
])
2495+
.unwrap(),
2496+
false,
2497+
))),
2498+
false,
2499+
))),
2500+
false,
2501+
1,
2502+
)]);
2503+
2504+
let diff5 = SchemaDiffArgs {
2505+
before: &before5,
2506+
after: &after5,
2507+
}
2508+
.compute_diff()
2509+
.unwrap();
2510+
2511+
assert_eq!(diff5.added_fields.len(), 1);
2512+
assert_eq!(diff5.removed_fields.len(), 1);
2513+
assert_eq!(diff5.updated_fields.len(), 3);
2514+
2515+
assert_eq!(
2516+
diff5.added_fields[0].path,
2517+
ColumnName::new(["nested_maps", "value", "value", "added"])
2518+
);
2519+
assert_eq!(
2520+
diff5.removed_fields[0].path,
2521+
ColumnName::new(["nested_maps", "value", "value", "removed"])
2522+
);
2523+
2524+
let paths: HashSet<ColumnName> = diff5
2525+
.updated_fields
2526+
.iter()
2527+
.map(|u| u.path.clone())
2528+
.collect();
2529+
assert!(paths.contains(&ColumnName::new([
2530+
"nested_maps",
2531+
"key",
2532+
"renamed_outer_key"
2533+
])));
2534+
assert!(paths.contains(&ColumnName::new([
2535+
"nested_maps",
2536+
"value",
2537+
"key",
2538+
"renamed_inner_key"
2539+
])));
2540+
assert!(paths.contains(&ColumnName::new([
2541+
"nested_maps",
2542+
"value",
2543+
"value",
2544+
"renamed_data"
2545+
])));
2546+
2547+
assert!(diff5.has_breaking_changes()); // Removal is breaking
22962548
}
22972549
}

0 commit comments

Comments
 (0)