switch to _expand_logop to honour and/or expander wrapping
[dbsrgits/SQL-Abstract.git] / lib / SQL / Abstract.pm
index a049130..12c2c0c 100644 (file)
@@ -28,7 +28,7 @@ BEGIN {
 # GLOBALS
 #======================================================================
 
-our $VERSION  = '1.87';
+our $VERSION  = '1.90_02';
 
 # This would confuse some packagers
 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
@@ -279,6 +279,33 @@ sub new {
         [ $_[0]->_order_by($_[2]) ];
       };
     }
+    if (__PACKAGE__->can('_select_fields') ne $class->can('_select_fields')) {
+      $opt{expand_clause}{'select.select'} = sub { $_[2] };
+      $opt{render_clause}{'select.select'} = sub {
+        my @super = $_[0]->_select_fields($_[2]);
+        my $effort = [
+          ref($super[0]) eq 'HASH'
+            ? $_[0]->render_expr($super[0])
+            : @super
+        ];
+        return $_[0]->join_query_parts(
+          ' ', { -keyword => 'select' }, $effort
+        );
+      };
+    }
+    foreach my $type (qw(in between)) {
+      my $meth = "_where_field_".uc($type);
+      if (__PACKAGE__->can($meth) ne $class->can($meth)) {
+        my $exp = sub {
+          my ($self, $op, $v, $k) = @_;
+          $op = join ' ', split '_', $op;
+          return +{ -literal => [
+            $self->$meth($k, $op, $v)
+          ] };
+        };
+        $opt{expand_op}{$_} = $exp for $type, "not_${type}";
+      }
+    }
     if ($class->isa('DBIx::Class::SQLMaker')) {
       $opt{warn_once_on_nest} = 1;
       $opt{disable_old_special_ops} = 1;
@@ -287,6 +314,11 @@ sub new {
         s/\A\s+//, s/\s+\Z// for $sql;
         return [ $sql, @bind ];
       };
+      $opt{expand_op}{ident} = $class->make_unop_expander(sub {
+        my ($self, undef, $body) = @_;
+        $body = $body->from if Scalar::Util::blessed($body);
+        $self->_expand_ident(ident => $body);
+      });
     }
   }
 
@@ -330,7 +362,7 @@ sub make_binop_expander {
 sub plugin {
   my ($self, $plugin, @args) = @_;
   unless (ref $plugin) {
-    $plugin =~ s/\A\+/${\ref($self)}::Plugin::/;
+    $plugin =~ s/\A\+/${\__PACKAGE__}::Plugin::/;
     require(join('/', split '::', $plugin).'.pm');
   }
   $plugin->apply_to($self, @args);
@@ -344,8 +376,11 @@ BEGIN {
     my $name = join '_', reverse split '_', $type;
     my $singular = "${type}er";
 
-    eval qq{sub ${singular} { shift->${singular}s(\@_) }; 1 }
-      or die "Method builder failed for ${singular}: $@";
+    eval qq{sub ${singular} {
+      my \$self = shift;
+      return \$self->_ext_rw('${name}', \@_) if \@_ == 1;
+      return \$self->${singular}s(\@_)
+    }; 1 } or die "Method builder failed for ${singular}: $@";
     eval qq{sub wrap_${singular} {
       shift->wrap_${singular}s(\@_)
     }; 1 } or die "Method builder failed for wrap_${singular}: $@";
@@ -536,7 +571,8 @@ sub _returning {
   my ($sql, @bind) = @{ $self->render_aqt(
     $self->expand_expr({ -list => $f }, -ident)
   ) };
-  return ($self->_sqlcase(' returning ').$sql, @bind);
+  my $rsql = $self->_sqlcase(' returning ').$sql;
+  return wantarray ? ($rsql, @bind) : $rsql;
 }
 
 sub _expand_insert_value {
@@ -736,9 +772,10 @@ sub _expand_select_clause_order_by {
 sub _select_fields {
   my ($self, $fields) = @_;
   return $fields unless ref($fields);
-  return @{ $self->render_aqt(
+  my ($sql, @bind) = @{ $self->render_aqt(
     $self->expand_expr({ -list => $fields }, '-ident')
   ) };
+  return wantarray ? ($sql, @bind) : $sql;
 }
 
 #======================================================================
@@ -907,7 +944,7 @@ sub _expand_expr {
   if (ref($expr) eq 'HASH') {
     return undef unless my $kc = keys %$expr;
     if ($kc > 1) {
-      return $self->_expand_op_andor(and => $expr);
+      return $self->_expand_logop(and => $expr);
     }
     my ($key, $value) = %$expr;
     if ($key =~ /^-/ and $key =~ s/ [_\s]? \d+ $//x ) {
@@ -917,7 +954,7 @@ sub _expand_expr {
     return $self->_expand_hashpair($key, $value);
   }
   if (ref($expr) eq 'ARRAY') {
-    return $self->_expand_op_andor(lc($self->{logic}), $expr);
+    return $self->_expand_logop(lc($self->{logic}), $expr);
   }
   if (my $literal = is_literal_value($expr)) {
     return +{ -literal => $literal };
@@ -939,7 +976,7 @@ sub _expand_hashpair {
   }
   if ($k =~ /^-./) {
     return $self->_expand_hashpair_op($k, $v);
-  } elsif ($k =~ /^[^\w]/i) {
+  } elsif ($k =~ /^\W+$/) {
     my ($lhs, @rhs) = ref($v) eq 'ARRAY' ? @$v : $v;
     return $self->_expand_op(
       -op, [ $k, $self->expand_expr($lhs, -ident), @rhs ]
@@ -956,7 +993,7 @@ sub _expand_hashpair_ident {
   # hash with multiple or no elements is andor
 
   if (ref($v) eq 'HASH' and keys %$v != 1) {
-    return $self->_expand_op_andor(and => $v, $k);
+    return $self->_expand_logop(and => $v, $k);
   }
 
   # undef needs to be re-sent with cmp to achieve IS/IS NOT NULL
@@ -987,7 +1024,7 @@ sub _expand_hashpair_ident {
         ? (shift(@{$v = [ @$v ]}), $1)
         : lc($self->{logic} || 'OR')
     );
-    return $self->_expand_op_andor(
+    return $self->_expand_logop(
       $logic => $v, $k
     );
   }
@@ -1164,7 +1201,7 @@ sub _expand_hashtriple {
         "operator '%s' applied on an empty array (field '$k')"
       ) ? $self->sqlfalse : $self->sqltrue);
     }
-    return $self->_expand_op_andor($logic => \@values, $k);
+    return $self->_expand_logop($logic => \@values, $k);
   }
   if (is_undef_value($vv)) {
     my $is = ($self->_dwim_op_to_is($op,
@@ -1242,6 +1279,9 @@ sub _expand_op {
   if (my $exp = $self->{expand_op}{$op}) {
     return $self->$exp($op, \@opargs);
   }
+  if (List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) {
+    return { -op => [ $op, @opargs ] };
+  }
   +{ -op => [ $op, map $self->expand_expr($_), @opargs ] };
 }
 
@@ -1257,7 +1297,7 @@ sub _expand_bool {
 sub _expand_list {
   my ($self, undef, $expr) = @_;
   return { -op => [
-    ',', map $self->expand_expr($_), 
+    ',', map $self->expand_expr($_),
           @{$expr->{-op}}[1..$#{$expr->{-op}}]
   ] } if ref($expr) eq 'HASH' and ($expr->{-op}||[''])->[0] eq ',';
   return +{ -op => [ ',',
@@ -1266,6 +1306,11 @@ sub _expand_list {
   ] };
 }
 
+sub _expand_logop {
+  my ($self, $logop, $v, $k) = @_;
+  $self->${\$self->{expand_op}{$logop}}($logop, $v, $k);
+}
+
 sub _expand_op_andor {
   my ($self, $logop, $v, $k) = @_;
   if (defined $k) {
@@ -1654,6 +1699,25 @@ sub _open_outer_paren {
   $sql;
 }
 
+sub _where_field_IN {
+  my ($self, $k, $op, $vals) = @_;
+  @{$self->_render_op_in(
+    $op,
+    [
+      $self->expand_expr($k, -ident),
+      map $self->expand_expr($_, -value),
+        ref($vals) eq 'ARRAY' ? @$vals : $vals
+    ]
+  )};
+}
+
+sub _where_field_BETWEEN {
+  my ($self, $k, $op, $vals) = @_;
+  @{$self->_render_op_between(
+    $op,
+    [ $self->expand_expr($k, -ident), ref($vals) eq 'ARRAY' ? @$vals : $vals ]
+  )};
+}
 
 #======================================================================
 # ORDER BY
@@ -1705,6 +1769,8 @@ sub _order_by {
 
   my $final_sql = $self->_sqlcase(' order by ').$sql;
 
+  return $final_sql unless wantarray;
+
   return ($final_sql, @bind);
 }