-- added support for belongs_to type relationships and better support for when the...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
index eda5e42..31358a9 100644 (file)
@@ -34,7 +34,7 @@ In the examples below, the following table classes are used:
 
   package MyApp::Schema::Artist;
   use base qw/DBIx::Class/;
-  __PACKAGE__->load_components(qw/Core/);
+  __PACKAGE__->load_components(qw/Core/)
   __PACKAGE__->table('artist');
   __PACKAGE__->add_columns(qw/artistid name/);
   __PACKAGE__->set_primary_key('artistid');
@@ -1252,35 +1252,48 @@ Pass an arrayref of hashrefs. Each hashref should be a structure suitable for
 submitting to a $resultset->create(...) method.
 
 In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
-to insert the data, as this is a fast method.
+to insert the data, as this is a faster method.
 
 Otherwise, each set of data is inserted into the database using
 L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
 objects is returned.
 
-i.e.,
-
-  $rs->populate( [
-         { artistid => 4, name => 'Manufactured Crap', cds => [ 
-                 { title => 'My First CD', year => 2006 },
-                 { title => 'Yet More Tweeny-Pop crap', year => 2007 },
-               ] 
-         },
-         { artistid => 5, name => 'Angsty-Whiny Girl', cds => [
-                 { title => 'My parents sold me to a record company' ,year => 2005 },
-                 { title => 'Why Am I So Ugly?', year => 2006 },
-                 { title => 'I Got Surgery and am now Popular', year => 2007 }
-               ]
-         },
-         { name => 'Like I Give a Damn' }
+Example:  Assuming an Artist Class that has many CDs Classes relating:
 
-       ] );
+  my $Artist_rs = $schema->resultset("Artist");
+  
+  ## Void Context Example 
+  $Artist_rs->populate([
+     { artistid => 4, name => 'Manufactured Crap', cds => [ 
+        { title => 'My First CD', year => 2006 },
+        { title => 'Yet More Tweeny-Pop crap', year => 2007 },
+      ],
+     },
+     { artistid => 5, name => 'Angsty-Whiny Girl', cds => [
+        { title => 'My parents sold me to a record company' ,year => 2005 },
+        { title => 'Why Am I So Ugly?', year => 2006 },
+        { title => 'I Got Surgery and am now Popular', year => 2007 }
+      ],
+     },
+  ]);
+  
+  ## Array Context Example
+  my ($ArtistOne, $ArtistTwo, $ArtistThree) = $Artist_rs->populate([
+    { name => "Artist One"},
+       { name => "Artist Two"},
+       { name => "Artist Three", cds=> [
+         { title => "First CD", year => 2007},
+         { title => "Second CD", year => 2008},
+       ]}
+  ]);
+  
+  print $ArtistOne->name; ## response is 'Artist One'
+  print $ArtistThree->cds->count ## reponse is '2'
 
 =cut
 use Data::Dump qw/dump/;
-
 sub populate {
-  my ($self, $data) = @_;  #warn dump $self->result_source->primary_columns;
+  my ($self, $data) = @_;
   
   if(defined wantarray) {
     my @created;
@@ -1288,43 +1301,71 @@ sub populate {
       push(@created, $self->create($item));
     }
     return @created;
-  } 
-  else
-  {
+  } else {
     my ($first, @rest) = @$data;
-       
-       ## We assume for now that the first item is required to name all the columns
-       ## and relationships similarly to how schema->populate requires a first item
-       ## of all the column names.
-       
-    my @names = grep { !$self->result_source->has_relationship($_) } keys %$first;
-       
-    $self->result_source->storage->insert_bulk(
-               $self->result_source, 
-               \@names, 
-               [map { [ map {defined $_ ? $_ : $self->throw_exception("Undefined value for column!")} @$_{@names} ] } @$data]
-       );
-       
-       ## Again we assume the first row has to define all the related resultsets
-       my @rels = grep { $self->result_source->has_relationship($_) } keys %$first;
-       my @pks = $self->result_source->primary_columns;
-       
-       ## Must have PKs to use this!!!
-       
-       foreach my $item (@$data)
+
+       my @names = grep {!ref $first->{$_}} keys %$first;
+    my @rels = grep { $self->result_source->has_relationship($_) } keys %$first;
+    my @pks = $self->result_source->primary_columns;   
+
+       ## do the belongs_to relationships      
+    foreach my $index (0..$#{@$data})
        {
-               ## First we need to get a result for each
-               ## We need to call populate for each relationship.
-               
                foreach my $rel (@rels)
                {
-                       my $result = $self->find(map {{$_=>$item->{$_}} } @pks);
+                       next unless $data->[$index]->{$rel} && ref $data->[$index]->{$rel} eq "HASH";
                        
-                       my @discard = $result->$rel->populate($item->{$rel});
-                       #$result->$rel->populate($item->{$rel});
+                       my $result = $self->related_resultset($rel)->create($data->[$index]->{$rel});
+                       
+                       my ($reverse) = keys %{$self->result_source->reverse_relationship_info($rel)};
+                       
+                       my $related = $result->result_source->resolve_condition(
+
+                               $result->result_source->relationship_info($reverse)->{cond},
+                               $self,                          
+                               $result,                                
+                       );
+
+                       delete $data->[$index]->{$rel};
+                       $data->[$index] = {%{$data->[$index]}, %$related};
+                       
+                       push @names, keys %$related if $index == 0;
                }
        }
        
+    my @values = map {
+      [ map {
+         defined $_ ? $_ : $self->throw_exception("Undefined value for column!")
+      } @$_{@names} ]
+    } @$data;
+
+    $self->result_source->storage->insert_bulk(
+      $self->result_source, 
+      \@names, 
+      \@values,
+    );
+
+       ## do the has_many relationships
+    foreach my $item (@$data) {
+
+      foreach my $rel (@rels) {
+        next unless $item->{$rel} && ref $item->{$rel} eq "ARRAY";
+
+        my $parent = $self->find(map {{$_=>$item->{$_}} } @pks) || next;
+        my $child = $parent->$rel;
+               
+        my $related = $child->result_source->resolve_condition(
+          $parent->result_source->relationship_info($rel)->{cond},
+          $child,
+          $parent,
+        );
+
+        my @rows_to_add = ref $item->{$rel} eq 'ARRAY' ? @{$item->{$rel}} : ($item->{$rel});
+        my @populate = map { {%$_, %$related} } @rows_to_add;
+
+        $child->populate( \@populate );
+      }
+    }
   }
 }
 
@@ -1401,7 +1442,8 @@ sub new_result {
   my %new = (
     %{ $self->_remove_alias($values, $alias) },
     %{ $self->_remove_alias($collapsed_cond, $alias) },
-    -source_handle => $self->_source_handle
+    -source_handle => $self->_source_handle,
+    -result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED
   );
 
   return $self->result_class->new(\%new);