don't gensym for unqualified versions of already selected columns
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / Slice / GenericSubquery.pm
1 package Data::Query::Renderer::SQL::Slice::GenericSubquery;
2
3 use Data::Query::ExprHelpers;
4 use Moo::Role;
5
6 with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
7
8 sub slice_subquery {
9   (limit => 1, offset => 1);
10 }
11
12 sub slice_stability {
13   (limit => 'requires', offset => 'requires');
14 }
15
16 sub _render_slice {
17   my ($self, $dq) = @_;
18   die "Slice's inner is not a Select"
19     unless is_Select my $orig_select = $dq->{from};
20   my %remapped = $self->_subquery_remap($orig_select);
21   my $first_from = $remapped{inner_body};
22   # Should we simply strip until we reach a join/alias/etc. here?
23   $first_from = $first_from->{from}{from} if is_Having($first_from);
24   $first_from = $first_from->{from} if is_Where($first_from);
25   while (is_Join $first_from) {
26     $first_from = $first_from->{left};
27   }
28   $first_from = $first_from->{from} if is_Alias($first_from);
29   my $first_order = $remapped{inside_order}[0]{by};
30   my $count_col = $first_order->{elements}[-1];
31   my $count_alias = 'rownum__emulation';
32   my $count_sel = Select(
33     [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ],
34     Where(
35       Operator(
36         { 'SQL.Naive' => ($remapped{inside_order}[0]{reverse} ? '>' : '<') },
37         [
38           Identifier($count_alias, $count_col),
39           $remapped{outside_order}[0]{by}
40         ]
41       ),
42       Alias($count_alias, $first_from)
43     )
44   );
45   my $count_where = Operator(
46     { 'SQL.Naive' => ($dq->{offset} ? 'BETWEEN' : '<') },
47     [ $count_sel, (
48         $dq->{offset}
49           ? (
50               $dq->{offset},
51               {
52                 %{$dq->{limit}},
53                 value => $dq->{limit}{value}+$dq->{offset}{value}-1
54               }
55             )
56           : ($dq->{limit})
57       )
58     ]
59   );
60   return $self->render(
61     Select(
62       $remapped{outside_select_list},
63       (compose { no warnings 'once'; Order($b->{by}, $b->{reverse}, $b->{nulls}, $a) }
64         @{$remapped{outside_order}},
65         Where(
66           $count_where,
67           Alias(
68             $remapped{default_inside_alias},
69             Select(
70               $remapped{inside_select_list},
71               $remapped{inner_body},
72             )
73           )
74         )
75       )
76     )
77   );
78 }
79
80 1;