@@ -775,6 +775,208 @@ describe('M:N include correlated subquery', () => {
775775 BinaryExpr . eq ( ColumnRef . of ( 'posts' , 'user_id' ) , ColumnRef . of ( 'users' , 'id' ) ) ,
776776 ) ;
777777 } ) ;
778+
779+ // M:N + distinct(cols) + nested non-leaf include exercises
780+ // `buildDistinctNonLeafChildRowsSelect` which applies `junctionJoins` to
781+ // `baseInner` — the innermost scalar SELECT inside the ROW_NUMBER wrap.
782+ // This test verifies the junction join attaches to `baseInner` (not to the
783+ // dedup wrapper or the outer distinct SELECT) and that the correlated WHERE
784+ // is present at that same level.
785+ it ( 'attaches junction join to baseInner in M:N + distinct + nested non-leaf path' , ( ) => {
786+ // Contract: parents -[M:N via parent_child]-> children (has `name` column),
787+ // children -[1:N FK]-> grandchildren (child_id → id).
788+ // We inline the contract to give `children` a `name` column for distinct.
789+ const contract = {
790+ domain : {
791+ namespaces : {
792+ public : {
793+ id : 'public' ,
794+ models : {
795+ Parent : {
796+ fields : { id : { nullable : false , type : { kind : 'scalar' , codecId : 'pg/int4@1' } } } ,
797+ relations : {
798+ children : {
799+ to : { model : 'Child' , namespace : 'public' } ,
800+ cardinality : 'N:M' ,
801+ on : { localFields : [ 'id' ] , targetFields : [ 'id' ] } ,
802+ through : {
803+ table : 'parent_child' ,
804+ parentColumns : [ 'parent_id' ] ,
805+ childColumns : [ 'child_id' ] ,
806+ targetColumns : [ 'id' ] ,
807+ } ,
808+ } ,
809+ } ,
810+ storage : { table : 'parents' , fields : { id : { column : 'id' } } } ,
811+ } ,
812+ Child : {
813+ fields : {
814+ id : { nullable : false , type : { kind : 'scalar' , codecId : 'pg/int4@1' } } ,
815+ name : { nullable : false , type : { kind : 'scalar' , codecId : 'pg/text@1' } } ,
816+ } ,
817+ relations : { } ,
818+ storage : {
819+ table : 'children' ,
820+ fields : { id : { column : 'id' } , name : { column : 'name' } } ,
821+ } ,
822+ } ,
823+ Grandchild : {
824+ fields : {
825+ id : { nullable : false , type : { kind : 'scalar' , codecId : 'pg/int4@1' } } ,
826+ child_id : { nullable : false , type : { kind : 'scalar' , codecId : 'pg/int4@1' } } ,
827+ } ,
828+ relations : { } ,
829+ storage : {
830+ table : 'grandchildren' ,
831+ fields : {
832+ id : { column : 'id' } ,
833+ child_id : { column : 'child_id' } ,
834+ } ,
835+ } ,
836+ } ,
837+ } ,
838+ } ,
839+ } ,
840+ } ,
841+ storage : {
842+ namespaces : {
843+ public : {
844+ id : 'public' ,
845+ tables : {
846+ parents : {
847+ columns : { id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } } ,
848+ primaryKey : { columns : [ 'id' ] } ,
849+ uniques : [ ] ,
850+ indexes : [ ] ,
851+ foreignKeys : [ ] ,
852+ } ,
853+ children : {
854+ columns : {
855+ id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } ,
856+ name : { nativeType : 'text' , codecId : 'pg/text@1' , nullable : false } ,
857+ } ,
858+ primaryKey : { columns : [ 'id' ] } ,
859+ uniques : [ ] ,
860+ indexes : [ ] ,
861+ foreignKeys : [ ] ,
862+ } ,
863+ grandchildren : {
864+ columns : {
865+ id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } ,
866+ child_id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } ,
867+ } ,
868+ primaryKey : { columns : [ 'id' ] } ,
869+ uniques : [ ] ,
870+ indexes : [ ] ,
871+ foreignKeys : [ ] ,
872+ } ,
873+ parent_child : {
874+ columns : {
875+ parent_id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } ,
876+ child_id : { nativeType : 'int4' , codecId : 'pg/int4@1' , nullable : false } ,
877+ } ,
878+ primaryKey : { columns : [ 'parent_id' , 'child_id' ] } ,
879+ uniques : [ ] ,
880+ indexes : [ ] ,
881+ foreignKeys : [ ] ,
882+ } ,
883+ } ,
884+ } ,
885+ } ,
886+ } ,
887+ capabilities : { } ,
888+ } ;
889+
890+ // Grandchild FK include: children.id → grandchildren.child_id
891+ const grandchildInclude : IncludeExpr = {
892+ relationName : 'grandchildren' ,
893+ relatedModelName : 'Grandchild' ,
894+ relatedTableName : 'grandchildren' ,
895+ targetColumn : 'child_id' ,
896+ localColumn : 'id' ,
897+ cardinality : '1:N' ,
898+ nested : emptyState ( ) ,
899+ scalar : undefined ,
900+ combine : undefined ,
901+ } ;
902+
903+ // M:N include: parents → children via parent_child, with distinct('name')
904+ // and a nested non-leaf grandchild include — exercises
905+ // buildDistinctNonLeafChildRowsSelect.
906+ const include : IncludeExpr = {
907+ relationName : 'children' ,
908+ relatedModelName : 'Child' ,
909+ relatedTableName : 'children' ,
910+ targetColumn : 'id' ,
911+ localColumn : 'id' ,
912+ cardinality : 'N:M' ,
913+ through : {
914+ table : 'parent_child' ,
915+ parentColumns : [ 'parent_id' ] ,
916+ childColumns : [ 'child_id' ] ,
917+ targetColumns : [ 'id' ] ,
918+ parentLocalColumns : [ 'id' ] ,
919+ } ,
920+ nested : {
921+ ...emptyState ( ) ,
922+ distinct : [ 'name' ] ,
923+ includes : [ grandchildInclude ] ,
924+ } ,
925+ scalar : undefined ,
926+ combine : undefined ,
927+ } ;
928+
929+ const state = { ...emptyState ( ) , includes : [ include ] } ;
930+ // Cast: inline contract literal is structurally compatible but lacks
931+ // generated nominal types; the cast is local to this test.
932+ const plan = compileSelectWithIncludes (
933+ contract as unknown as Parameters < typeof compileSelectWithIncludes > [ 0 ] ,
934+ 'parents' ,
935+ state ,
936+ ) ;
937+
938+ expectSelectAst ( plan . ast ) ;
939+ const childrenProjection = plan . ast . projection . find ( ( item ) => item . alias === 'children' ) ;
940+ expectSubqueryExpr ( childrenProjection ?. expr ) ;
941+
942+ // Aggregate wrapper: FROM (children__rows)
943+ const aggregateQuery = childrenProjection . expr . query ;
944+ expectDerivedTableSource ( aggregateQuery . from ) ;
945+ expect ( aggregateQuery . from . alias ) . toBe ( 'children__rows' ) ;
946+
947+ // Outer distinct SELECT: FROM (children__distinct)
948+ const childRows = aggregateQuery . from . query ;
949+ expectDerivedTableSource ( childRows . from ) ;
950+ expect ( childRows . from . alias ) . toBe ( 'children__distinct' ) ;
951+
952+ // ROW_NUMBER dedup wrapper: FROM (children__ranked)
953+ const innerSelect = childRows . from . query ;
954+ expectDerivedTableSource ( innerSelect . from ) ;
955+ expect ( innerSelect . from . alias ) . toBe ( 'children__ranked' ) ;
956+
957+ // baseInner: innermost scalar SELECT — junction join must be here
958+ const baseInner = innerSelect . from . query ;
959+
960+ // Junction join attaches to baseInner, not the dedup wrapper or outer SELECT
961+ expect ( baseInner . joins ) . toHaveLength ( 1 ) ;
962+ const junctionJoin = baseInner . joins ! [ 0 ] ! ;
963+ expect ( junctionJoin . joinType ) . toBe ( 'inner' ) ;
964+ expect ( junctionJoin . lateral ) . toBe ( false ) ;
965+ expect ( junctionJoin . source ) . toBeInstanceOf ( TableSource ) ;
966+ expect ( ( junctionJoin . source as TableSource ) . name ) . toBe ( 'parent_child' ) ;
967+ expect ( junctionJoin . on ) . toEqual (
968+ BinaryExpr . eq ( ColumnRef . of ( 'parent_child' , 'child_id' ) , ColumnRef . of ( 'children' , 'id' ) ) ,
969+ ) ;
970+
971+ // Correlated WHERE is present at baseInner level
972+ expect ( baseInner . where ) . toEqual (
973+ BinaryExpr . eq ( ColumnRef . of ( 'parent_child' , 'parent_id' ) , ColumnRef . of ( 'parents' , 'id' ) ) ,
974+ ) ;
975+
976+ // No junction join leaked to the dedup wrapper or outer distinct SELECT
977+ expect ( innerSelect . joins ?? [ ] ) . toHaveLength ( 0 ) ;
978+ expect ( childRows . joins ?? [ ] ) . toHaveLength ( 0 ) ;
979+ } ) ;
778980} ) ;
779981
780982describe ( 'compileSelect MTI JOINs' , ( ) => {
0 commit comments