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
sub cursor {
my ($self) = @_;
- my $attrs = { %{$self->_resolved_attrs} };
+ my $attrs = $self->_resolved_attrs_copy;
+ $attrs->{_virtual_order_by} = $self->_gen_virtual_order;
+
return $self->{cursor}
||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
$attrs->{where},$attrs);
$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;
+ $attrs->{_virtual_order_by} = $self->_gen_virtual_order;
+
if ($where) {
if (defined $attrs->{where}) {
$attrs->{where} = {
return (@data ? ($self->_construct_object(@data))[0] : undef);
}
+# _gen_virtual_order
+#
+# This is a horrble hack, but seems like the best we can do at this point
+# Some limit emulations (Top) require an ordered resultset in order to
+# function at all. So supply a PK order to be used if necessary
+
+sub _gen_virtual_order {
+ return [ shift->result_source->primary_columns ];
+}
+
# _is_unique_query
#
# Try to determine if the specified query is guaranteed to be unique, based on
sub search_like {
my $class = shift;
- carp join ("\n",
- 'search_like() is deprecated and will be removed in 0.09.',
- 'Instead use ->search({ x => { -like => "y%" } })',
- '(note the outer pair of {}s - they are important!)'
+ carp (
+ 'search_like() is deprecated and will be removed in DBIC version 0.09.'
+ .' Instead use ->search({ x => { -like => "y%" } })'
+ .' (note the outer pair of {}s - they are important!)'
);
my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
my $query = ref $_[0] eq 'HASH' ? { %{shift()} }: {@_};
=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
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 having_bind/;
-
- # if we are not paged - we are simply asking for a limit
- if (not $self->{attrs}{page} and not $self->{attrs}{software_limit}) {
- push @subq_attrs, qw/rows offset/;
- }
-
- return $self->_has_attr (@subq_attrs)
- ? $self->_count_subq
- : $self->_count_simple
-}
-
-sub _count_subq {
- my $self = shift;
-
- my $attrs = { %{$self->_resolved_attrs} };
-
- # 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 select +select as +as columns +columns/;
-
- # 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) ];
-
- $attrs->{from} = [{
- count_subq => (ref $self)->new ($self->result_source, $sub_attrs )->as_query
- }];
+ my $meth = $self->_has_attr (qw/prefetch collapse distinct group_by/)
+ ? 'count_grouped'
+ : 'count'
+ ;
- # the subquery replaces this
- delete $attrs->{$_} for qw/where bind prefetch collapse group_by having/;
-
- return $self->__count ($attrs);
-}
-
-sub _count_simple {
- my $self = shift;
-
- my $count = $self->__count;
- return 0 unless $count;
-
- # need to take offset from resolved attrs
-
- $count -= $self->{_attrs}{offset} if $self->{_attrs}{offset};
- $count = $self->{attrs}{rows} if
- $self->{attrs}{rows} and $self->{attrs}{rows} < $count;
- $count = 0 if ($count < 0);
- return $count;
-}
-
-sub __count {
- my ($self, $attrs) = @_;
-
- $attrs ||= { %{$self->{attrs}} };
-
- # 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/);
-
- $attrs->{select} = { count => '*' };
- $attrs->{as} = [qw/count/];
-
- my $tmp_rs = (ref $self)->new($self->result_source, $attrs);
- my ($count) = $tmp_rs->cursor->next;
+ my $attrs = $self->_resolved_attrs_copy;
+ my $rsrc = $self->result_source;
- return $count;
+ return $rsrc->storage->$meth ($rsrc, $attrs);
}
sub _bool {
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 select +select as +as columns +columns/;
+ delete $attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns/;
$attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ];
if ($needs_group_by_subq) {
=item Arguments: none
-=item Return Value: 1
+=item Return Value: $storage_rv
=back
will not run DBIC cascade triggers. See L</delete_all> if you need triggers
to run. See also L<DBIx::Class::Row/delete>.
-delete may not generate correct SQL for a query with joins or a resultset
-chained from a related resultset. In this case it will generate a warning:-
-
-In these cases you may find that delete_all is more appropriate, or you
-need to respecify your query in a way that can be expressed without a join.
+Return value will be the amount of rows deleted; exact type of return value
+is storage-dependent.
=cut
## do the belongs_to relationships
foreach my $index (0..$#$data) {
- if( grep { !defined $data->[$index]->{$_} } @pks ) {
- my @ret = $self->populate($data);
- return;
+
+ # delegate to create() for any dataset without primary keys with specified relationships
+ if (grep { !defined $data->[$index]->{$_} } @pks ) {
+ for my $r (@rels) {
+ if (grep { ref $data->[$index]{$r} eq $_ } qw/HASH ARRAY/) { # a related set must be a HASH or AoH
+ my @ret = $self->populate($data);
+ return;
+ }
+ }
}
foreach my $rel (@rels) {
- next unless $data->[$index]->{$rel} && ref $data->[$index]->{$rel} eq "HASH";
+ next unless ref $data->[$index]->{$rel} eq "HASH";
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(
my $attrs = $self->{attrs};
my $from = $attrs->{from}
- || [ { $attrs->{alias} => $source->from } ];
+ || [ {
+ -result_source => $source,
+ -alias => $attrs->{alias},
+ $attrs->{alias} => $source->from,
+ } ];
my $seen = { %{$attrs->{seen_join}||{}} };
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};
push( @{ $attrs->{as} }, @$adds );
}
- $attrs->{from} ||= [ { $self->{attrs}{alias} => $source->from } ];
+ $attrs->{from} ||= [ {
+ -result_source => $source,
+ -alias => $self->{attrs}{alias},
+ $self->{attrs}{alias} => $source->from,
+ } ];
if ( exists $attrs->{join} || exists $attrs->{prefetch} ) {
my $join = delete $attrs->{join} || {};
}
- $attrs->{group_by} ||= $attrs->{select}
- if delete $attrs->{distinct};
if ( $attrs->{order_by} ) {
$attrs->{order_by} = (
ref( $attrs->{order_by} ) eq 'ARRAY'
}
push( @{ $attrs->{order_by} }, @pre_order );
}
+
+ if (delete $attrs->{distinct}) {
+ $attrs->{group_by} ||= [ grep { !ref($_) || (ref($_) ne 'HASH') } @{$attrs->{select}} ];
+ }
+
$attrs->{collapse} = $collapse;
if ( $attrs->{page} and not defined $attrs->{offset} ) {
my $p = $paths;
$p = $p->{$_} ||= {} for @{$j->[0]{-join_path}};
- push @{$p->{-join_aliases} }, $j->[0]{-join_alias};
+ push @{$p->{-join_aliases} }, $j->[0]{-alias};
}
return $paths;