@@ -380,6 +380,94 @@ def test_e2e_join_left(tmp_path) -> None:
380380 engine .dispose ()
381381
382382
383+ def test_e2e_right_join_raw_sql (tmp_path ) -> None :
384+ engine = _engine_for (tmp_path )
385+ metadata = MetaData ()
386+ users = _users_table (metadata )
387+ orders = Table (
388+ "orders" ,
389+ metadata ,
390+ Column ("id" , Integer , primary_key = True ),
391+ Column ("user_id" , Integer ),
392+ Column ("amount" , Integer ),
393+ )
394+ metadata .create_all (engine )
395+
396+ with engine .begin () as conn :
397+ conn .execute (insert (users ).values (id = 1 , name = "Alice" , age = 30 ))
398+ conn .execute (insert (users ).values (id = 2 , name = "Bob" , age = 25 ))
399+ conn .execute (insert (orders ).values (id = 1 , user_id = 1 , amount = 100 ))
400+
401+ with engine .connect () as conn :
402+ rows = conn .execute (
403+ sa .text (
404+ "SELECT users.name, orders.amount "
405+ "FROM users RIGHT JOIN orders ON users.id = orders.user_id"
406+ )
407+ ).all ()
408+ assert rows == [("Alice" , 100 )]
409+
410+ engine .dispose ()
411+
412+
413+ def test_e2e_full_outer_join_raw_sql (tmp_path ) -> None :
414+ engine = _engine_for (tmp_path )
415+ metadata = MetaData ()
416+ users = _users_table (metadata )
417+ orders = Table (
418+ "orders" ,
419+ metadata ,
420+ Column ("id" , Integer , primary_key = True ),
421+ Column ("user_id" , Integer ),
422+ Column ("amount" , Integer ),
423+ )
424+ metadata .create_all (engine )
425+
426+ with engine .begin () as conn :
427+ conn .execute (insert (users ).values (id = 1 , name = "Alice" , age = 30 ))
428+ conn .execute (insert (users ).values (id = 2 , name = "Bob" , age = 25 ))
429+ conn .execute (insert (orders ).values (id = 1 , user_id = 1 , amount = 100 ))
430+ conn .execute (insert (orders ).values (id = 2 , user_id = 999 , amount = 200 ))
431+
432+ with engine .connect () as conn :
433+ rows = conn .execute (
434+ sa .text (
435+ "SELECT users.name, orders.amount "
436+ "FROM users FULL OUTER JOIN orders ON users.id = orders.user_id"
437+ )
438+ ).all ()
439+ assert set (rows ) == {("Alice" , 100 ), ("Bob" , None ), (None , 200 )}
440+
441+ engine .dispose ()
442+
443+
444+ def test_e2e_cross_join_raw_sql (tmp_path ) -> None :
445+ engine = _engine_for (tmp_path )
446+ metadata = MetaData ()
447+ users = _users_table (metadata )
448+ teams = Table (
449+ "teams" ,
450+ metadata ,
451+ Column ("id" , Integer , primary_key = True ),
452+ Column ("name" , String ),
453+ )
454+ metadata .create_all (engine )
455+
456+ with engine .begin () as conn :
457+ conn .execute (insert (users ), [{"id" : 1 , "name" : "Alice" , "age" : 30 }, {"id" : 2 , "name" : "Bob" , "age" : 25 }])
458+ conn .execute (insert (teams ), [{"id" : 1 , "name" : "A" }, {"id" : 2 , "name" : "B" }])
459+
460+ with engine .connect () as conn :
461+ rows = conn .execute (
462+ sa .text (
463+ "SELECT users.id, teams.id FROM users CROSS JOIN teams ORDER BY users.id, teams.id"
464+ )
465+ ).all ()
466+ assert rows == [(1 , 1 ), (1 , 2 ), (2 , 1 ), (2 , 2 )]
467+
468+ engine .dispose ()
469+
470+
383471def test_e2e_subquery_in_where (tmp_path ) -> None :
384472 engine = _engine_for (tmp_path )
385473 metadata = MetaData ()
0 commit comments