@@ -162,6 +162,59 @@ public void testNestedNullMappings() {
162162 ((StructType ) convertedNested .getItemType ()).getFields ().get (1 ).getType ());
163163 }
164164
165+ @ Test
166+ public void testDeepNullComposites () {
167+ Field leaf = Field .nullable ("item" , ArrowType .Null .INSTANCE );
168+ Field list = new Field ("item" , FieldType .nullable (ArrowType .List .INSTANCE ),
169+ Collections .singletonList (leaf ));
170+ Field entries = new Field ("entries" , FieldType .notNullable (ArrowType .Struct .INSTANCE ),
171+ Arrays .asList (Field .notNullable ("key" , ArrowType .Utf8 .INSTANCE ), leaf ));
172+ Field map = new Field ("item" , FieldType .nullable (new ArrowType .Map (false )),
173+ Collections .singletonList (entries ));
174+ for (Field child : Arrays .asList (list , map )) {
175+ Type childType = LanceTypeConverter .toDorisType (child );
176+ for (ArrowType outer : Arrays .asList (ArrowType .List .INSTANCE ,
177+ ArrowType .LargeList .INSTANCE , new ArrowType .FixedSizeList (2 ))) {
178+ Field nested = new Field ("nested" , FieldType .nullable (outer ),
179+ Collections .singletonList (child ));
180+ Assertions .assertEquals (new ArrayType (childType ), LanceTypeConverter .toDorisType (nested ));
181+ }
182+ Field struct = new Field ("nested" , FieldType .nullable (ArrowType .Struct .INSTANCE ),
183+ Collections .singletonList (child ));
184+ Type converted = LanceTypeConverter .toDorisType (struct );
185+ Assertions .assertInstanceOf (StructType .class , converted );
186+ Assertions .assertEquals (childType , ((StructType ) converted ).getFields ().get (0 ).getType ());
187+ Field nestedEntries = new Field ("entries" , FieldType .notNullable (ArrowType .Struct .INSTANCE ),
188+ Arrays .asList (Field .notNullable ("key" , ArrowType .Utf8 .INSTANCE ), child ));
189+ Field nestedMap = new Field ("nested" , FieldType .nullable (new ArrowType .Map (false )),
190+ Collections .singletonList (nestedEntries ));
191+ Assertions .assertEquals (new MapType (Type .STRING , childType , false , true ),
192+ LanceTypeConverter .toDorisType (nestedMap ));
193+ }
194+ }
195+
196+ @ Test
197+ public void testNonNullableNullLeavesAreUnsupported () {
198+ Field leaf = Field .notNullable ("item" , ArrowType .Null .INSTANCE );
199+ Assertions .assertEquals (Type .UNSUPPORTED , LanceTypeConverter .toDorisType (leaf ));
200+ for (ArrowType outer : Arrays .asList (ArrowType .List .INSTANCE ,
201+ ArrowType .LargeList .INSTANCE , new ArrowType .FixedSizeList (2 ), ArrowType .Struct .INSTANCE )) {
202+ Field nested = new Field ("nested" , FieldType .nullable (outer ), Collections .singletonList (leaf ));
203+ Assertions .assertEquals (Type .UNSUPPORTED , LanceTypeConverter .toDorisType (nested ));
204+ }
205+ for (boolean nullKey : Arrays .asList (false , true )) {
206+ Field entries = new Field ("entries" , FieldType .notNullable (ArrowType .Struct .INSTANCE ),
207+ Arrays .asList (nullKey ? leaf : Field .notNullable ("key" , ArrowType .Utf8 .INSTANCE ),
208+ nullKey ? Field .nullable ("value" , ArrowType .Utf8 .INSTANCE ) : leaf ));
209+ Field map = new Field ("map" , FieldType .nullable (new ArrowType .Map (false )),
210+ Collections .singletonList (entries ));
211+ Assertions .assertEquals (Type .UNSUPPORTED , LanceTypeConverter .toDorisType (map ));
212+ Field nested = new Field ("nested" , FieldType .nullable (ArrowType .List .INSTANCE ),
213+ Collections .singletonList (map ));
214+ Assertions .assertEquals (Type .UNSUPPORTED , LanceTypeConverter .toDorisType (nested ));
215+ }
216+ }
217+
165218 /** Verifies known extension mappings and storage validation. */
166219 @ Test
167220 public void testKnownExtensionMappingsAndStorageValidation () {
0 commit comments