Crazy ass multi create fixes..
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Row.pm
index 7a6f68e..d35d299 100644 (file)
@@ -22,8 +22,13 @@ This class is responsible for defining and doing basic operations on rows
 derived from L<DBIx::Class::ResultSource> objects.
 
 Row objects are returned from L<DBIx::Class::ResultSet>s using the
-L<DBIx::Class::ResultSet/create>, L<DBIx::Class::ResultSet/find>,
-L<DBIx::Class::ResultSet/next> and L<DBIx::Class::ResultSet/all> methods.
+L<create|DBIx::Class::ResultSet/create>, L<find|DBIx::Class::ResultSet/find>,
+L<next|DBIx::Class::ResultSet/next> and L<all|DBIx::Class::ResultSet/all> methods,
+as well as invocations of 'single' (
+L<belongs_to|DBIx::Class::Relationship/belongs_to>,
+L<has_one|DBIx::Class::Relationship/has_one> or
+L<might_have|DBIx::Class::Relationship/might_have>)
+relationship accessors of L<DBIx::Class::Row> objects.
 
 =head1 METHODS
 
@@ -73,17 +78,21 @@ For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
 sub __new_related_find_or_new_helper {
   my ($self, $relname, $data) = @_;
   if ($self->__their_pk_needs_us($relname, $data)) {
+#    print STDERR "PK needs us\n";
+#    print STDERR "Data: ", Data::Dumper::Dumper($data);
     return $self->result_source
                 ->related_source($relname)
                 ->resultset
                 ->new_result($data);
   }
   if ($self->result_source->pk_depends_on($relname, $data)) {
+#      print STDERR "PK depends on\n";
     return $self->result_source
                 ->related_source($relname)
                 ->resultset
                 ->find_or_create($data);
   }
+#  print STDERR "Neither, find_or_new\n";
   return $self->find_or_new_related($relname, $data);
 }
 
@@ -91,12 +100,20 @@ sub __their_pk_needs_us { # this should maybe be in resultsource.
   my ($self, $relname, $data) = @_;
   my $source = $self->result_source;
   my $reverse = $source->reverse_relationship_info($relname);
+#  print STDERR "Found reverse rel info: ", Data::Dumper::Dumper($reverse);
   my $rel_source = $source->related_source($relname);
   my $us = { $self->get_columns };
+#  print STDERR "Test on self cols: ", Data::Dumper::Dumper($us);
   foreach my $key (keys %$reverse) {
     # if their primary key depends on us, then we have to
     # just create a result and we'll fill it out afterwards
-    return 1 if $rel_source->pk_depends_on($key, $us);
+    my $dep = $rel_source->pk_depends_on($key, $us);
+    if($dep) {
+#        print STDERR "Assigning $self to $key\n";
+        $data->{$key} = $self;
+        return 1;
+    }
+#    return 1 if $rel_source->pk_depends_on($key, $us);
   }
   return 0;
 }
@@ -119,6 +136,7 @@ sub new {
     $new->result_source($source);
   }
 
+#  print "Source ", $source->source_name, " is $new\n";
   if ($attrs) {
     $new->throw_exception("attrs must be a hashref")
       unless ref($attrs) eq 'HASH';
@@ -135,6 +153,8 @@ sub new {
         if ($info && $info->{attrs}{accessor}
           && $info->{attrs}{accessor} eq 'single')
         {
+#          print STDERR "Single $key ", Data::Dumper::Dumper($attrs);
+#          print STDERR "from $class to: $info->{class}\n";
           my $rel_obj = delete $attrs->{$key};
           if(!Scalar::Util::blessed($rel_obj)) {
             $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
@@ -144,10 +164,13 @@ sub new {
 
           $new->set_from_related($key, $rel_obj) if $rel_obj->in_storage;
           $related->{$key} = $rel_obj;
+#          print STDERR "Related :", join(", ", keys %$related), "\n";
           next;
         } elsif ($info && $info->{attrs}{accessor}
             && $info->{attrs}{accessor} eq 'multi'
             && ref $attrs->{$key} eq 'ARRAY') {
+#          print STDERR "Multi $key ", Data::Dumper::Dumper($attrs);
+#          print STDERR "from $class to: $info->{class}\n";
           my $others = delete $attrs->{$key};
           foreach my $rel_obj (@$others) {
             if(!Scalar::Util::blessed($rel_obj)) {
@@ -158,6 +181,7 @@ sub new {
             $new->set_from_related($key, $rel_obj) if $rel_obj->in_storage;
           }
           $related->{$key} = $others;
+#          print STDERR "Related :", join(", ", keys %$related), "\n";
           next;
         } elsif ($info && $info->{attrs}{accessor}
           && $info->{attrs}{accessor} eq 'filter')
@@ -175,6 +199,7 @@ sub new {
           $inflated->{$key} = $attrs->{$key};
           next;
         }
+#          print STDERR "Done :", join(", ", keys %$related), "\n";
       }
       $new->throw_exception("No such column $key on $class")
         unless $class->has_column($key);
@@ -241,24 +266,33 @@ sub insert {
     my @pri = $self->primary_columns;
 
     REL: foreach my $relname (keys %related_stuff) {
-
+#        print STDERR "Looking at: $relname\n";
       my $rel_obj = $related_stuff{$relname};
 
       next REL unless (Scalar::Util::blessed($rel_obj)
                        && $rel_obj->isa('DBIx::Class::Row'));
 
+#        print STDERR "Check pk: from ", $source->source_name, " to $relname\n";
+#        print STDERR "With ", Data::Dumper::Dumper({ $rel_obj->get_columns });
       next REL unless $source->pk_depends_on(
                         $relname, { $rel_obj->get_columns }
                       );
-
+#        print STDERR "$rel_obj\n";
+#        print STDERR "in_storage: ", $rel_obj->in_storage, "\n";
+#        print STDERR "Inserting $relname\n";
       $rel_obj->insert();
       $self->set_from_related($relname, $rel_obj);
       delete $related_stuff{$relname};
     }
   }
 
+#  print STDERR "self $self\n";
+#  print STDERR "self in_storage ", $self->in_storage, "\n";
+#  print STDERR "Ran out of rels, insert ", $source->source_name, "\n";
   my $updated_cols = $source->storage->insert($source, { $self->get_columns });
   $self->set_columns($updated_cols);
+  $self->in_storage(1);
+#  print STDERR "$self\n";
 
   ## PK::Auto
   my @auto_pri = grep {
@@ -297,10 +331,15 @@ sub insert {
         my $reverse = $source->reverse_relationship_info($relname);
         foreach my $obj (@cands) {
           $obj->set_from_related($_, $self) for keys %$reverse;
+#          my $them = { %{$obj->{_relationship_data} || {} }, $obj->get_inflated_columns };
           my $them = { $obj->get_inflated_columns };
+#          print STDERR "Does $relname need our PK?\n";
           if ($self->__their_pk_needs_us($relname, $them)) {
-            $obj = $self->find_or_create_related($relname, $them);
+#              print STDERR "Yes\n";
+            # $obj = $self->find_or_create_related($relname, $them);
+            $obj->insert();
           } else {
+#              print STDERR "No\n";
             $obj->insert();
           }
         }
@@ -309,7 +348,7 @@ sub insert {
     $rollback_guard->commit;
   }
 
-  $self->in_storage(1);
+#  $self->in_storage(1);
   undef $self->{_orig_ident};
   return $self;
 }
@@ -435,7 +474,7 @@ L</in_storage>. Runs an SQL DELETE statement using the primary key
 values to locate the row.
 
 The object is still perfectly usable, but L</in_storage> will
-now return 0 and the object must reinserted using L</insert>
+now return 0 and the object must be reinserted using L</insert>
 before it can be used to L</update> the row again. 
 
 If you delete an object in a class with a C<has_many> relationship, an
@@ -494,6 +533,11 @@ been fetched from the database or set by an accessor.
 If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
 will be deflated and returned.
 
+Note that if you used the C<columns> or the C<select/as>
+L<search attributes|DBIx::Class::ResultSet/ATTRIBUTES> on the resultset from
+which C<$row> was derived, and B<did not include> C<$columnname> in the list,
+this method will return C<undef> even if the database contains some value.
+
 To retrieve all loaded column values as a hash, use L</get_columns>.
 
 =cut
@@ -659,8 +703,8 @@ sub get_inflated_columns {
 Sets a raw column value. If the new value is different from the old one,
 the column is marked as dirty for when you next call L</update>.
 
-If passed an object or reference as a value, this will happily attempt
-store it, and a later L</insert> or L</update> will try and
+If passed an object or reference as a value, this method will happily
+attempt to store it, and a later L</insert> or L</update> will try and
 stringify/numify as appropriate. To set an object to be deflated
 instead, see L</set_inflated_columns>.
 
@@ -751,24 +795,17 @@ sub set_inflated_columns {
       {
         my $rel = delete $upd->{$key};
         $self->set_from_related($key => $rel);
-        $self->{_relationship_data}{$key} = $rel;          
+        $self->{_relationship_data}{$key} = $rel;
       } elsif ($info && $info->{attrs}{accessor}
-        && $info->{attrs}{accessor} eq 'multi'
-        && ref $upd->{$key} eq 'ARRAY') {
-        my $others = delete $upd->{$key};
-        foreach my $rel_obj (@$others) {
-          if(!Scalar::Util::blessed($rel_obj)) {
-            $rel_obj = $self->create_related($key, $rel_obj);
-          }
-        }
-        $self->{_relationship_data}{$key} = $others; 
-#            $related->{$key} = $others;
-        next;
+        && $info->{attrs}{accessor} eq 'multi') {
+          $self->throw_exception(
+            "Recursive update is not supported over relationships of type multi ($key)"
+          );
       }
       elsif ($self->has_column($key)
         && exists $self->column_info($key)->{_inflate_info})
       {
-        $self->set_inflated_column($key, delete $upd->{$key});          
+        $self->set_inflated_column($key, delete $upd->{$key});
       }
     }
   }
@@ -848,7 +885,7 @@ sub copy {
 
 =item Arguments: $columnname, $value
 
-=item Returns: The value set
+=item Returns: The value sent to storage
 
 =back