Create ArrayAST, HashAST and AST types in a type library so that some constructs...
Ash Berlin [Tue, 10 Mar 2009 09:36:26 +0000 (09:36 +0000)]
.gitignore
lib/SQL/Abstract.pm
lib/SQL/Abstract/AST/v1.pm
lib/SQL/Abstract/Types.pm [new file with mode: 0644]
t/002_types.t [new file with mode: 0644]
t/200_join.t

index 38677d1..4359afb 100644 (file)
@@ -2,6 +2,6 @@
 Makefile
 META.yml
 .*.sw[op]
-blib/
+/blib/
 pm_to_blib
 Makefile.old
index f077979..e95b8b8 100644 (file)
@@ -10,16 +10,10 @@ class SQL::Abstract {
   use MooseX::Types -declare => [qw/NameSeparator/];
   use MooseX::Types::Moose qw/ArrayRef Str Int HashRef CodeRef/;
   use MooseX::AttributeHelpers;
+  use SQL::Abstract::Types qw/NameSeparator AST ArrayAST/;
 
   clean;
 
-  subtype NameSeparator,
-    as ArrayRef[Str];
-    #where { @$_ == 1 ||| @$_ == 2 },
-    #message { "Name separator must be one or two elements" };
-
-  coerce NameSeparator, from Str, via { [ $_ ] };
-
   our $VERSION = '2.000000';
 
   our $AST_VERSION = '1';
@@ -116,7 +110,7 @@ class SQL::Abstract {
   }
 
   # Main entry point
-  method generate(ClassName $class: ArrayRef $ast) {
+  method generate(ClassName $class: AST $ast) {
     croak "SQL::Abstract AST version not specified"
       unless ($ast->[0] eq '-ast_version');
 
@@ -132,12 +126,16 @@ class SQL::Abstract {
     $self->_clear_binds();
   }
 
-  method dispatch (ArrayRef $ast) {
-
-    local $_ = $ast->[0];
-    s/^-/_/ or croak "Unknown type tag '$_'";
+  method dispatch (AST $ast) {
+    # I want multi methods!
+    my $tag;
+    if (is_ArrayAST($ast)) {
+      ($tag = $ast->[0]) =~ s/^-/_/;
+    } else {
+      $tag = "_" . $ast->{-type};
+    }
     
-    my $meth = $self->can($_) || croak "Unknown tag '$_'";
+    my $meth = $self->can($tag) || croak "Unknown tag '$tag'";
     return $meth->($self, $ast);
   }
 
index f0ed698..7d269e4 100644 (file)
@@ -6,9 +6,9 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
   use Data::Dump qw/pp/;
 
   use Moose::Util::TypeConstraints;
-  use MooseX::Types -declare => [qw/NameSeparator/];
-  use MooseX::Types::Moose qw/ArrayRef Str Int/;
+  use MooseX::Types::Moose qw/ArrayRef Str Int Ref HashRef/;
   use MooseX::AttributeHelpers;
+  use SQL::Abstract::Types qw/AST ArrayAST HashAST/;
 
   clean;
 
@@ -27,17 +27,17 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     };
   }
 
-  method _select(ArrayRef $ast) {
+  method _select(HashAST $ast) {
     
   }
 
-  method _where(ArrayRef $ast) {
+  method _where(ArrayAST $ast) {
     my (undef, @clauses) = @$ast;
   
     return 'WHERE ' . $self->_recurse_where(\@clauses);
   }
 
-  method _order_by(ArrayRef $ast) {
+  method _order_by(ArrayAST $ast) {
     my (undef, @clauses) = @$ast;
 
     my @output;
@@ -54,7 +54,7 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     return "ORDER BY " . join(", ", @output);
   }
 
-  method _name(ArrayRef $ast) {
+  method _name(ArrayAST $ast) {
     my (undef, @names) = @$ast;
 
     my $sep = $self->name_separator;
@@ -67,20 +67,20 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     return join($sep->[0], @names);
   }
 
-  method _join(ArrayRef $ast) {
-    my (undef, @items) = @$ast;
+  method _join(HashAST $ast) {
   
-    croak "invalid component in JOIN: $_" unless ArrayRef->check($items[0]);
-    my @output = 'JOIN';
+    my $output = 'JOIN ' . $self->dispatch($ast->{tablespec});
+
+    $output .= exists $ast->{on}
+             ? ' ON (' . $self->_recurse_where( $ast->{on} )
+             : ' USING (' .$self->dispatch($ast->{using} || croak "No 'on' or 'join' clause passed to -join");
 
-    # TODO: Validation of inputs
-    return 'JOIN '. $self->dispatch(shift @items) .
-                  ' ON (' .
-                  $self->_recurse_where( \@items ) . ')';
+    $output .= ")";
+    return $output;
       
   }
 
-  method _list(ArrayRef $ast) {
+  method _list(ArrayAST $ast) {
     my (undef, @items) = @$ast;
 
     return join(
@@ -88,37 +88,41 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
       map { $self->dispatch($_) } @items);
   }
 
-  method _alias(ArrayRef $ast) {
+  method _alias(ArrayAST $ast) {
     my (undef, $alias, $as) = @$ast;
 
     return $self->dispatch($alias) . " AS $as";
 
   }
 
-  method _value(ArrayRef $ast) {
+  method _value(ArrayAST $ast) {
     my ($undef, $value) = @$ast;
 
     $self->add_bind($value);
     return "?";
   }
 
-  method _recurse_where($clauses) {
+  method _recurse_where(ArrayRef $clauses) {
 
     my $OP = 'AND';
     my $prio = $SQL::Abstract::PRIO{and};
     my $first = $clauses->[0];
 
-    if (!ref $first && $first =~ /^-(and|or)$/) {
-      $OP = uc($1);
-      $prio = $SQL::Abstract::PRIO{$1};
-      shift @$clauses;
+    if (!ref $first) {
+      if ($first =~ /^-(and|or)$/) {
+        $OP = uc($1);
+        $prio = $SQL::Abstract::PRIO{$1};
+        shift @$clauses;
+      } else {
+        $clauses = [ $clauses ];
+      }
     }
 
     my $dispatch_table = $self->where_dispatch_table;
 
     my @output;
     foreach (@$clauses) {
-      croak "invalid component in where clause: $_" unless ArrayRef->check($_);
+      croak "invalid component in where clause: $_" unless is_ArrayRef($_);
       my $op = $_->[0];
 
       if ($op =~ /^-(and|or)$/) {
@@ -137,7 +141,7 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     return join(" $OP ", @output);
   }
 
-  method _where_component($ast) {
+  method _where_component(ArrayRef $ast) {
     my $op = $ast->[0];
 
     if (my $code = $self->lookup_where_dispatch($op)) { 
@@ -153,7 +157,7 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
   }
 
 
-  method _binop($ast) {
+  method _binop(ArrayRef $ast) {
     my ($op, $lhs, $rhs) = @$ast;
 
     join (' ', $self->_where_component($lhs), 
@@ -162,7 +166,7 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
     );
   }
 
-  method _in($ast) {
+  method _in(ArrayAST $ast) {
     my ($tag, $field, @values) = @$ast;
 
     my $not = $tag =~ /^-not/ ? " NOT" : "";
@@ -175,19 +179,6 @@ class SQL::Abstract::AST::v1 extends SQL::Abstract {
            ")";
   }
 
-  method _like($ast) {
-    my ($tag, $field, @values) = @$ast;
-
-    my $not = $tag =~ /^-not/ ? " NOT" : "";
-
-    return $self->_false if @values == 0;
-    return $self->_where_component($field) .
-           $not. 
-           " LIKE " .
-           join(", ", map { $self->_where_component($_) } @values ) .
-           "";
-  }
-
   method _generic_func(ArrayRef $ast) {
   }
 
diff --git a/lib/SQL/Abstract/Types.pm b/lib/SQL/Abstract/Types.pm
new file mode 100644 (file)
index 0000000..272584d
--- /dev/null
@@ -0,0 +1,26 @@
+use MooseX::Declare;
+class SQL::Abstract::Types {
+  use Moose::Util::TypeConstraints;
+  use MooseX::Types -declare => [qw/NameSeparator AST ArrayAST HashAST/];
+  use MooseX::Types::Moose qw/ArrayRef Str Int Ref HashRef/;
+
+  subtype ArrayAST, as ArrayRef,
+    where { is_Str($_->[0]) && substr($_->[0],0,1) eq '-' },
+    message { "First key of arrayref must be a string starting with '-'"; };
+
+  subtype HashAST, as HashRef,
+    where { exists $_->{-type} && is_Str($_->{-type}) },
+    message { "No '-type' key, or it is not a string" };
+
+  subtype AST, as ArrayAST|HashAST; 
+
+  subtype NameSeparator,
+    as ArrayRef[Str];
+    #where { @$_ == 1 ||| @$_ == 2 },
+    #message { "Name separator must be one or two elements" };
+
+  coerce NameSeparator, from Str, via { [ $_ ] };
+
+}
+
+1;
diff --git a/t/002_types.t b/t/002_types.t
new file mode 100644 (file)
index 0000000..e4b7486
--- /dev/null
@@ -0,0 +1,20 @@
+use strict;
+use warnings;
+
+use Test::More tests => 7;
+
+use MooseX::Types::Moose qw/ArrayRef Str Int Ref HashRef/;
+use SQL::Abstract::Types ':all';
+
+is(ArrayAST->validate( [ -foo => 'bar' ] ), undef, "is_ArrayAST with valid" );
+ok(!is_ArrayAST( [ foo => 'bar' ] ), "is_ArrayAST with invalid" );
+
+
+is(HashAST->validate( { -type => 'select', select => [] } ), undef, "is_HashAST with valid" );
+ok(!is_HashAST( { foo => 'bar' } ), "is_HashAST with invalid" );
+
+
+is(AST->validate( { -type => 'select', select => [] } ), undef, "is_AST with valid hash" );
+is(AST->validate( [ -name => 1, 2 ] ), undef, "is_AST with valid array" );
+
+is(is_AST([ -name => qw/me id/]), 1);
index 2e89ebc..176ab81 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 2;
+use Test::More tests => 3;
 use Test::Differences;
 
 use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
@@ -9,10 +9,17 @@ use_ok('SQL::Abstract') or BAIL_OUT( "$@" );
 my $sqla = SQL::Abstract->create(1);
 
 is $sqla->dispatch(
-  [ -join =>
-      [-name => qw/foo/],
-      [ '==', [-name => qw/foo id/], [ -name => qw/me foo_id/ ] ]
-  ]
+  { -type => 'join',
+    tablespec => [-name => qw/foo/],
+    on => [ '==', [-name => qw/foo id/], [ -name => qw/me foo_id/ ] ],
+  }
 ), "JOIN foo ON (foo.id = me.foo_id)", 
    "simple join clause";
 
+is $sqla->dispatch(
+  { -type => 'join',
+    tablespec => [-alias => [-name => qw/foo/], 'bar' ],
+    using => [ -name => qw/foo_id/ ]
+  }
+), "JOIN foo AS bar USING (foo_id)", 
+   "using join clause";