first cut at GenericSubquery
Matt S Trout [Fri, 17 Aug 2012 14:32:23 +0000 (15:32 +0100)]
lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm [new file with mode: 0644]

diff --git a/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm b/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm
new file mode 100644 (file)
index 0000000..c01c48c
--- /dev/null
@@ -0,0 +1,67 @@
+package Data::Query::Renderer::SQL::Slice::GenericSubquery;
+
+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($orig_select);
+  my $first_from = $remapped{inner_body};
+  $first_from = $first_from->{from} if is_Where($first_from);
+  while (is_Join $first_from) {
+    $first_from = $first_from->{left};
+  }
+  $first_from = $first_from->{from} if is_Alias($first_from);
+  my $first_order = $remapped{inside_order}[0]{by};
+  my $count_col = $first_order->{elements}[-1];
+  my $count_alias = 'rownum__emulation';
+  my $count_sel = Select(
+    [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ],
+    Where(
+      Operator(
+        { 'SQL.Naive' => ($first_order->{reverse} ? '>' : '<') },
+        [ Identifier($count_alias, $count_col), $first_order ]
+      ),
+      Alias($count_alias, $first_from)
+    )
+  );
+  my $count_where = Operator(
+    { 'SQL.Naive' => ($dq->{offset} ? 'BETWEEN' : '<') },
+    [ $count_sel, (
+        $dq->{offset}
+          ? (
+              $dq->{offset},
+              {
+                %{$dq->{limit}},
+                value => $dq->{limit}{value}+$dq->{offset}{value}-1
+              }
+            )
+          : ($dq->{limit})
+      )
+    ]
+  );
+  return $self->render(
+    Select(
+      $remapped{outside_select_list},
+      (compose { no warnings 'once'; Order($b->{by}, $b->{reverse}, $a) }
+        @{$remapped{outside_order}},
+        Where(
+          $count_where,
+          Alias(
+            $remapped{default_inside_alias},
+            Select(
+              $remapped{inside_select_list},
+              $remapped{inner_body},
+            )
+          )
+        )
+      )
+    )
+  );
+}
+
+1;