duh
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
index c8a2d77..f6cc3ba 100644 (file)
@@ -46,27 +46,13 @@ A new ResultSet is returned from calling L</search> on an existing
 ResultSet. The new one will contain all the conditions of the
 original, plus any new conditions added in the C<search> call.
 
-A ResultSet is also an iterator. L</next> is used to return all the
-L<DBIx::Class::Row>s the ResultSet represents.
+A ResultSet also incorporates an implicit iterator. L</next> and L</reset>
+can be used to walk through all the L<DBIx::Class::Row>s the ResultSet
+represents.
 
 The query that the ResultSet represents is B<only> executed against
 the database when these methods are called:
-
-=over
-
-=item L</find>
-
-=item L</next>
-
-=item L</all>
-
-=item L</count>
-
-=item L</single>
-
-=item L</first>
-
-=back
+L</find> L</next> L</all> L</first> L</single> L</count>
 
 =head1 EXAMPLES
 
@@ -674,7 +660,7 @@ L<DBIx::Class::Cursor> for more information.
 sub cursor {
   my ($self) = @_;
 
-  my $attrs = { %{$self->_resolved_attrs} };
+  my $attrs = $self->_resolved_attrs_copy;
   return $self->{cursor}
     ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
           $attrs->{where},$attrs);
@@ -725,7 +711,7 @@ sub single {
       $self->throw_exception('single() only takes search conditions, no attributes. You want ->search( $cond, $attrs )->single()');
   }
 
-  my $attrs = { %{$self->_resolved_attrs} };
+  my $attrs = $self->_resolved_attrs_copy;
   if ($where) {
     if (defined $attrs->{where}) {
       $attrs->{where} = {
@@ -1145,8 +1131,8 @@ sub result_class {
 =back
 
 Performs an SQL C<COUNT> with the same query as the resultset was built
-with to find the number of elements. If passed arguments, does a search
-on the resultset and counts the results of that.
+with to find the number of elements. Passing arguments is equivalent to
+C<< $rs->search ($cond, \%attrs)->count >>
 
 =cut
 
@@ -1155,32 +1141,38 @@ sub count {
   return $self->search(@_)->count if @_ and defined $_[0];
   return scalar @{ $self->get_cache } if $self->get_cache;
 
-  my @subq_attrs = qw/prefetch collapse distinct group_by having/;
+  my @grouped_subq_attrs = qw/prefetch collapse distinct group_by having/;
+  my @subq_attrs = ();
+  
   my $attrs = $self->_resolved_attrs;
-
   # if we are not paged - we are simply asking for a limit
   if (not $attrs->{page} and not $attrs->{software_limit}) {
     push @subq_attrs, qw/rows offset/;
   }
 
-  return $self->_has_attr (@subq_attrs)
-    ? $self->_count_subq
+  my $need_subq = $self->_has_attr (@subq_attrs);
+  my $need_group_subq = $self->_has_attr (@grouped_subq_attrs);
+
+  return ($need_subq || $need_group_subq)
+    ? $self->_count_subq ($need_group_subq)
     : $self->_count_simple
 }
 
 sub _count_subq {
-  my $self = shift;
+  my ($self, $add_group_by) = @_;
 
-  my $attrs = { %{$self->_resolved_attrs} };
+  my $attrs = $self->_resolved_attrs_copy;
 
   # copy for the subquery, we need to do some adjustments to it too
   my $sub_attrs = { %$attrs };
 
-  # these can not go in the subquery either
-  delete $sub_attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns/;
+  # these can not go in the subquery, and there is no point of ordering it
+  delete $sub_attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns order_by/;
 
-  # force a group_by and the same set of columns (most databases require this)
-  $sub_attrs->{columns} = $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ];
+  # if needed force a group_by and the same set of columns (most databases require this)
+  if ($add_group_by) {
+    $sub_attrs->{columns} = $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ];
+  }
 
   $attrs->{from} = [{
     count_subq => (ref $self)->new ($self->result_source, $sub_attrs )->as_query
@@ -1211,7 +1203,7 @@ sub _count_simple {
 sub __count {
   my ($self, $attrs) = @_;
 
-  $attrs ||= { %{$self->_resolved_attrs} };
+  $attrs ||= $self->_resolved_attrs_copy;
 
   # take off any column specs, any pagers, record_filter is cdbi, and no point of ordering a count
   delete $attrs->{$_} for (qw/columns +columns select +select as +as rows offset page pager order_by record_filter/); 
@@ -1352,7 +1344,7 @@ sub _rs_update_delete {
   if ($needs_group_by_subq or $needs_subq) {
 
     # make a new $rs selecting only the PKs (that's all we really need)
-    my $attrs = $self->_resolved_attrs;
+    my $attrs = $self->_resolved_attrs_copy;
 
     delete $attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns/;
     $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ];
@@ -2510,6 +2502,12 @@ sub _resolve_from {
   return ($from,$seen);
 }
 
+# too many times we have to do $attrs = { %{$self->_resolved_attrs} }
+sub _resolved_attrs_copy {
+  my $self = shift;
+  return { %{$self->_resolved_attrs (@_)} };
+}
+
 sub _resolved_attrs {
   my $self = shift;
   return $self->{_attrs} if $self->{_attrs};
@@ -2610,7 +2608,7 @@ sub _resolved_attrs {
 
   }
 
-  $attrs->{group_by} ||= $attrs->{select}
+  $attrs->{group_by} ||= [ grep { !ref($_) || (ref($_) ne 'HASH') } @{$attrs->{select}} ]
     if delete $attrs->{distinct};
   if ( $attrs->{order_by} ) {
     $attrs->{order_by} = (