default the default_inside_alias in case of a full SELECT list of ASed things
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / Slice / FetchFirst.pm
1 package Data::Query::Renderer::SQL::Slice::FetchFirst;
2
3 use Data::Query::ExprHelpers;
4 use Moo::Role;
5
6 with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
7
8 sub _render_slice_limit {
9   my ($self, $dq) = @_;
10   return [
11     ($dq->{from} ? $self->_render($dq->{from}) : ()),
12     $self->_format_keyword('FETCH FIRST'),
13     sprintf("%i", $dq->{limit}{value}),
14     $self->_format_keyword('ROWS ONLY')
15   ];
16 }
17
18 sub slice_subquery {
19   (offset => 1);
20 }
21
22 sub slice_stability {
23   (offset => 'requires');
24 }
25
26 sub _slice_type { 'FetchFirst' }
27
28 sub _render_slice {
29   my ($self, $dq) = @_;
30   unless ($dq->{offset}) {
31     return $self->_render_slice_limit($dq);
32   }
33   unless ($dq->{order_is_stable}) {
34     die $self->_slice_type." limit style requires a stable order";
35   }
36   die "Slice's inner is not a Select"
37     unless is_Select my $orig_select = $dq->{from};
38   die "Slice's Select not followed by Order but order_is_stable set"
39     unless is_Order $orig_select->{from};
40
41   my %remapped = $self->_subquery_remap($orig_select);
42
43   my @inside_select_list = @{$remapped{inside_select_list}};
44   my @outside_select_list = @{$remapped{outside_select_list}};
45   my @inside_order = @{$remapped{inside_order}};
46   my @outside_order = @{$remapped{outside_order}};
47   my $default_inside_alias = $remapped{default_inside_alias};
48   my $inner_body = $remapped{inner_body};
49
50   my $limit_plus_offset = +{
51     %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
52   };
53
54   return $self->_render(
55     map {
56       $dq->{preserve_order}
57         ? Select(
58           \@outside_select_list,
59           compose {
60             Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
61           } (
62             @outside_order,
63             Alias($default_inside_alias, $_)
64           )
65         )
66         : $_
67     } (
68       Slice(
69         undef, $dq->{limit},
70         Select(
71           [
72             @outside_select_list,
73             $dq->{preserve_order}
74               ? (grep @{$_->{elements}} == 1,
75                   map $_->{by}, @outside_order)
76               : (),
77           ],
78           compose {
79             Order($b->{by}, !$b->{reverse}, -($b->{nulls}||0), $a)
80           } (
81             @outside_order,
82             Alias(
83               $default_inside_alias,
84               Slice(
85                 undef, $limit_plus_offset,
86                 Select(
87                   \@inside_select_list,
88                   compose {
89                     Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
90                   } @inside_order, $inner_body
91                 )
92               )
93             )
94           )
95         )
96       )
97     )
98   );
99 }
100
101 1;