@@ -908,6 +908,89 @@ mod test {
908
908
assert_eq ! ( result, vec![ None ; 0 ] ) ;
909
909
}
910
910
911
+ #[ test]
912
+ fn test_field_name_fallback_when_id_unavailable ( ) {
913
+ // Create an Arrow struct array with fields that don't have field IDs in metadata
914
+ let int32_array = Int32Array :: from ( vec ! [ Some ( 1 ) , Some ( 2 ) , None ] ) ;
915
+ let string_array = StringArray :: from ( vec ! [ Some ( "hello" ) , Some ( "world" ) , None ] ) ;
916
+
917
+ let struct_array =
918
+ Arc :: new ( StructArray :: from ( vec ! [
919
+ (
920
+ // Field without field ID metadata - should fallback to name matching
921
+ Arc :: new( Field :: new( "field_a" , DataType :: Int32 , true ) ) ,
922
+ Arc :: new( int32_array) as ArrayRef ,
923
+ ) ,
924
+ (
925
+ // Field with wrong field ID metadata - should fallback to name matching
926
+ Arc :: new( Field :: new( "field_b" , DataType :: Utf8 , true ) . with_metadata(
927
+ HashMap :: from( [ ( PARQUET_FIELD_ID_META_KEY . to_string( ) , "999" . to_string( ) ) ] ) ,
928
+ ) ) ,
929
+ Arc :: new( string_array) as ArrayRef ,
930
+ ) ,
931
+ ] ) ) as ArrayRef ;
932
+
933
+ // Create Iceberg struct type with field IDs that don't match the Arrow metadata
934
+ let iceberg_struct_type = StructType :: new ( vec ! [
935
+ Arc :: new( NestedField :: optional(
936
+ 1 , // Different ID than what's in Arrow metadata (or no metadata)
937
+ "field_a" , // Same name as Arrow field
938
+ Type :: Primitive ( PrimitiveType :: Int ) ,
939
+ ) ) ,
940
+ Arc :: new( NestedField :: optional(
941
+ 2 , // Different ID than what's in Arrow metadata (999)
942
+ "field_b" , // Same name as Arrow field
943
+ Type :: Primitive ( PrimitiveType :: String ) ,
944
+ ) ) ,
945
+ ] ) ;
946
+
947
+ // This should succeed by falling back to field name matching
948
+ let result = arrow_struct_to_literal ( & struct_array, & iceberg_struct_type) . unwrap ( ) ;
949
+
950
+ assert_eq ! ( result, vec![
951
+ Some ( Literal :: Struct ( Struct :: from_iter( vec![
952
+ Some ( Literal :: int( 1 ) ) ,
953
+ Some ( Literal :: string( "hello" . to_string( ) ) ) ,
954
+ ] ) ) ) ,
955
+ Some ( Literal :: Struct ( Struct :: from_iter( vec![
956
+ Some ( Literal :: int( 2 ) ) ,
957
+ Some ( Literal :: string( "world" . to_string( ) ) ) ,
958
+ ] ) ) ) ,
959
+ Some ( Literal :: Struct ( Struct :: from_iter( vec![ None , None , ] ) ) ) ,
960
+ ] ) ;
961
+ }
962
+
963
+ #[ test]
964
+ fn test_field_not_found_error ( ) {
965
+ // Test that we get an appropriate error when neither field ID nor name matches
966
+
967
+ let int32_array = Int32Array :: from ( vec ! [ Some ( 1 ) , Some ( 2 ) ] ) ;
968
+
969
+ let struct_array = Arc :: new ( StructArray :: from ( vec ! [ (
970
+ Arc :: new( Field :: new( "arrow_field_name" , DataType :: Int32 , true ) ) ,
971
+ Arc :: new( int32_array) as ArrayRef ,
972
+ ) ] ) ) as ArrayRef ;
973
+
974
+ // Create Iceberg struct type with field that doesn't match by ID or name
975
+ let iceberg_struct_type = StructType :: new ( vec ! [ Arc :: new( NestedField :: optional(
976
+ 10 ,
977
+ "different_field_name" , // Different name than Arrow field
978
+ Type :: Primitive ( PrimitiveType :: Int ) ,
979
+ ) ) ] ) ;
980
+
981
+ // This should fail with an appropriate error message
982
+ let result = arrow_struct_to_literal ( & struct_array, & iceberg_struct_type) ;
983
+
984
+ assert ! ( result. is_err( ) ) ;
985
+ let error = result. unwrap_err ( ) ;
986
+ assert_eq ! ( error. kind( ) , ErrorKind :: DataInvalid ) ;
987
+ assert ! (
988
+ error. message( ) . contains(
989
+ "Field with id=10 or name=different_field_name not found in struct array"
990
+ )
991
+ ) ;
992
+ }
993
+
911
994
#[ test]
912
995
fn test_complex_nested ( ) {
913
996
// complex nested type for test
0 commit comments