is_op and register_op
[scpubgit/Q-Branch.git] / lib / SQL / Abstract / Clauses.pm
index f60ddad..88a3226 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 {
@@ -160,11 +206,10 @@ sub _render_statement {
     };
     push @parts, $part;
   }
-  my ($sql, @bind) = @{ $self->join_query_parts(' ', @parts) };
-  return [
-    (our $Render_Top_Level ? $sql : '('.$sql.')'),
-    @bind
-  ];
+  my $q = $self->join_query_parts(' ', @parts);
+  return $self->join_query_parts('',
+    (our $Render_Top_Level ? $q : ('(', $q, ')'))
+  );
 }
 
 sub render_aqt {
@@ -182,7 +227,6 @@ sub render_statement {
 
 sub select {
   my ($self, @args) = @_;
-
   my $stmt = do {
     if (ref(my $sel = $args[0]) eq 'HASH') {
       $sel
@@ -270,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 {
@@ -327,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 {