working RowNum.pm
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / Slice / RowNum.pm
1 package Data::Query::Renderer::SQL::Slice::RowNum;
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_select($orig_select);
13   my $inside_select = Alias(
14     $remapped{default_inside_alias},
15     Select($remapped{inside_select_list}, $orig_select->{from}),
16   );
17   unless ($dq->{offset}) {
18     return $self->render(
19       Select(
20         $remapped{outside_select_list},
21         Where(
22           Operator(
23             { 'SQL.Naive' => '<=' },
24             [
25               Literal(SQL => 'ROWNUM'),
26               $dq->{limit}
27             ]
28           ),
29           $inside_select
30         )
31       )
32     );
33   }
34   my ($limit_plus_offset, $offset_plus) = (
35     { %{$dq->{limit}}, value => $dq->{limit}{value}+$dq->{offset}{value} },
36     { %{$dq->{limit}}, value => $dq->{offset}{value}+1 }
37   );
38
39   my $rownum_name = 'rownum__index';
40
41   if ($dq->{order_is_stable}) {
42     return $self->render(
43       Select(
44         $remapped{outside_select_list},
45         Where(
46           Operator(
47             { 'SQL.Naive' => '>=' },
48             [ Identifier($rownum_name), $offset_plus ]
49           ),
50           Alias(
51             $remapped{default_inside_alias},
52             Select(
53               [ @{$remapped{outside_select_list}},
54                 Alias($rownum_name, Literal(SQL => 'ROWNUM')) ],
55               Where(
56                 Operator(
57                   { 'SQL.Naive' => '<=' },
58                   [ Literal(SQL => 'ROWNUM'), $limit_plus_offset ]
59                 ),
60                 $inside_select,
61               )
62             )
63           )
64         )
65       )
66     );
67   } else {
68     return $self->render(
69       Select(
70         $remapped{outside_select_list},
71         Where(
72           Operator(
73             { 'SQL.Naive' => 'BETWEEN' },
74             [ Identifier($rownum_name), $offset_plus, $limit_plus_offset ]
75           ),
76           Alias(
77             $remapped{default_inside_alias},
78             Select(
79               [ @{$remapped{outside_select_list}},
80                 Alias($rownum_name, Literal(SQL => 'ROWNUM')) ],
81               $inside_select
82             )
83           )
84         )
85       )
86     );
87   }
88 }
89
90 1;