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