Remove pointless else after return
[dbsrgits/SQL-Abstract.git] / lib / SQL / Abstract / Converter.pm
index 8779cce..2a7d90a 100644 (file)
@@ -81,7 +81,15 @@ 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 {
@@ -200,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
     }
@@ -260,6 +268,18 @@ sub _where_to_dq {
   return $self->_expr_to_dq($where, $logic);
 }
 
+my %op_conversions = (
+  '==' => '=',
+  'eq' => '=',
+  'ne' => '!=',
+  '!' => 'NOT',
+  'gt' => '>',
+  'ge' => '>=',
+  'lt' => '<',
+  'le' => '<=',
+  'defined' => 'IS NOT NULL',
+);
+
 sub _expr_to_dq {
   my ($self, $where, $logic) = @_;
 
@@ -273,7 +293,20 @@ sub _expr_to_dq {
   ) {
     return $self->_literal_to_dq($$where);
   } elsif (ref($where) eq 'REF' and ref($$where) eq 'HASH') {
-    return $$where;
+    return map_dq_tree {
+      if (
+        is_Operator
+        and not $_->{operator}{'SQL.Naive'}
+        and my $op = $_->{operator}{'Perl'}
+      ) {
+        my $sql_op = $op_conversions{$op} || uc($op);
+        return +{
+          %{$_},
+          operator => { 'SQL.Naive' => $sql_op }
+        };
+      }
+      return $_;
+    } $$where;
   } elsif (!ref($where) or Scalar::Util::blessed($where)) {
     return $self->_value_to_dq($where);
   }
@@ -450,6 +483,7 @@ sub _where_hashpair_to_dq {
       }
     };
     if ($op eq 'BETWEEN' or $op eq 'IN' or $op eq 'NOT IN' or $op eq 'NOT BETWEEN') {
+      $rhs = [$rhs] unless ref $rhs;
       if (ref($rhs) ne 'ARRAY') {
         if ($op =~ /IN$/) {
           # have to add parens if none present because -in => \"SELECT ..."
@@ -458,17 +492,35 @@ sub _where_hashpair_to_dq {
             my $x = $$rhs;
             1 while ($x =~ s/\A\s*\((.*)\)\s*\Z/$1/s);
             $rhs = \$x;
-          } else {
-            my ($x, @rest) = @{$$rhs};
-            1 while ($x =~ s/\A\s*\((.*)\)\s*\Z/$1/s);
-            $rhs = \[ $x, @rest ];
+          } elsif (ref($rhs) eq 'REF') {
+            if (ref($$rhs) eq 'ARRAY') {
+              my ($x, @rest) = @{$$rhs};
+              1 while ($x =~ s/\A\s*\((.*)\)\s*\Z/$1/s);
+              $rhs = \[ $x, @rest ];
+            } elsif (ref($$rhs) eq 'HASH') {
+              return $self->_op_to_dq($op, $self->_ident_to_dq($k), $$rhs);
+            }
           }
         }
         return $self->_op_to_dq(
           $op, $self->_ident_to_dq($k), $self->_literal_to_dq($$rhs)
         );
       }
-      return $self->_literal_to_dq($self->{sqlfalse}) unless @$rhs;
+      if (grep !defined, @$rhs) {
+        my ($inop, $logic, $nullop) = $op =~ /^NOT/
+          ? (-not_in => AND => { '!=' => undef })
+          : (-in => OR => undef);
+        if (my @defined = grep defined, @$rhs) {
+          return $self->_expr_to_dq_ARRAYREF([
+            { $k => { $inop => \@defined } },
+            { $k => $nullop },
+          ], $logic);
+        }
+        return $self->_expr_to_dq_HASHREF({ $k => $nullop });
+      }
+      return $self->_literal_to_dq(
+        $op =~ /^NOT/ ? $self->{sqltrue} : $self->{sqlfalse}
+      ) unless @$rhs;
       return $self->_op_to_dq(
         $op, $self->_ident_to_dq($k), map $self->_expr_to_dq($_), @$rhs
       )
@@ -517,13 +569,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),
+    $nulls,
     ($from ? ($from) : undef),
   );
 
@@ -536,7 +589,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;
@@ -545,6 +598,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, 
@@ -557,22 +612,38 @@ sub _order_by_to_dq {
     #        dbihacks crack combined with old literal order_by crack
     # < ribasushi> heh :)
 
-    if (my ($ident, $dir) = $$arg =~ /^(\w+)(?:\s+(desc|asc))?$/i) {
+    # this should take into account our quote char and name sep
+
+    my $match_ident = '\w+(?:\.\w+)*';
+
+    if (my ($ident, $dir) = $$arg =~ /^(${match_ident})(?:\s+(desc|asc))?$/i) {
       $dq->{by} = $self->_ident_to_dq($ident);
       $dq->{reverse} = 1 if $dir and lc($dir) eq 'desc';
     } else {
       $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|none)$/i;
+      } else {
+        die "invalid key ${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";
   }