better override handling, handle defined-but-empty sql parts
[scpubgit/Q-Branch.git] / lib / SQL / Abstract / Clauses.pm
index 25462b4..aae5782 100644 (file)
@@ -63,11 +63,21 @@ sub register_defaults {
   $self->{expand}{exists} = sub {
     $_[0]->_expand_op(undef, [ exists => $_[2] ]);
   };
-  $self->{render}{convert_where} = sub {
-    my $self = shift;
-    local $self->{convert_where} = $self->{convert};
-    $self->render_aqt($_[1]);
-  };
+
+  # check for overriden methods
+  if ($self->can('_table') ne SQL::Abstract->can('_table')) {
+    $self->{expand_clause}{'select.from'} = sub {
+      return +{ -literal => [ $_[0]->_table($_[2]) ] };
+    };
+  }
+  if ($self->can('_order_by') ne SQL::Abstract->can('_order_by')) {
+    $self->{expand_clause}{'select.order_by'} = sub {
+      my ($osql, @obind) = $_[0]->_order_by($_[2]);
+      $osql =~ s/^order by //i;
+      return undef unless length($osql);
+      return +{ -literal => [ $osql, @obind ] };
+    };
+  }
   return $self;
 }
 
@@ -83,8 +93,44 @@ sub _expand_select_clause_from {
 
 sub _expand_select_clause_where {
   my ($self, undef, $where) = @_;
-  my $exp = $self->expand_expr($where);
-  +(where => ($self->{convert} ? +{ -convert_where => $exp } : $exp));
+
+  my $sqla = do {
+    if (my $conv = $self->{convert}) {
+      my $_wrap = sub {
+        my $orig = shift;
+        sub {
+          my $self = shift;
+          +{ -func => [
+            $conv,
+            $self->$orig(@_)
+          ] };
+        };
+      };
+      $self->clone
+           ->wrap_expanders(map +($_ => $_wrap), qw(ident value bind))
+           ->wrap_op_expanders(map +($_ => $_wrap), qw(ident value bind))
+           ->wrap_expander(func => sub {
+               my $orig = shift;
+               sub {
+                 my ($self, $type, $thing) = @_;
+                 if (ref($thing) eq 'ARRAY' and $thing->[0] eq $conv
+                     and @$thing == 2 and ref($thing->[1]) eq 'HASH'
+                     and (
+                       $thing->[1]{-ident}
+                       or $thing->[1]{-value}
+                       or $thing->[1]{-bind})
+                     ) {
+                   return { -func => $thing }; # already went through our expander
+                 }
+                 return $self->$orig($type, $thing);
+               }
+             });
+    } else {
+      $self;
+    }
+  };
+
+  return +(where => $sqla->expand_expr($where));
 }
 
 sub _expand_select_clause_order_by {
@@ -174,14 +220,13 @@ sub render_aqt {
 
 sub render_statement {
   my ($self, $expr, $default_scalar_to) = @_;
-  $self->render_aqt(
+  @{$self->render_aqt(
     $self->expand_expr($expr, $default_scalar_to), 1
-  );
+  )};
 }
 
 sub select {
   my ($self, @args) = @_;
-
   my $stmt = do {
     if (ref(my $sel = $args[0]) eq 'HASH') {
       $sel
@@ -198,8 +243,8 @@ sub select {
     }
   };
 
-  my $rendered = $self->render_statement({ -select => $stmt });
-  return wantarray ? @$rendered : $rendered->[0];
+  my @rendered = $self->render_statement({ -select => $stmt });
+  return wantarray ? @rendered : $rendered[0];
 }
 
 sub update {
@@ -217,8 +262,8 @@ sub update {
       \%clauses;
     }
   };
-  my $rendered = $self->render_statement({ -update => $stmt });
-  return wantarray ? @$rendered : $rendered->[0];
+  my @rendered = $self->render_statement({ -update => $stmt });
+  return wantarray ? @rendered : $rendered[0];
 }
 
 sub delete {
@@ -232,8 +277,8 @@ sub delete {
       \%clauses;
     }
   };
-  my $rendered = $self->render_statement({ -delete => $stmt });
-  return wantarray ? @$rendered : $rendered->[0];
+  my @rendered = $self->render_statement({ -delete => $stmt });
+  return wantarray ? @rendered : $rendered[0];
 }
 
 sub insert {
@@ -247,8 +292,8 @@ sub insert {
       \%clauses;
     }
   };
-  my $rendered = $self->render_statement({ -insert => $stmt });
-  return wantarray ? @$rendered : $rendered->[0];
+  my @rendered = $self->render_statement({ -insert => $stmt });
+  return wantarray ? @rendered : $rendered[0];
 }
 
 sub _expand_insert_clause_target {
@@ -269,7 +314,10 @@ sub _expand_insert_clause_from {
   }
   return $data if ref($data) eq 'HASH' and $data->{-row};
   my ($f_aqt, $v_aqt) = $self->_expand_insert_values($data);
-  return (from => { -values => $v_aqt }, ($f_aqt ? (fields => $f_aqt) : ()));
+  return (
+    from => { -values => [ $v_aqt ] },
+    ($f_aqt ? (fields => $f_aqt) : ()),
+  );
 }
 
 sub _expand_insert_clause_returning {
@@ -326,15 +374,28 @@ BEGIN {
     eval qq{sub ${singular}s {
       my (\$self, \@args) = \@_;
       while (my (\$this_key, \$this_value) = splice(\@args, 0, 2)) {
-        \$self->{${name}}{\$this_key} = \$this_value;
+        \$self->_ext_rw('${name}', \$this_key, \$this_value);
       }
       return \$self;
     }; 1 } or die "Method builder failed for ${singular}s: $@";
+    eval qq{sub wrap_${singular}s {
+      my (\$self, \@args) = \@_;
+      while (my (\$this_key, \$this_builder) = splice(\@args, 0, 2)) {
+        my \$orig = \$self->_ext_rw('${name}', \$this_key);
+        \$self->_ext_rw(
+          '${name}', \$this_key,
+           \$this_builder->(\$orig, '${name}', \$this_key),
+        );
+      }
+      return \$self;
+    }; 1 } or die "Method builder failed for wrap_${singular}s: $@";
     eval qq{sub ${singular}_list { sort keys %{\$_[0]->{\$name}} }; 1; }
      or die "Method builder failed for ${singular}_list: $@";
   }
 }
 
+sub register_op { $_[0]->{is_op}{$_[1]} = 1; $_[0] }
+
 sub statement_list { sort keys %{$_[0]->{clauses_of}} }
 
 sub clauses_of {