@@ -325,6 +325,107 @@ private PCollection<Row> ordersUnbounded() {
325325 .buildUnbounded ();
326326 }
327327
328+ @ Test
329+ public void testLeftOuterJoinWithNestedRows () {
330+ Schema nestedSchema =
331+ Schema .builder ().addInt32Field ("nested_int" ).addStringField ("nested_str" ).build ();
332+ Schema lhsSchema = Schema .builder ().addInt32Field ("id" ).addStringField ("val" ).build ();
333+ Schema rhsSchema =
334+ Schema .builder ().addInt32Field ("id" ).addRowField ("nested" , nestedSchema ).build ();
335+
336+ PCollection <Row > lhs =
337+ pipeline .apply (
338+ "lhs" ,
339+ org .apache .beam .sdk .transforms .Create .of (
340+ Row .withSchema (lhsSchema ).addValues (1 , "lhs1" ).build (),
341+ Row .withSchema (lhsSchema ).addValues (2 , "lhs2" ).build ())
342+ .withRowSchema (lhsSchema ));
343+
344+ PCollection <Row > rhs =
345+ pipeline .apply (
346+ "rhs" ,
347+ org .apache .beam .sdk .transforms .Create .of (
348+ Row .withSchema (rhsSchema )
349+ .addValues (1 , Row .withSchema (nestedSchema ).addValues (10 , "nested1" ).build ())
350+ .build ())
351+ .withRowSchema (rhsSchema ));
352+
353+ String sql =
354+ "SELECT lhs.id, lhs.val, rhs.nested FROM lhs LEFT OUTER JOIN rhs ON lhs.id = rhs.id" ;
355+
356+ PCollection <Row > result =
357+ PCollectionTuple .of ("lhs" , lhs ).and ("rhs" , rhs ).apply ("sql" , SqlTransform .query (sql ));
358+
359+ Schema expectedSchema =
360+ Schema .builder ()
361+ .addInt32Field ("id" )
362+ .addStringField ("val" )
363+ .addNullableField ("nested" , Schema .FieldType .row (nestedSchema ))
364+ .build ();
365+
366+ PAssert .that (result )
367+ .containsInAnyOrder (
368+ Row .withSchema (expectedSchema )
369+ .addValues (1 , "lhs1" , Row .withSchema (nestedSchema ).addValues (10 , "nested1" ).build ())
370+ .build (),
371+ Row .withSchema (expectedSchema ).addValues (2 , "lhs2" , null ).build ());
372+
373+ pipeline .run ();
374+ }
375+
376+ @ Test
377+ public void testLeftOuterJoinWithArrayOfNestedRows () {
378+ Schema nestedSchema =
379+ Schema .builder ().addInt32Field ("nested_int" ).addStringField ("nested_str" ).build ();
380+ Schema lhsSchema = Schema .builder ().addInt32Field ("id" ).addStringField ("val" ).build ();
381+ Schema rhsSchema =
382+ Schema .builder ()
383+ .addInt32Field ("id" )
384+ .addArrayField ("nested_list" , Schema .FieldType .row (nestedSchema ))
385+ .build ();
386+
387+ PCollection <Row > lhs =
388+ pipeline .apply (
389+ "lhs" ,
390+ org .apache .beam .sdk .transforms .Create .of (
391+ Row .withSchema (lhsSchema ).addValues (1 , "lhs1" ).build (),
392+ Row .withSchema (lhsSchema ).addValues (2 , "lhs2" ).build ())
393+ .withRowSchema (lhsSchema ));
394+
395+ java .util .List <Row > nestedRows =
396+ java .util .Arrays .asList (
397+ Row .withSchema (nestedSchema ).addValues (10 , "nested1" ).build (),
398+ Row .withSchema (nestedSchema ).addValues (20 , "nested2" ).build ());
399+
400+ PCollection <Row > rhs =
401+ pipeline .apply (
402+ "rhs" ,
403+ org .apache .beam .sdk .transforms .Create .of (
404+ Row .withSchema (rhsSchema ).addValues (1 , nestedRows ).build ())
405+ .withRowSchema (rhsSchema ));
406+
407+ String sql =
408+ "SELECT lhs.id, lhs.val, rhs.nested_list FROM lhs LEFT OUTER JOIN rhs ON lhs.id = rhs.id" ;
409+
410+ PCollection <Row > result =
411+ PCollectionTuple .of ("lhs" , lhs ).and ("rhs" , rhs ).apply ("sql" , SqlTransform .query (sql ));
412+
413+ Schema expectedSchema =
414+ Schema .builder ()
415+ .addInt32Field ("id" )
416+ .addStringField ("val" )
417+ .addNullableField (
418+ "nested_list" , Schema .FieldType .array (Schema .FieldType .row (nestedSchema )))
419+ .build ();
420+
421+ PAssert .that (result )
422+ .containsInAnyOrder (
423+ Row .withSchema (expectedSchema ).addValues (1 , "lhs1" , nestedRows ).build (),
424+ Row .withSchema (expectedSchema ).addValues (2 , "lhs2" , null ).build ());
425+
426+ pipeline .run ();
427+ }
428+
328429 private PCollection <Row > queryFromOrderTables (String sql ) {
329430 return tuple (
330431 "ORDER_DETAILS1" ,
0 commit comments