add compose routine and refactor FetchFirst to functional style
Matt S Trout [Sat, 28 Jul 2012 18:56:32 +0000 (18:56 +0000)]
lib/Data/Query/ExprHelpers.pm
lib/Data/Query/Renderer/SQL/Slice/FetchFirst.pm

index 6b2cbef..8c030d7 100644 (file)
@@ -5,7 +5,7 @@ use Data::Query::Constants;
 
 use base qw(Exporter);
 
-our @EXPORT = qw(perl_scalar_value perl_operator Literal Identifier);
+our @EXPORT = qw(perl_scalar_value perl_operator Literal Identifier compose);
 
 sub perl_scalar_value {
   +{
@@ -81,4 +81,32 @@ foreach my $name (values %Data::Query::Constants::CONST) {
   }
 }
 
+sub compose (&@) {
+  my $code = shift;
+  require Scalar::Util;
+  my $type = Scalar::Util::reftype($code);
+  unless($type and $type eq 'CODE') {
+    require Carp;
+    Carp::croak("Not a subroutine reference");
+  }
+  no strict 'refs';
+
+  return shift unless @_ > 1;
+
+  use vars qw($a $b);
+
+  my $caller = caller;
+  local(*{$caller."::a"}) = \my $a;
+  local(*{$caller."::b"}) = \my $b;
+
+  $a = pop;
+  foreach (reverse @_) {
+    $b = $_;
+    $a = &{$code}();
+  }
+
+  $a;
+}
+
+
 1;
index 5558074..7a3234d 100644 (file)
@@ -1,6 +1,5 @@
 package Data::Query::Renderer::SQL::Slice::FetchFirst;
 
-use List::Util qw(reduce);
 use Data::Query::ExprHelpers;
 use Moo::Role;
 
@@ -87,42 +86,51 @@ sub _render_slice {
     push @order_nodes, $order;
     $order = $order->{from};
   }
-  my $inside_order = reduce {
-    Order($b->{by}, $b->{reverse}, $a)
-  } $order, reverse @order_nodes;
-  my $inside_select = Select(\@inside_select_list, $inside_order);
+  $default_inside_alias ||= 'me';
   my $limit_plus_offset = +{
     %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
   };
-  $default_inside_alias ||= 'me';
-  my $bridge_from = Alias(
-    $default_inside_alias,
-    Slice(undef, $limit_plus_offset, $inside_select)
-  );
-  my $outside_order = reduce {
-    Order($order_map{$b->{by}}, !$b->{reverse}, $a)
-  } $bridge_from, reverse @order_nodes;
-  my $outside_select = Select(
-    (
+  my $inner_body = $order;
+  return $self->_render(
+    map {
       $dq->{preserve_order}
-        ? [
+        ? Select(
+          \@outside_select_list,
+          compose {
+            Order($order_map{$b->{by}}, $b->{reverse}, $a)
+          } @order_nodes, Alias($default_inside_alias, $_)
+        )
+        : $_
+    } Slice(
+        undef, $dq->{limit},
+        Select(
+          [
             @outside_select_list,
-            grep @{$_->{elements}} == 1, @order_map{map $_->{by}, @order_nodes}
-          ]
-        : \@outside_select_list,
-    ),
-    $outside_order,
+            $dq->{preserve_order}
+              ? (grep @{$_->{elements}} == 1,
+                  @order_map{map $_->{by}, @order_nodes})
+              : (),
+          ],
+          compose {
+            Order($order_map{$b->{by}}, !$b->{reverse}, $a)
+          } (
+            @order_nodes,
+            Alias(
+              $default_inside_alias,
+              Slice(
+                undef, $limit_plus_offset,
+                Select(
+                  \@inside_select_list,
+                  compose {
+                    Order($b->{by}, $b->{reverse}, $a)
+                  } @order_nodes, $inner_body
+                )
+              )
+            )
+          )
+        )
+      )
   );
-  my $final = Slice(undef, $dq->{limit}, $outside_select);
-  if ($dq->{preserve_order}) {
-    $final = Select(
-      \@outside_select_list,
-      reduce {
-        Order($order_map{$b->{by}}, $b->{reverse}, $a)
-      } Alias($default_inside_alias, $final), reverse @order_nodes
-    );
-  }
-  return $self->_render($final);
 }
 
 1;