added paragraph to update_or_create and find_or_create docs how to know if a row...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
index c8c89c5..3b68af1 100644 (file)
@@ -927,7 +927,7 @@ sub _build_unique_cond {
 
 =over 4
 
-=item Arguments: $rel, $cond, \%attrs?
+=item Arguments: $rel, $cond?, \%attrs?
 
 =item Return Value: $new_resultset (scalar context) || @row_objs (list context)
 
@@ -1541,10 +1541,15 @@ sub _count_subq_rs {
   # extra selectors do not go in the subquery and there is no point of ordering it, nor locking it
   delete @{$sub_attrs}{qw/collapse columns as select _prefetch_selector_range order_by for/};
 
-  # if we multi-prefetch we group_by primary keys only as this is what we would
+  # if we multi-prefetch we group_by something unique, as this is what we would
   # get out of the rs via ->next/->all. We *DO WANT* to clobber old group_by regardless
   if ( keys %{$attrs->{collapse}}  ) {
-    $sub_attrs->{group_by} = [ map { "$attrs->{alias}.$_" } ($rsrc->_pri_cols) ]
+    $sub_attrs->{group_by} = [ map { "$attrs->{alias}.$_" } @{
+      $rsrc->_identifying_column_set || $self->throw_exception(
+        'Unable to construct a unique group_by criteria properly collapsing the '
+      . 'has_many prefetch before count()'
+      );
+    } ]
   }
 
   # Calculate subquery selector
@@ -1795,20 +1800,26 @@ sub _rs_update_delete {
   }
 
   # we got this far - means it is time to wrap a subquery
-  my $pcols = [ $rsrc->_pri_cols ];
+  my $idcols = $rsrc->_identifying_column_set || $self->throw_exception(
+    sprintf(
+      "Unable to perform complex resultset %s() without an identifying set of columns on source '%s'",
+      $op,
+      $rsrc->source_name,
+    )
+  );
   my $existing_group_by = delete $attrs->{group_by};
 
   # make a new $rs selecting only the PKs (that's all we really need for the subq)
   delete $attrs->{$_} for qw/collapse _collapse_order_by select _prefetch_selector_range as/;
-  $attrs->{columns} = [ map { "$attrs->{alias}.$_" } @$pcols ];
+  $attrs->{columns} = [ map { "$attrs->{alias}.$_" } @$idcols ];
   $attrs->{group_by} = \ '';  # FIXME - this is an evil hack, it causes the optimiser to kick in and throw away the LEFT joins
   my $subrs = (ref $self)->new($rsrc, $attrs);
 
-  if (@$pcols == 1) {
+  if (@$idcols == 1) {
     return $storage->$op (
       $rsrc,
       $op eq 'update' ? $values : (),
-      { $pcols->[0] => { -in => $subrs->as_query } },
+      { $idcols->[0] => { -in => $subrs->as_query } },
     );
   }
   elsif ($storage->_use_multicolumn_in) {
@@ -1816,7 +1827,7 @@ sub _rs_update_delete {
     my $sql_maker = $storage->sql_maker;
     my ($sql, @bind) = @${$subrs->as_query};
     $sql = sprintf ('(%s) IN %s', # the as_query already comes with a set of parenthesis
-      join (', ', map { $sql_maker->_quote ($_) } @$pcols),
+      join (', ', map { $sql_maker->_quote ($_) } @$idcols),
       $sql,
     );
 
@@ -1864,8 +1875,8 @@ sub _rs_update_delete {
     my @op_condition;
     for my $row ($subrs->search({}, { group_by => $subq_group_by })->cursor->all) {
       push @op_condition, { map
-        { $pcols->[$_] => $row->[$_] }
-        (0 .. $#$pcols)
+        { $idcols->[$_] => $row->[$_] }
+        (0 .. $#$idcols)
       };
     }
 
@@ -2701,6 +2712,23 @@ all in the call to C<find_or_create>, even when set to C<undef>.
 See also L</find> and L</update_or_create>. For information on how to declare
 unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
 
+If you need to know if an existing row was found or a new one created use
+L</find_or_new> and L<DBIx::Class::Row/in_storage> instead. Don't forget
+to call L<DBIx::Class::Row/insert> to save the newly created row to the
+database!
+
+  my $cd = $schema->resultset('CD')->find_or_new({
+    cdid   => 5,
+    artist => 'Massive Attack',
+    title  => 'Mezzanine',
+    year   => 2005,
+  });
+
+  if( $cd->in_storage ) {
+      # do some stuff
+      $cd->insert;
+  }
+
 =cut
 
 sub find_or_create {
@@ -2762,6 +2790,25 @@ all in the call to C<update_or_create>, even when set to C<undef>.
 See also L</find> and L</find_or_create>. For information on how to declare
 unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
 
+If you need to know if an existing row was updated or a new one created use
+L</update_or_new> and L<DBIx::Class::Row/in_storage> instead. Don't forget
+to call L<DBIx::Class::Row/insert> to save the newly created row to the
+database!
+
+  my $cd = $schema->resultset('CD')->update_or_new(
+    {
+      artist => 'Massive Attack',
+      title  => 'Mezzanine',
+      year   => 1998,
+    },
+    { key => 'cd_artist_title' }
+  );
+
+  if( $cd->in_storage ) {
+      # do some stuff
+      $cd->insert;
+  }
+
 =cut
 
 sub update_or_create {