better override handling, handle defined-but-empty sql parts
[scpubgit/Q-Branch.git] / lib / SQL / Abstract / Clauses.pm
index b859342..aae5782 100644 (file)
@@ -63,6 +63,21 @@ sub register_defaults {
   $self->{expand}{exists} = sub {
     $_[0]->_expand_op(undef, [ exists => $_[2] ]);
   };
+
+  # 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;
 }
 
@@ -79,40 +94,43 @@ sub _expand_select_clause_from {
 sub _expand_select_clause_where {
   my ($self, undef, $where) = @_;
 
-  local (@{$self->{expand}}{qw(ident value)},
-         @{$self->{expand_op}}{qw(ident value)},
-         $self->{expand_op}{bind})
-     = (map {
-      my $orig = $self->{expand}{$_};
-      sub {
-        my $self = shift;
-        +{ -func => [
-          $self->{convert},
-          $self->$orig(@_)
-        ] };
-      }
-    } qw(ident value ident value bind)
-  ) if $self->{convert};
-
-  local $self->{expand}{func} = do {
-    my $orig = $self->{expand}{func};
-    sub {
-      my ($self, $type, $thing) = @_;
-      if (ref($thing) eq 'ARRAY' and $thing->[0] eq $self->{convert}
-          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);
+  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;
     }
-  } if $self->{convert};
+  };
 
-  my $exp = $self->expand_expr($where);
-  +(where => $exp);
+  return +(where => $sqla->expand_expr($where));
 }
 
 sub _expand_select_clause_order_by {
@@ -202,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
@@ -226,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 {
@@ -245,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 {
@@ -260,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 {
@@ -275,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 {
@@ -357,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 {