ORDER BY, HAVING, GROUP BY and WHERE clauses on select
Ash Berlin [Sat, 14 Mar 2009 17:17:02 +0000 (17:17 +0000)]
lib/SQL/Abstract/AST/v1.pm
t/001_basic.t
t/201_select.t
t/300_order_by.t [deleted file]
t/300_ordering.t [new file with mode: 0644]

index d0f4522..ae2e05c 100644 (file)
@@ -54,12 +54,21 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     push @output, FROM => $self->dispatch($ast->{tablespec})
       if exists $ast->{tablespec};
 
-    for (qw/where having group_by/) {
+    if (exists $ast->{where}) {
+      my $sub_ast = $ast->{where};
+
+      confess "$_ option is not an AST: " . dump($sub_ast)
+        unless is_AST($sub_ast);
+
+      push @output, "WHERE", $self->_expr($sub_ast);
+    }
+
+    for (qw/group_by having order_by/) {
       if (exists $ast->{$_}) {
         my $sub_ast = $ast->{$_};
 
-        confess "$_ option is not an AST: " . dump($sub_ast)
-          unless is_AST($sub_ast);
+        confess "$_ option is not an AST or an ArrayRef: " . dump($sub_ast)
+          unless is_AST($sub_ast) || is_ArrayRef($sub_ast);;
 
         my $meth = "__$_";
         push @output, $self->$meth($sub_ast);
@@ -82,28 +91,27 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     push @output, 
         exists $ast->{on}
       ? ('ON', '(' . $self->_expr( $ast->{on} ) . ')' )
-      : ('USING', '(' .$self->dispatch($ast->{using} || croak "No 'on' or 'join' clause passed to -join").
+      : ('USING', '(' .$self->dispatch($ast->{using} 
+                        || croak "No 'on' or 'uinsg' clause passed to join cluase: " .
+                                 dump($ast) 
+                        ) .
                   ')' );
 
     return join(" ", @output);
       
   }
 
-  method _order_by(AST $ast) {
-    my @clauses = @{$ast->{order_by}};
-  
-    my @output;
-   
-    for (@clauses) {
-      if (is_ArrayRef($_) && $_->[0] =~ /^-(asc|desc)$/) {
-        my $o = $1;
-        push @output, $self->dispatch($_->[1]) . " " . uc($o);
-        next;
-      }
-      push @output, $self->dispatch($_);
-    }
+  method _ordering(AST $ast) {
+    my $output = $self->_expr($ast->{expr});
+
+    $output .= " " . uc $1
+      if $ast->{direction} && 
+         ( $ast->{direction} =~ /^(asc|desc)$/i 
+           || confess "Unknown ordering direction " . dump($ast)
+         );
 
-    return "ORDER BY " . join(", ", @output);
+    return $output;
   }
 
   method _name(HashAST $ast) {
@@ -133,7 +141,9 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
 
 
   method _list(AST $ast) {
-    my @items = @{$ast->{args}};
+    my @items = is_ArrayRef($ast->{args})
+              ? @{$ast->{args}}
+              : $ast->{args};
 
     return join(
       $self->list_separator,
@@ -155,10 +165,19 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
   }
 
   # Not dispatchable to.
-  method __where(HashAST $ast) {
-    return "WHERE " . $self->_expr($ast);
+  method __having($args) {
+    return "HAVING " . $self->_list({-type => 'list', args => $args});
+  }
+
+  method __group_by($args) {
+    return "GROUP BY " . $self->_list({-type => 'list', args => $args});
   }
 
+  method __order_by($args) {
+    return "ORDER BY " . $self->_list({-type => 'list', args => $args});
+  }
+
+
   # Perhaps badly named. handles 'and' and 'or' clauses
   method _recurse_where(HashAST $ast) {
 
index 728d948..849a982 100644 (file)
@@ -1,10 +1,11 @@
 use strict;
 use warnings;
 
-use Test::More tests => 8;
+use Test::More tests => 9;
 use Test::Differences;
 
 use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
+use_ok('SQL::Abstract::AST::v1') or BAIL_OUT( "$@" );
 
 my $sqla = SQL::Abstract->create(1);
 
index d27a327..b20dc46 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 4;
+use Test::More tests => 5;
 use Test::Differences;
 
 use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
@@ -72,3 +72,19 @@ is $sqla->dispatch(
 
 ), "SELECT me.* FROM foo AS me WHERE me.id = ?",
    "select with where";
+
+
+is $sqla->dispatch(
+  { -type => 'select',
+    tablespec => $foo_as_me,
+    columns => [
+      { -type => 'name', args => [qw/me id/] },
+      { -type => 'alias', ident => $me_foo_id, as => 'foo' },
+    ],
+    order_by => [
+      { -type => 'ordering', expr => { -type => 'name', args => [qw/me name/] }, direction => 'desc' },
+      $me_foo_id,
+    ]
+  }
+), "SELECT me.id, me.foo_id AS foo FROM foo AS me ORDER BY me.name DESC, me.foo_id",
+   "select clause with order by";
diff --git a/t/300_order_by.t b/t/300_order_by.t
deleted file mode 100644 (file)
index ee12886..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-use strict;
-use warnings;
-
-use Test::More tests => 4;
-use Test::Differences;
-
-use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
-
-my $sqla = SQL::Abstract->create(1);
-
-
-is $sqla->dispatch(
-  { -type => 'order_by', order_by => [ { -type => name => args => [qw/me date/ ] } ] }
-), "ORDER BY me.date",
-   "order by";
-
-is $sqla->dispatch(
-  { -type => 'order_by',
-    order_by => [
-      { -type => name => args => [qw/me date/] },
-      { -type => name => args => [qw/me foobar/] },
-    ]
-  }
-), "ORDER BY me.date, me.foobar",
-   "order by";
-
-# Hrmmm how to mark this up.
-is $sqla->dispatch(
-  { -type => 'order_by', 
-    order_by => [
-      [ -desc => { -type => name => args => [qw/me date/ ] } ] 
-    ] 
-  }
-), "ORDER BY me.date DESC",
-   "order by desc";
diff --git a/t/300_ordering.t b/t/300_ordering.t
new file mode 100644 (file)
index 0000000..cf5456a
--- /dev/null
@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+use Test::Differences;
+
+use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
+
+my $sqla = SQL::Abstract->create(1);
+
+
+is $sqla->dispatch(
+  { -type => 'ordering', expr => { -type => name => args => [qw/me date/ ] } }
+), "me.date",
+   "basic ordering";
+
+is $sqla->dispatch(
+  { -type => 'ordering', 
+    expr => { -type => name => args => [qw/me date/] },
+    direction => 'DESC'
+  }
+), "me.date DESC",
+   "desc ordering";
+
+
+is $sqla->dispatch(
+  { -type => 'ordering', 
+    expr => { -type => name => args => [qw/me date/] },
+    direction => 'asc'
+  }
+), "me.date ASC",
+   "asc ordering";