Joins work for search, some refactoring
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / Base.pm
index 05f2508..0b12a3b 100644 (file)
@@ -38,10 +38,7 @@ sub add_relationship {
   #warn %{$f_class->_columns};
 
   return unless eval { %{$f_class->_columns}; }; # Foreign class not loaded
-  my %join = (%$attrs, _action => 'join',
-    _aliases => { 'self' => 'me', 'foreign' => $rel },
-    _classes => { 'me' => $class, $rel => $f_class });
-  eval { $class->resolve_condition($cond, \%join) };
+  eval { $class->_resolve_join($rel, 'me') };
 
   if ($@) { # If the resolve failed, back out and re-throw the error
     delete $rels{$rel}; # 
@@ -51,6 +48,29 @@ sub add_relationship {
   1;
 }
 
+sub _resolve_join {
+  my ($class, $join, $alias) = @_;
+  if (ref $join eq 'ARRAY') {
+    return map { $class->_resolve_join($_, $alias) } @$join;
+  } elsif (ref $join eq 'HASH') {
+    return map { $class->_resolve_join($_, $alias),
+                 $class->_relationships->{$_}{class}->_resolve_join($join->{$_}, $_) }
+           keys %$join;
+  } elsif (ref $join) {
+    $class->throw("No idea how to resolve join reftype ".ref $join);
+  } else {
+    my $rel_obj = $class->_relationships->{$join};
+    $class->throw("No such relationship ${join}") unless $rel_obj;
+    my $j_class = $rel_obj->{class};
+    my %join = (_action => 'join',
+         _aliases => { 'self' => $alias, 'foreign' => $join },
+         _classes => { $alias => $class, $join => $j_class });
+    my $j_cond = $j_class->resolve_condition($rel_obj->{cond}, \%join);
+    return [ { $join => $j_class->_table_name,
+               -join_type => $rel_obj->{attrs}{join_type} || '' }, $j_cond ];
+  }
+}
+
 sub resolve_condition {
   my ($self, $cond, $attrs) = @_;
   if (ref $cond eq 'HASH') {
@@ -110,10 +130,7 @@ sub _cond_value {
       my $class = $attrs->{_classes}{$alias};
       $self->throw("Unknown column $field on $class as $alias")
         unless exists $class->_columns->{$field};
-      my $ret = join('.', $alias, $field);
-      # return { '=' => \$ret }; # SQL::Abstract doesn't handle this yet :(
-      $ret = " = ${ret}";
-      return \$ret;
+      return join('.', $alias, $field);
     } else {
       $self->throw( "Unable to resolve type ${type}: only have aliases for ".
             join(', ', keys %{$attrs->{_aliases} || {}}) );
@@ -182,9 +199,25 @@ sub new_related {
   return $self->resolve_class($rel_obj->{class})->new(\%fields);
 }
 
+sub find_related {
+  my $self = shift;
+  my $rel = shift;
+  my $rel_obj = $self->_relationships->{$rel};
+  $self->throw( "No such relationship ${rel}" ) unless $rel_obj;
+  my ($cond) = $self->resolve_condition($rel_obj->{cond}, { _action => 'convert' });
+  $self->throw( "Invalid query: @_" ) if (@_ > 1 && (@_ % 2 == 1));
+  my $attrs = { };
+  if (@_ > 1 && ref $_[$#_] eq 'HASH') {
+    $attrs = { %{ pop(@_) } };
+  }
+  my $query = ((@_ > 1) ? {@_} : shift);
+  $query = ($query ? { '-and' => [ $cond, $query ] } : $cond);
+  return $self->resolve_class($rel_obj->{class})->find($query);
+}
+
 sub find_or_create_related {
   my $self = shift;
-  return ($self->search_related(@_))[0] || $self->create_related(@_);
+  return $self->find_related(@_) || $self->create_related(@_);
 }
 
 sub set_from_related {