handle \$dq in order by
[dbsrgits/SQL-Abstract.git] / lib / SQL / Abstract / Converter.pm
index 4890ee0..d9c6a97 100644 (file)
@@ -3,10 +3,6 @@ package SQL::Abstract::Converter;
 use Carp ();
 use List::Util ();
 use Scalar::Util ();
-use Data::Query::Constants qw(
-  DQ_IDENTIFIER DQ_OPERATOR DQ_VALUE DQ_LITERAL DQ_JOIN DQ_SELECT DQ_ORDER
-  DQ_WHERE DQ_DELETE DQ_UPDATE DQ_INSERT
-);
 use Data::Query::ExprHelpers;
 use Moo;
 use namespace::clean;
@@ -85,14 +81,22 @@ sub _ident_to_dq {
   my ($self, $ident) = @_;
   $self->_assert_pass_injection_guard($ident)
     unless $self->renderer_will_quote;
-  $self->_maybe_convert_dq(Identifier(split /\Q${\$self->identifier_sep}/, $ident));
+  $self->_maybe_convert_dq(
+    Identifier(do {
+      if (my $sep = $self->identifier_sep) {
+        split /\Q$sep/, $ident
+      } else {
+        $ident
+      }
+    })
+  );
 }
 
 sub _maybe_convert_dq {
   my ($self, $dq) = @_;
   if (my $c = $self->{where_convert}) {
     Operator({ 'SQL.Naive' => 'apply' }, [
-        { type => DQ_IDENTIFIER, elements => [ $self->_sqlcase($c) ] },
+        Identifier($self->_sqlcase($c)),
         $dq
       ]
     );
@@ -204,7 +208,7 @@ sub _select_to_dq {
 
   my $ordered_dq = do {
     if ($order) {
-      $self->_order_by_to_dq($order, undef, $source_dq);
+      $self->_order_by_to_dq($order, undef, undef, $source_dq);
     } else {
       $source_dq
     }
@@ -372,8 +376,9 @@ sub _apply_to_dq {
 
   foreach my $arg (@args) {
     if (
-      $arg->{type} eq DQ_OPERATOR and $arg->{operator}{'SQL.Naive'} eq 'apply'
-      and @{$arg->{args}} == 2 and $arg->{args}[1]{type} ne DQ_OPERATOR
+      is_Operator($arg) and $arg->{operator}{'SQL.Naive'} eq 'apply'
+      and @{$arg->{args}} == 2 and !is_Operator($arg->{args}[1])
+
     ) {
       $arg->{operator}{'SQL.Naive'} = (shift @{$arg->{args}})->{elements}->[0];
     }
@@ -520,13 +525,14 @@ sub _where_hashpair_to_dq {
 }
 
 sub _order_by_to_dq {
-  my ($self, $arg, $dir, $from) = @_;
+  my ($self, $arg, $dir, $nulls, $from) = @_;
 
   return unless $arg;
 
   my $dq = Order(
     undef,
     (defined($dir) ? (!!($dir =~ /desc/i)) : undef),
+    (defined($nulls) ? ($nulls =~ /first/i ? 1 : -1) : undef),
     ($from ? ($from) : undef),
   );
 
@@ -539,7 +545,7 @@ sub _order_by_to_dq {
     my ($outer, $inner);
     foreach my $member (@$arg) {
       local $Order_Inner;
-      my $next = $self->_order_by_to_dq($member, $dir, $from);
+      my $next = $self->_order_by_to_dq($member, $dir, $nulls, $from);
       $outer ||= $next;
       $inner->{from} = $next if $inner;
       $inner = $Order_Inner || $next;
@@ -548,6 +554,8 @@ sub _order_by_to_dq {
     return $outer;
   } elsif (ref($arg) eq 'REF' and ref($$arg) eq 'ARRAY') {
     $dq->{by} = $self->_literal_to_dq($$arg);
+  } elsif (ref($arg) eq 'REF' and ref($$arg) eq 'HASH') {
+    $dq->{by} = $$arg;
   } elsif (ref($arg) eq 'SCALAR') {
 
     # < mst> right, but if it doesn't match that, it goes "ok, right, not sure, 
@@ -567,15 +575,27 @@ sub _order_by_to_dq {
       $dq->{by} = $self->_literal_to_dq($$arg);
     }
   } elsif (ref($arg) eq 'HASH') {
-    my ($key, $val, @rest) = %$arg;
+    return () unless %$arg;
+
+    my ($direction, $val);
+    foreach my $key (keys %$arg) {
+      if ( $key =~ /^-(desc|asc)/i ) {
+        die "hash passed to _order_by_to_dq must have exactly one of -desc or -asc"
+            if defined $direction;
+        $direction = $1;
+        $val = $arg->{$key};
+      } elsif ($key =~ /^-nulls$/i)  {
+        $nulls = $arg->{$key};
+        die "invalid value for -nulls" unless $nulls =~ /^(?:first|last)$/i;
+      } else {
+        die "invalid key in hash passed to _order_by_to_dq";
+      }
+    }
 
-    return unless $key;
+    die "hash passed to _order_by_to_dq must have exactly one of -desc or -asc"
+        unless defined $direction;
 
-    if (@rest or not $key =~ /^-(desc|asc)/i) {
-      die "hash passed to _order_by must have exactly one key (-desc or -asc)";
-    }
-    my $dir = uc $1;
-    return $self->_order_by_to_dq($val, $dir, $from);
+    return $self->_order_by_to_dq($val, $direction, $nulls, $from);
   } else {
     die "Can't handle $arg in _order_by_to_dq";
   }