fixups for HAVING clauses
[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 _render_slice {
9   my ($self, $dq) = @_;
10   die "Slice's inner is not a Select"
11     unless is_Select my $orig_select = $dq->{from};
12   my %remapped = $self->_subquery_remap($orig_select);
13   my $first_from = $remapped{inner_body};
14   # Should we simply strip until we reach a join/alias/etc. here?
15   $first_from = $first_from->{from}{from} if is_Having($first_from);
16   $first_from = $first_from->{from} if is_Where($first_from);
17   while (is_Join $first_from) {
18     $first_from = $first_from->{left};
19   }
20   $first_from = $first_from->{from} if is_Alias($first_from);
21   my $first_order = $remapped{inside_order}[0]{by};
22   my $count_col = $first_order->{elements}[-1];
23   my $count_alias = 'rownum__emulation';
24   my $count_sel = Select(
25     [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ],
26     Where(
27       Operator(
28         { 'SQL.Naive' => ($remapped{inside_order}[0]{reverse} ? '>' : '<') },
29         [
30           Identifier($count_alias, $count_col),
31           $remapped{outside_order}[0]{by}
32         ]
33       ),
34       Alias($count_alias, $first_from)
35     )
36   );
37   my $count_where = Operator(
38     { 'SQL.Naive' => ($dq->{offset} ? 'BETWEEN' : '<') },
39     [ $count_sel, (
40         $dq->{offset}
41           ? (
42               $dq->{offset},
43               {
44                 %{$dq->{limit}},
45                 value => $dq->{limit}{value}+$dq->{offset}{value}-1
46               }
47             )
48           : ($dq->{limit})
49       )
50     ]
51   );
52   return $self->render(
53     Select(
54       $remapped{outside_select_list},
55       (compose { no warnings 'once'; Order($b->{by}, $b->{reverse}, $a) }
56         @{$remapped{outside_order}},
57         Where(
58           $count_where,
59           Alias(
60             $remapped{default_inside_alias},
61             Select(
62               $remapped{inside_select_list},
63               $remapped{inner_body},
64             )
65           )
66         )
67       )
68     )
69   );
70 }
71
72 1;