don't gensym for unqualified versions of already selected columns
[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_select {
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 @outside_select_list = map {
28     if (is_Alias) {
29       Identifier($_->{to});
30     } else {
31       $_;
32     }
33   } @inside_select_list;
34
35   return (
36     inside_select_list => \@inside_select_list,
37     outside_select_list => \@outside_select_list,
38     default_inside_alias => $default_inside_alias,
39   );
40 }
41
42 sub _subquery_remap {
43   my ($self, $orig_select) = @_;
44
45   my $gensym_count;
46   my %select_remap = $self->_subquery_remap_select($orig_select);
47
48   my $default_inside_alias = $select_remap{default_inside_alias};
49   my @inside_select_list = @{$select_remap{inside_select_list}};
50   my @outside_select_list = @{$select_remap{outside_select_list}};
51
52   my %alias_map = map {
53     if (is_Alias and is_Identifier $_->{from}) {
54       +(
55         join('.',@{$_->{from}{elements}}) => Identifier($_->{to}),
56         $_->{from}{elements}[-1] => Identifier($_->{to}),
57       )
58     } elsif (is_Identifier) {
59       +(
60         join('.',@{$_->{elements}}) => $_,
61         $_->{elements}[-1] => $_,
62       )
63     } else {
64       +()
65     }
66   } @inside_select_list;
67
68   my @inside_order;
69   my $inner_body = do {
70     my $order = $orig_select->{from};
71     while (is_Order $order) {
72       push @inside_order, $order;
73       $order = $order->{from};
74     }
75     $order;
76   };
77
78   my $order_gensym_count;
79   my @outside_order = map {
80     my $by = $_->{by};
81     if (is_Identifier $by) {
82       $default_inside_alias ||= $by->{elements}[0]
83         if @{$by->{elements}} == 2;
84       my $mapped_by
85         = $alias_map{join('.', @{$by->{elements}})}
86           ||= do {
87                 if (
88                   @{$by->{elements}} == 2
89                   and $by->{elements}[0] eq $default_inside_alias
90                 ) {
91                   push @inside_select_list, $by;
92                   $by;
93                 } else {
94                   my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
95                   push @inside_select_list, Alias($name, $by);
96                   Identifier($name);
97                 }
98               };
99       Order($mapped_by, $_->{reverse}, $_->{nulls});
100     } else {
101       my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
102       push @inside_select_list, Alias($name, $by);
103       Order(Identifier($name), $_->{reverse}, $_->{nulls});
104     }
105   } @inside_order;
106
107   $default_inside_alias ||= 'me';
108
109   return (
110     inside_select_list => \@inside_select_list,
111     outside_select_list => \@outside_select_list,
112     inside_order => \@inside_order,
113     outside_order => \@outside_order,
114     default_inside_alias => $default_inside_alias,
115     inner_body => $inner_body,
116   );
117 }
118
119 1;