Work on compat layer
[dbsrgits/SQL-Abstract-2.0-ish.git] / lib / SQL / Abstract / Compat.pm
index 471ca04..3928a78 100644 (file)
@@ -18,7 +18,8 @@ class SQL::Abstract::Compat {
     is => 'rw',
     isa => LogicEnum,
     default => 'AND',
-    coerce => 1
+    coerce => 1,
+    required => 1,
   );
 
   has visitor => (
@@ -29,16 +30,40 @@ class SQL::Abstract::Compat {
     builder => '_build_visitor',
   );
 
+  has cmp => (
+    is => 'rw',
+    isa => 'Str',
+    default => '=',
+    required => 1,
+  );
+
+  our %CMP_MAP = (
+    '=' => '==',
+  );
+
+  has convert => (
+    is => 'rw',
+    isa => 'Str',
+    predicate => 'has_field_convertor'
+  );
 
   method select(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
                 WhereType $where?,
                 WhereType $order?)
   {
+    my $ast = $self->select_ast($from,$fields,$where,$order);
+
+    return ($self->visitor->dispatch($ast), $self->visitor->binds);
+  }
+  method select_ast(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
+                WhereType $where?,
+                WhereType $order?)
+  {
     my $ast = {
       -type => 'select',
       columns => [ 
         map {
-          $self->mk_name($_)
+          $self->mk_name(0, $_)
         } ( is_Str($fields) ? $fields : @$fields )
       ],
       tablespec => $self->tablespec($from)
@@ -47,8 +72,7 @@ class SQL::Abstract::Compat {
 
     $ast->{where} = $self->recurse_where($where)
       if defined $where;
-
-    return ($self->visitor->dispatch($ast), $self->visitor->binds);
+    return $ast;
   }
 
   method where(WhereType $where,
@@ -69,12 +93,17 @@ class SQL::Abstract::Compat {
   } 
 
   sub mk_name {
-    shift;
-    return { -type => 'name', args => [ @_ ] };
+    my ($self, $use_convert) = (shift,shift);
+    my $ast = { -type => 'name', args => [ @_ ] };
+
+    return $ast
+      unless $use_convert && $self->has_field_convertor;
+
+    return $self->apply_convert($ast);
   }
 
   method tablespec(Str|ArrayRef|ScalarRef $from) {
-    return $self->mk_name($from)
+    return $self->mk_name(0, $from)
       if is_Str($from);
   }
 
@@ -145,11 +174,12 @@ class SQL::Abstract::Compat {
   }
 
   method field(Str $key, $value) returns (AST) {
+    my $op = $CMP_MAP{$self->cmp} || $self->cmp;
     my $ret = {
       -type => 'expr',
-      op => '==',
+      op => $op,
       args => [
-        { -type => 'name', args => [$key] }
+        $self->mk_name(1, $key)
       ],
     };
 
@@ -157,22 +187,38 @@ class SQL::Abstract::Compat {
       my ($op, @rest) = keys %$value;
       confess "Don't know how to handle " . dump($value) . " (too many keys)"
         if @rest;
+      $value = $value->{$op};
 
       # TODO: Validate the op?
-      if ($op =~ /^-([a-z_]+)$/i) {
-        $ret->{op} = lc $1;
+      if ($op =~ /^-?(?:(not)[_ ])?([a-z_]+)$/i) {
+        $ret->{op} = lc $2;
+        $ret->{op} = "not_" . $ret->{op} if $1;
 
-        if (is_ArrayRef($value->{$op})) {
+        if (is_ArrayRef($value)) {
           push @{$ret->{args}}, $self->value($_)
-            for @{$value->{$op}};
+            for @{$value};
           return $ret;
         }
       }
       else {
         $ret->{op} = $op;
       }
-
-      push @{$ret->{args}}, $self->value($value->{$op});
+      
+      if (is_ArrayRef($value)) {
+        local $self->{cmp} = $op;
+
+        my $ast = {
+          -type => 'expr',
+          # Handle e => { '!=', [qw(f g)] }.
+          # SQLA treats this as a 'DWIM'
+          op => $op eq '!=' ? 'or' : 'and',
+          args => [ map {
+            $self->field($key, $_)
+          } @{$value} ]
+        };
+        return $ast;
+      }
+      push @{$ret->{args}}, $self->value($value);
 
     }
     elsif (is_ArrayRef($value)) {
@@ -181,14 +227,7 @@ class SQL::Abstract::Compat {
         -type => 'expr',
         op => 'or',
         args => [ map {
-          {
-            -type => 'expr',
-            op => '==',
-            args => [
-              { -type => 'name', args => [$key] },
-              $self->value($_)
-            ],
-          }
+            $self->field($key, $_)
         } @$value ]
       };
     }
@@ -200,12 +239,22 @@ class SQL::Abstract::Compat {
   }
 
   method value($value) returns (AST) {
-    return { -type => 'value', value => $value }
+    return $self->apply_convert( { -type => 'value', value => $value })
       if is_Str($value);
 
     confess "Don't know how to handle terminal value " . dump($value);
   }
 
+  method apply_convert(AST $ast) {
+    return $ast unless $self->has_field_convertor;
+
+    return {
+      -type => 'expr',
+      op => $self->convert,
+      args => [ $ast ]
+    };
+  }
+
 
 }