@@ -455,14 +455,64 @@ impl<'a> ViewQueryContext<'a> {
455455 fn order_by_clauses ( & self ) -> Vec < String > {
456456 let mut clauses = Vec :: new ( ) ;
457457 if !self . config . group_by . is_empty ( ) && self . is_flat_mode ( ) {
458- for ( sidx, Sort ( sort_col, sort_dir) ) in self . config . sort . iter ( ) . enumerate ( ) {
459- if * sort_dir != SortDir :: None && !is_col_sort ( sort_dir) {
460- let dir = sort_dir_to_string ( sort_dir) ;
461- if !self . config . split_by . is_empty ( ) {
462- clauses. push ( format ! ( "__SORT_{}__ {}" , sidx, dir) ) ;
463- } else {
464- let agg = self . get_aggregate ( sort_col) ;
465- clauses. push ( format ! ( "{}({}) {}" , agg, self . col_name( sort_col) , dir) ) ;
458+ let has_row_sort = self
459+ . config
460+ . sort
461+ . iter ( )
462+ . any ( |Sort ( _, dir) | * dir != SortDir :: None && !is_col_sort ( dir) ) ;
463+ if self . config . group_by . len ( ) > 1 && has_row_sort {
464+ // Hierarchical flat sort — mirrors rollup logic but without GROUPING_ID
465+ for gidx in 0 ..self . config . group_by . len ( ) {
466+ let is_leaf = gidx >= self . config . group_by . len ( ) - 1 ;
467+ for ( sidx, Sort ( sort_col, sort_dir) ) in self . config . sort . iter ( ) . enumerate ( ) {
468+ if * sort_dir == SortDir :: None || is_col_sort ( sort_dir) {
469+ continue ;
470+ }
471+
472+ let dir = sort_dir_to_string ( sort_dir) ;
473+ if !self . config . split_by . is_empty ( ) {
474+ if is_leaf {
475+ clauses. push ( format ! ( "__SORT_{}__ {}" , sidx, dir) ) ;
476+ } else {
477+ clauses. push ( format ! (
478+ "first(__SORT_{}__) OVER __WINDOW_{}__ {}" ,
479+ sidx, gidx, dir
480+ ) ) ;
481+ }
482+ } else {
483+ let agg = self . get_aggregate ( sort_col) ;
484+ if is_leaf {
485+ clauses. push ( format ! (
486+ "{}({}) {}" ,
487+ agg,
488+ self . col_name( sort_col) ,
489+ dir
490+ ) ) ;
491+ } else {
492+ clauses. push ( format ! (
493+ "first({}({})) OVER __WINDOW_{}__ {}" ,
494+ agg,
495+ self . col_name( sort_col) ,
496+ gidx,
497+ dir
498+ ) ) ;
499+ }
500+ }
501+ }
502+
503+ clauses. push ( format ! ( "{} ASC" , self . row_path_aliases[ gidx] ) ) ;
504+ }
505+ } else {
506+ // Single group level — simple sort, no window needed
507+ for ( sidx, Sort ( sort_col, sort_dir) ) in self . config . sort . iter ( ) . enumerate ( ) {
508+ if * sort_dir != SortDir :: None && !is_col_sort ( sort_dir) {
509+ let dir = sort_dir_to_string ( sort_dir) ;
510+ if !self . config . split_by . is_empty ( ) {
511+ clauses. push ( format ! ( "__SORT_{}__ {}" , sidx, dir) ) ;
512+ } else {
513+ let agg = self . get_aggregate ( sort_col) ;
514+ clauses. push ( format ! ( "{}({}) {}" , agg, self . col_name( sort_col) , dir) ) ;
515+ }
466516 }
467517 }
468518 }
@@ -531,14 +581,30 @@ impl<'a> ViewQueryContext<'a> {
531581 }
532582
533583 fn window_clauses ( & self ) -> Vec < String > {
534- if self . is_flat_mode ( ) || self . config . sort . is_empty ( ) || self . config . group_by . len ( ) <= 1 {
584+ if self . config . sort . is_empty ( ) || self . config . group_by . len ( ) <= 1 {
535585 return Vec :: new ( ) ;
536586 }
537587
538588 let mut clauses = Vec :: new ( ) ;
539589 for gidx in 0 ..( self . config . group_by . len ( ) - 1 ) {
540590 let partition = self . row_path_aliases [ ..=gidx] . join ( ", " ) ;
541- if !self . config . split_by . is_empty ( ) {
591+ if self . is_flat_mode ( ) {
592+ // Flat mode: partition by row path only (no GROUPING_ID)
593+ if !self . config . split_by . is_empty ( ) {
594+ let order = self . row_path_aliases . join ( ", " ) ;
595+ clauses. push ( format ! (
596+ "__WINDOW_{}__ AS (PARTITION BY {} ORDER BY {})" ,
597+ gidx, partition, order,
598+ ) ) ;
599+ } else {
600+ clauses. push ( format ! (
601+ "__WINDOW_{}__ AS (PARTITION BY {} ORDER BY {})" ,
602+ gidx,
603+ partition,
604+ self . group_col_names. join( ", " )
605+ ) ) ;
606+ }
607+ } else if !self . config . split_by . is_empty ( ) {
542608 let shift = self . config . group_by . len ( ) - 1 - gidx;
543609 let grouping_expr = if shift > 0 {
544610 format ! ( "(__GROUPING_ID__ >> {})" , shift)
0 commit comments