working RowNumberOver
[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_type { 'FetchFirst' }
19
20 sub _render_slice {
21   my ($self, $dq) = @_;
22   unless ($dq->{offset}) {
23     return $self->_render_slice_limit($dq);
24   }
25   unless ($dq->{order_is_stable}) {
26     die $self->_slice_type." limit style requires a stable order";
27   }
28   die "Slice's inner is not a Select"
29     unless is_Select my $orig_select = $dq->{from};
30   die "Slice's Select not followed by Order but order_is_stable set"
31     unless is_Order $orig_select->{from};
32
33   my %remapped = $self->_subquery_remap($orig_select);
34
35   my @inside_select_list = @{$remapped{inside_select_list}};
36   my @outside_select_list = @{$remapped{outside_select_list}};
37   my @inside_order = @{$remapped{inside_order}};
38   my @outside_order = @{$remapped{outside_order}};
39   my $default_inside_alias = $remapped{default_inside_alias};
40   my $inner_body = $remapped{inner_body};
41
42   my $limit_plus_offset = +{
43     %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
44   };
45
46   return $self->_render(
47     map {
48       $dq->{preserve_order}
49         ? Select(
50           \@outside_select_list,
51           compose {
52             Order($b->{by}, $b->{reverse}, $a)
53           } (
54             @outside_order,
55             Alias($default_inside_alias, $_)
56           )
57         )
58         : $_
59     } (
60       Slice(
61         undef, $dq->{limit},
62         Select(
63           [
64             @outside_select_list,
65             $dq->{preserve_order}
66               ? (grep @{$_->{elements}} == 1,
67                   map $_->{by}, @outside_order)
68               : (),
69           ],
70           compose {
71             Order($b->{by}, !$b->{reverse}, $a)
72           } (
73             @outside_order,
74             Alias(
75               $default_inside_alias,
76               Slice(
77                 undef, $limit_plus_offset,
78                 Select(
79                   \@inside_select_list,
80                   compose {
81                     Order($b->{by}, $b->{reverse}, $a)
82                   } @inside_order, $inner_body
83                 )
84               )
85             )
86           )
87         )
88       )
89     )
90   );
91 }
92
93 1;