beginnings of RowNum.pm
Matt S Trout [Thu, 16 Aug 2012 17:53:39 +0000 (18:53 +0100)]
lib/Data/Query/Renderer/SQL/Slice/RowNum.pm [new file with mode: 0644]

diff --git a/lib/Data/Query/Renderer/SQL/Slice/RowNum.pm b/lib/Data/Query/Renderer/SQL/Slice/RowNum.pm
new file mode 100644 (file)
index 0000000..c14790a
--- /dev/null
@@ -0,0 +1,90 @@
+package Data::Query::Renderer::SQL::Slice::RowNum;
+
+use Data::Query::ExprHelpers;
+use Moo::Role;
+
+with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
+
+sub _render_slice {
+  my ($self, $dq) = @_;
+  die "Slice's inner is not a Select"
+    unless is_Select my $orig_select = $dq->{from};
+  my %remapped = $self->_subquery_remap_select($orig_select);
+  my $inside_select = Alias(
+    $remapped{default_inside_alias},
+    Select($remapped{inside_select_list}, $orig_select->{from}),
+  );
+  unless ($dq->{offset}) {
+    return $self->render(
+      Select(
+        $remapped{outside_select_list},
+        Where(
+          Operator(
+            { 'SQL.Naive' => '<=' },
+            [
+              Literal(SQL => 'ROWNUM'),
+              $dq->{limit}
+            ]
+          ),
+          $inside_select
+        )
+      )
+    );
+  }
+  my ($limit_plus_offset, $offset_plus) = (
+    { %{$dq->{limit}}, value => $dq->{limit}{value}+$dq->{offset}{value} },
+    { %{$dq->{limit}}, value => $dq->{offset}{value}+1 }
+  );
+
+  my $rownum_name = 'rownum__index';
+
+  if ($dq->{order_is_stable}) {
+    return $self->render(
+      Select(
+        $remapped{outside_select_list},
+        Where(
+          Operator(
+            { 'SQL.Naive' => '>=' },
+            [ Identifier($rownum_name), $limit_plus_offset, ]
+          ),
+          Alias(
+            $remapped{default_inside_alias},
+            Select(
+              [ @{$remapped{outside_select_list}},
+                Alias($rownum_name, Literal(SQL => 'ROWNUM')) ],
+              Where(
+                Operator(
+                  { 'SQL.Naive' => '<=' },
+                  [ Literal(SQL => 'ROWNUM'), $offset_plus ]
+                ),
+                $inside_select,
+              )
+            )
+          )
+        )
+      )
+    );
+  } else {
+    return $self->render(
+      Select(
+        $remapped{outside_select_list},
+        Where(
+          Operator(
+            { 'SQL.Naive' => 'BETWEEN' },
+            [ Identifier($rownum_name), $limit_plus_offset, $offset_plus ]
+          ),
+          Alias(
+            $remapped{default_inside_alias},
+            Select(
+              [ @{$remapped{outside_select_list}},
+                Alias($rownum_name, Literal(SQL => 'ROWNUM')) ],
+              $inside_select
+            )
+          )
+        )
+      )
+    );
+  }
+}
+
+1;