working RowNumberOver
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / Slice / SubqueryRemap.pm
1 package Data::Query::Renderer::SQL::Slice::SubqueryRemap;
2
3 use Data::Query::ExprHelpers;
4 use Moo::Role;
5
6 sub _subquery_remap {
7   my ($self, $orig_select) = @_;
8
9   my $gensym_count;
10   my $default_inside_alias;
11
12   my @inside_select_list = map {
13     if (is_Alias) {
14       $_;
15     } elsif (is_Identifier) {
16       my @el = @{$_->{elements}};
17       if (@el == 2 and $el[0] eq ($default_inside_alias ||= $el[0])) {
18         $_;
19       } else {
20         Alias(join('__', @el), $_);
21       }
22     } else {
23       Alias(sprintf("GENSYM__%03i",++$gensym_count), $_);
24     }
25   } @{$orig_select->{select}};
26
27   my %alias_map = map {
28     if (is_Alias and is_Identifier $_->{from}) {
29       +(join('.',@{$_->{from}{elements}}) => Identifier($_->{to}))
30     } elsif (is_Identifier) {
31       +(join('.',@{$_->{elements}}) => $_)
32     } else {
33       +()
34     }
35   } @inside_select_list;
36
37   my @outside_select_list = map {
38     if (is_Alias) {
39       Identifier($_->{to});
40     } else {
41       $_;
42     }
43   } @inside_select_list;
44
45   my @inside_order;
46   my $inner_body = do {
47     my $order = $orig_select->{from};
48     while (is_Order $order) {
49       push @inside_order, $order;
50       $order = $order->{from};
51     }
52     $order;
53   };
54
55   my $order_gensym_count;
56   my @outside_order = map {
57     my $by = $_->{by};
58     if (is_Identifier $by) {
59       $default_inside_alias ||= $by->{elements}[0]
60         if @{$by->{elements}} == 2;
61       my $mapped_by
62         = $alias_map{join('.', @{$by->{elements}})}
63           ||= do {
64                 if (
65                   @{$by->{elements}} == 2
66                   and $by->{elements}[0] eq $default_inside_alias
67                 ) {
68                   push @inside_select_list, $by;
69                   $by;
70                 } else {
71                   my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
72                   push @inside_select_list, Alias($name, $by);
73                   Identifier($name);
74                 }
75               };
76       Order($mapped_by, $_->{reverse});
77     } else {
78       die "XXX not implemented yet";
79     }
80   } @inside_order;
81
82   $default_inside_alias ||= 'me';
83
84   return (
85     inside_select_list => \@inside_select_list,
86     outside_select_list => \@outside_select_list,
87     inside_order => \@inside_order,
88     outside_order => \@outside_order,
89     default_inside_alias => $default_inside_alias,
90     inner_body => $inner_body,
91   );
92 }
93
94 1;