has_a works
Matt S Trout [Fri, 22 Jul 2005 22:03:18 +0000 (22:03 +0000)]
12 files changed:
lib/DBIx/Class/AccessorGroup.pm
lib/DBIx/Class/CDBICompat.pm
lib/DBIx/Class/CDBICompat/ColumnCase.pm
lib/DBIx/Class/CDBICompat/ImaDBI.pm
lib/DBIx/Class/CDBICompat/LazyLoading.pm
lib/DBIx/Class/CDBICompat/Triggers.pm
lib/DBIx/Class/Core.pm
lib/DBIx/Class/PK.pm
lib/DBIx/Class/Table.pm
t/cdbi-t/01-columns.t
t/cdbi-t/02-Film.t
t/cdbi-t/19-set_sql.t

index 51dd7bc..7a2da2c 100644 (file)
@@ -1,5 +1,12 @@
 package DBIx::Class::AccessorGroup;
 
+use strict;
+use warnings;
+
+use base qw/Class::Data::Inheritable/;
+
+__PACKAGE__->mk_classdata('_accessor_group_deleted' => { });
+
 sub mk_group_accessors {
     my($self, $group, @fields) = @_;
 
@@ -9,6 +16,7 @@ sub mk_group_accessors {
 
 {
     no strict 'refs';
+    no warnings 'redefine';
 
     sub _mk_group_accessors {
         my($self, $maker, $group, @fields) = @_;
@@ -27,11 +35,13 @@ sub mk_group_accessors {
             my $accessor = $self->$maker($group, $field);
             my $alias = "_${field}_accessor";
 
-            *{$class."\:\:$field"}  = $accessor
-              unless defined &{$class."\:\:$field"};
+            #warn "$class $group $field $alias";
 
-            *{$class."\:\:$alias"}  = $accessor
-              unless defined &{$class."\:\:$alias"};
+            *{$class."\:\:$field"}  = $accessor;
+              #unless defined &{$class."\:\:$field"}
+
+            *{$class."\:\:$alias"}  = $accessor;
+              #unless defined &{$class."\:\:$alias"}
         }
     }
 }
@@ -59,10 +69,10 @@ sub make_group_accessor {
         my $self = shift;
 
         if(@_) {
-            return $self->set($field, @_);
+            return $self->$set($field, @_);
         }
         else {
-            return $self->get($field);
+            return $self->$get($field);
         }
     };
 }
@@ -82,7 +92,7 @@ sub make_group_ro_accessor {
                         "objects of class '$class'");
         }
         else {
-            return $self->get($field);
+            return $self->$get($field);
         }
     };
 }
@@ -102,9 +112,18 @@ sub make_group_wo_accessor {
                         "objects of class '$class'");
         }
         else {
-            return $self->set($field, @_);
+            return $self->$set($field, @_);
         }
     };
 }
 
+sub delete_accessor {
+  my ($class, $accessor) = @_;
+  $class = ref $class if ref $class;
+  my $sym = "${class}::${accessor}";
+  undef &$sym;
+  delete $DB::sub{$sym};
+  #$class->_accessor_group_deleted->{"${class}::${accessor}"} = 1;
+}
+
 1;
index fc30d0a..c5e2634 100644 (file)
@@ -13,6 +13,7 @@ use base qw/DBIx::Class::CDBICompat::Convenience
             DBIx::Class::CDBICompat::Constructor
             DBIx::Class::CDBICompat::AccessorMapping
             DBIx::Class::CDBICompat::ColumnCase
+            DBIx::Class::CDBICompat::HasA
             DBIx::Class::CDBICompat::LazyLoading
             DBIx::Class::CDBICompat::AutoUpdate
             DBIx::Class::CDBICompat::ColumnGroups
index e5c23d8..d6f527c 100644 (file)
@@ -6,32 +6,55 @@ use NEXT;
 
 sub _register_column_group {
   my ($class, $group, @cols) = @_;
-  return $class->NEXT::_register_column_group($group => map lc, @cols);
+  return $class->NEXT::ACTUAL::_register_column_group($group => map lc, @cols);
 }
 
 sub _register_columns {
   my ($class, @cols) = @_;
-  return $class->NEXT::_register_columns(map lc, @cols);
+  return $class->NEXT::ACTUAL::_register_columns(map lc, @cols);
+}
+
+sub has_a {
+  my ($class, $col, @rest) = @_;
+  $class->NEXT::ACTUAL::has_a(lc($col), @rest);
+  $class->delete_accessor($col);
+  $class->mk_group_accessors('has_a' => $col);
+  return 1;
+}
+
+sub get_has_a {
+  my ($class, $get, @rest) = @_;
+  return $class->NEXT::ACTUAL::get_has_a(lc($get), @rest);
+}
+
+sub store_has_a {
+  my ($class, $set, @rest) = @_;
+  return $class->NEXT::ACTUAL::store_has_a(lc($set), @rest);
+}
+
+sub set_has_a {
+  my ($class, $set, @rest) = @_;
+  return $class->NEXT::ACTUAL::set_has_a(lc($set), @rest);
 }
 
 sub get_column {
   my ($class, $get, @rest) = @_;
-  return $class->NEXT::get_column(lc $get, @rest);
+  return $class->NEXT::ACTUAL::get_column(lc($get), @rest);
 }
 
 sub set_column {
   my ($class, $set, @rest) = @_;
-  return $class->NEXT::set_column(lc $set, @rest);
+  return $class->NEXT::ACTUAL::set_column(lc($set), @rest);
 }
 
 sub store_column {
   my ($class, $set, @rest) = @_;
-  return $class->NEXT::store_column(lc $set, @rest);
+  return $class->NEXT::ACTUAL::store_column(lc($set), @rest);
 }
 
 sub find_column {
   my ($class, $col) = @_;
-  return $class->NEXT::find_column(lc $col);
+  return $class->NEXT::ACTUAL::find_column(lc($col));
 }
 
 sub _mk_group_accessors {
@@ -39,7 +62,24 @@ sub _mk_group_accessors {
   my %fields;
   $fields{$_} = 1 for @fields,
                     map lc, grep { !defined &{"${class}::${_}"} } @fields;
-  return $class->NEXT::_mk_group_accessors($type, $group, keys %fields);
+  return $class->NEXT::ACTUAL::_mk_group_accessors($type, $group, keys %fields);
+}
+
+sub _cond_key {
+  my ($class, $attrs, $key, @rest) = @_;
+  return $class->NEXT::ACTUAL::_cond_key($attrs, lc($key), @rest);
+}
+
+sub _cond_value {
+  my ($class, $attrs, $key, @rest) = @_;
+  return $class->NEXT::ACTUAL::_cond_value($attrs, lc($key), @rest);
+}
+
+sub new {
+  my ($class, $attrs, @rest) = @_;
+  my %att;
+  $att{lc $_} = $attrs->{$_} for keys %$attrs;
+  return $class->NEXT::ACTUAL::new(\%att, @rest);
 }
 
 1;
index f702f14..d0f16f2 100644 (file)
@@ -6,10 +6,49 @@ use warnings;
 use NEXT;
 use base qw/Class::Data::Inheritable/;
 
+__PACKAGE__->mk_classdata('_transform_sql_handler_order'
+                            => [ qw/TABLE ESSENTIAL JOIN/ ] );
+
 __PACKAGE__->mk_classdata('_transform_sql_handlers' =>
   {
-    'TABLE' => sub { return $_[0]->_table_name },
-    'ESSENTIAL' => sub { join(' ', $_[0]->columns('Essential')) },
+    'TABLE' =>
+      sub {
+        my ($self, $class, $data) = @_;
+        return $class->_table_name unless $data;
+        my ($f_class, $alias) = split(/=/, $data);
+        $f_class ||= $class;
+        $self->{_aliases}{$alias} = $f_class;
+        return $f_class->_table_name." ${alias}";
+      },
+    'ESSENTIAL' =>
+      sub {
+        my ($self, $class, $data) = @_;
+        return join(' ', $class->columns('Essential')) unless $data;
+        return join(' ', $self->{_aliases}{$data}->columns('Essential'));
+      },
+    'JOIN' =>
+      sub {
+        my ($self, $class, $data) = @_;
+        my ($from, $to) = split(/ /, $data);
+        my ($from_class, $to_class) = @{$self->{_aliases}}{$from, $to};
+        my ($rel_obj) = grep { $_->{class} && $_->{class} eq $to_class }
+                          values %{ $from_class->_relationships };
+        unless ($rel_obj) {
+          ($from, $to) = ($to, $from);
+          ($from_class, $to_class) = ($to_class, $from_class);
+          ($rel_obj) = grep { $_->{class} && $_->{class} eq $to_class }
+                         values %{ $from_class->_relationships };
+        }
+        die "No relationship to JOIN from ${from_class} to ${to_class}"
+          unless $rel_obj;
+        my $attrs = {
+          _aliases => { self => $from, foreign => $to },
+          _action => 'join',
+        };
+        my $join = $from_class->_cond_resolve($rel_obj->{cond}, $attrs);
+        return $join;
+      }
+        
   } );
 
 sub db_Main {
@@ -51,9 +90,10 @@ sub set_sql {
 sub transform_sql {
   my ($class, $sql, @args) = @_;
   my $table = $class->_table_name;
-  foreach my $key (keys %{ $class->_transform_sql_handlers }) {
+  my $attrs = { };
+  foreach my $key (@{$class->_transform_sql_handler_order}) {
     my $h = $class->_transform_sql_handlers->{$key};
-    $sql =~ s/__$key(?:\(([^\)]+)\))?__/$h->($class, $1)/eg;
+    $sql =~ s/__$key(?:\(([^\)]+)\))?__/$h->($attrs, $class, $1)/eg;
   }
   return sprintf($sql, @args);
 }
index ed61535..e991cc0 100644 (file)
@@ -23,6 +23,7 @@ sub _flesh {
   my %want;
   $want{$_} = 1 for map { keys %{$self->_column_groups->{$_}} } @groups;
   if (my @want = grep { !exists $self->{'_column_data'}{$_} } keys %want) {
+    #warn "@want";
     my $sth = $self->_get_sth('select', \@want, $self->_table_name,
                                 $self->_ident_cond); 
     $sth->execute($self->_ident_values);
index 21826f9..46a0d49 100644 (file)
@@ -5,7 +5,7 @@ use Class::Trigger;
 sub insert {
   my $self = shift;
   $self->call_trigger('before_create');
-  $self->NEXT::insert(@_);
+  $self->NEXT::ACTUAL::insert(@_);
   $self->call_trigger('after_create');
   return $self;
 }
@@ -15,7 +15,7 @@ sub update {
   $self->call_trigger('before_update');
   my @to_update = keys %{$self->{_dirty_columns} || {}};
   return -1 unless @to_update;
-  $self->NEXT::update(@_);
+  $self->NEXT::ACTUAL::update(@_);
   $self->call_trigger('after_update');
   return $self;
 }
@@ -23,7 +23,7 @@ sub update {
 sub delete {
   my $self = shift;
   $self->call_trigger('before_delete') if ref $self;
-  $self->NEXT::delete(@_);
+  $self->NEXT::ACTUAL::delete(@_);
   $self->call_trigger('after_delete') if ref $self;
   return $self;
 }
index 14b5367..fb412cc 100644 (file)
@@ -3,7 +3,9 @@ package DBIx::Class::Core;
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::PK
+use base qw/DBIx::Class::Relationship
+            DBIx::Class::SQL::Abstract
+            DBIx::Class::PK
             DBIx::Class::Table
             DBIx::Class::SQL
             DBIx::Class::DB
index 2725ff9..d1dc87c 100644 (file)
@@ -32,14 +32,18 @@ sub retrieve {
   if (ref $vals[0] eq 'HASH') {
     $query = $vals[0];
   } elsif (@pk == @vals) {
-    return ($class->retrieve_from_sql($class->_ident_cond, @vals))[0];
+    my $ret = ($class->retrieve_from_sql($class->_ident_cond, @vals))[0];
+    #warn "$class: ".join(', ', %{$ret->{_column_data}});
+    return $ret;
   } else {
     $query = {@vals};
   }
   die "Can't retrieve unless all primary keys are specified"
     unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
                                   # column names etc. Not sure what to do yet
-  return ($class->search($query))[0];
+  my $ret = ($class->search($query))[0];
+  #warn "$class: ".join(', ', %{$ret->{_column_data}});
+  return $ret;
 }
 
 sub discard_changes {
index 9873ce4..eabc9e7 100644 (file)
@@ -66,10 +66,14 @@ sub delete {
     $sth->finish;
     delete $self->{_in_database};
   } else {
+    my $attrs = { };
+    if (@_ > 1 && ref $_[$#_] eq 'HASH') {
+      $attrs = { %{ pop(@_) } };
+    }
     my $query = (ref $_[0] eq 'HASH' ? $_[0] : {@_});
-    my ($cond, $param) = $self->_where_from_hash($query);
+    my ($cond, @param) = $self->_cond_resolve($query, $attrs);
     my $sth = $self->_get_sth('delete', undef, $self->_table_name, $cond);
-    $sth->execute(@$param);
+    $sth->execute(@param);
     $sth->finish;
   }
   return $self;
@@ -138,17 +142,23 @@ sub sth_to_objects {
 }
 
 sub search {
-  my $class    = shift;
-  my $where    = ref $_[0] eq "HASH" ? shift: {@_};
-  my ($cond, $param)  = $class->_where_from_hash($where);
-  return $class->retrieve_from_sql($cond, @{$param});
+  my $class = shift;
+  my $attrs = { };
+  if (@_ > 1 && ref $_[$#_] eq 'HASH') {
+    $attrs = { %{ pop(@_) } };
+  }
+  my $query    = ref $_[0] eq "HASH" ? shift: {@_};
+  my ($cond, @param)  = $class->_cond_resolve($query, $attrs);
+  return $class->retrieve_from_sql($cond, @param);
 }
 
 sub search_like {
   my $class    = shift;
-  my $where    = ref $_[0] eq "HASH" ? shift: {@_};
-  my ($cond, $param)  = $class->_where_from_hash($where, { cmp => 'like' });
-  return $class->retrieve_from_sql($cond, @{$param});
+  my $attrs = { };
+  if (@_ > 1 && ref $_[$#_] eq 'HASH') {
+    $attrs = pop(@_);
+  }
+  return $class->search(@_, { %$attrs, cmp => 'LIKE' });
 }
 
 sub _select_columns {
@@ -162,15 +172,15 @@ sub copy {
   return $new->insert;
 }
 
-sub _where_from_hash {
-  my ($self, $query, $opts) = @_;
-  my $op = $opts->{'cmp'} || '=';
+sub _cond_resolve {
+  my ($self, $query, $attrs) = @_;
+  my $op = $attrs->{'cmp'} || '=';
   my $cond = join(' AND ',
                map { (defined $query->{$_}
                        ? "$_ $op ?"
                        : (do { delete $query->{$_}; "$_ IS NULL"; }));
                    } keys %$query);
-  return ($cond, [ values %$query ]);
+  return ($cond, values %$query);
 }
 
 sub table {
index 6b3346c..2c5fa2e 100644 (file)
@@ -37,7 +37,7 @@ use base 'DBIx::Class';
 
 City->table('City');
 City->columns(All => qw/Name State Population/);
-#City->has_a(State => 'State');
+City->has_a(State => 'State');
 
 
 #-------------------------------------------------------------------------
index bec54a2..68ee88d 100644 (file)
@@ -280,7 +280,7 @@ print join("\n", @warnings);
 
 # Change after_update policy
 SKIP: {
-        skip "DBIx::Class compat doesn't handle triggers yet", 4;
+        skip "DBIx::Class compat doesn't handle the exists stuff quite right yet", 4;
        my $bt = Film->retrieve($btaste->id);
        $bt->autoupdate(1);
 
index 2278cd4..2b986bd 100644 (file)
@@ -62,8 +62,8 @@ Film->set_sql(
        is $pgs[1]->id, $f4->id, "and F4";
 };
 
-SKIP: {
-  skip "DBIx::Class doesn't have has_a yet", 6;
+#SKIP: {
+#  skip "DBIx::Class doesn't have has_a yet", 6;
 {
        Actor->has_a(film => "Film");
        Film->set_sql(
@@ -106,4 +106,4 @@ SKIP: {
        is $apg[1]->title, "B", "and B";
 }
 
-} # end SKIP block
+#} # end SKIP block