Start working on update clause
[dbsrgits/SQL-Abstract-2.0-ish.git] / lib / SQL / Abstract / AST / v1.pm
index 2c00f26..54b4172 100644 (file)
@@ -19,11 +19,13 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
       %{super()},
       in => $self->can('_in'),
       not_in => $self->can('_in'),
+      between => $self->can('_between'),
+      not_between => $self->can('_between'),
       and => $self->can('_recurse_where'),
       or => $self->can('_recurse_where'),
       map { +"$_" => $self->can("_$_") } qw/
         value
-        name
+        identifier
         true
         false
         expr
@@ -78,6 +80,15 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     return join(' ', @output);
   }
 
+  method _update(AST $ast) {
+
+    for (qw/columns values tablespec/) {
+      confess "'$_' is required in update AST with " . dump ($ast)
+        unless exists $ast->{$_};
+    }
+    
+  }
+
   method _join(HashRef $ast) {
 
     # TODO: Validate join type
@@ -114,10 +125,10 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     return $output;
   }
 
-  method _name(AST $ast) {
-    my @names = @{$ast->{args}};
+  method _identifier(AST $ast) {
+    my @names = @{$ast->{elements}};
 
-    my $sep = $self->name_separator;
+    my $sep = $self->ident_separator;
     my $quote = $self->is_quoting 
               ? $self->quote_chars
               : [ '' ];
@@ -203,7 +214,9 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
       if ($_->{-type} eq 'expr' && $_->{op} =~ /^(and|or)$/) {
         my $sub_prio = $SQL::Abstract::PRIO{$1}; 
 
-        if ($sub_prio <= $prio) {
+        if ($sub_prio == $prio) {
+          # When the element below has same priority, i.e. 'or' as a child of
+          # 'or', dont produce extra brackets
           push @output, $self->_recurse_where($_);
         } else {
           push @output, '(' . $self->_recurse_where($_) . ')';
@@ -242,6 +255,15 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     my ($lhs, $rhs) = @{$ast->{args}};
     my $op = $ast->{op};
 
+    # IS NOT? NULL
+    if ($rhs->{-type} eq 'value' && !defined $rhs->{value} &&
+        ($op eq '==' || $op eq '!='))
+    {
+      return $self->_expr($lhs) .
+             ($op eq '==' ? " IS " : " IS NOT ") .
+             "NULL";
+    }
+
     join (' ', $self->_expr($lhs), 
                $self->binop_mapping($op) || croak("Unknown binary operator $op"),
                $self->_expr($rhs)
@@ -269,6 +291,23 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
            ")";
   }
 
+  method _between(AST $ast) {
+  
+    my ($field,@values) = @{$ast->{args}};
+
+    my $not = ($ast->{op} =~ /^not_/) ? " NOT" : "";
+    croak "between requires 3 arguments: " . dump($ast)
+      unless @values == 2;
+
+    # The brackets are to work round an issue with SQL::A::Test
+    return "(" .
+           $self->_expr($field) .
+           $not . 
+           " BETWEEN " .
+           join(" AND ", map { $self->dispatch($_) } @values ) .
+           ")";
+  }
+
   # 'constants' that are portable across DBs
   method _false($ast?) { "0 = 1" }
   method _true($ast?) { "1 = 1" }