sub search {
my $self = shift;
+ my $rs = $self->search_rs( @_ );
+ return (wantarray ? $rs->all : $rs);
+}
- my $rs;
- if( @_ ) {
-
- my $attrs = { %{$self->{attrs}} };
- my $having = delete $attrs->{having};
- $attrs = { %$attrs, %{ pop(@_) } } if @_ > 1 and ref $_[$#_] eq 'HASH';
-
- my $where = (@_
- ? ((@_ == 1 || ref $_[0] eq "HASH")
- ? shift
- : ((@_ % 2)
- ? $self->throw_exception(
- "Odd number of arguments to search")
- : {@_}))
- : undef());
- if (defined $where) {
- $attrs->{where} = (defined $attrs->{where}
- ? { '-and' =>
- [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
- $where, $attrs->{where} ] }
- : $where);
- }
+=head2 search_rs
- if (defined $having) {
- $attrs->{having} = (defined $attrs->{having}
- ? { '-and' =>
- [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
- $having, $attrs->{having} ] }
- : $having);
- }
+=over 4
- $rs = (ref $self)->new($self->result_source, $attrs);
+=item Arguments: $cond, \%attrs?
+
+=item Return Value: $resultset
+
+=back
+
+This method does the same exact thing as search() except it will
+always return a resultset, even in list context.
+
+=cut
+
+sub search_rs {
+ my $self = shift;
+
+ my $attrs = { %{$self->{attrs}} };
+ my $having = delete $attrs->{having};
+ $attrs = { %$attrs, %{ pop(@_) } } if @_ > 1 and ref $_[$#_] eq 'HASH';
+
+ my $where = (@_
+ ? ((@_ == 1 || ref $_[0] eq "HASH")
+ ? shift
+ : ((@_ % 2)
+ ? $self->throw_exception(
+ "Odd number of arguments to search")
+ : {@_}))
+ : undef());
+ if (defined $where) {
+ $attrs->{where} = (defined $attrs->{where}
+ ? { '-and' =>
+ [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
+ $where, $attrs->{where} ] }
+ : $where);
}
- else {
- $rs = $self;
- $rs->reset;
+
+ if (defined $having) {
+ $attrs->{having} = (defined $attrs->{having}
+ ? { '-and' =>
+ [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
+ $having, $attrs->{having} ] }
+ : $having);
}
- return (wantarray ? $rs->all : $rs);
+
+ my $rs = (ref $self)->new($self->result_source, $attrs);
+
+ unless (@_) { # no search, effectively just a clone
+ my $rows = $self->get_cache;
+ if ($rows) {
+ $rs->set_cache($rows);
+ }
+ }
+
+ return $rs;
}
=head2 search_literal
my $cd = $schema->resultset('CD')->find(5);
-You can also find a row by a specific key or unique constraint by specifying
-the C<key> attribute. For example:
+You can also find a row by a specific unique constraint using the C<key>
+attribute. For example:
my $cd = $schema->resultset('CD')->find('Massive Attack', 'Mezzanine', { key => 'artist_title' });
=cut
sub find {
- my ($self, @vals) = @_;
- my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
+ my $self = shift;
+ my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
# Parse out a hash from input
- my @unique_cols = exists $attrs->{key}
+ my @cols = exists $attrs->{key}
? $self->result_source->unique_constraint_columns($attrs->{key})
: $self->result_source->primary_columns;
- my %hash;
- if (ref $vals[0] eq 'HASH') {
- %hash = %{ $vals[0] };
+ my $hash;
+ if (ref $_[0] eq 'HASH') {
+ $hash = { %{$_[0]} };
}
- elsif (@vals == @unique_cols) {
- @hash{@unique_cols} = @vals;
+ elsif (@_ == @cols) {
+ $hash = {};
+ @{$hash}{@cols} = @_;
}
else {
- # Hack for CDBI queries
- %hash = @vals;
+ $self->throw_exception(
+ "Arguments to find must be a hashref or match the number of columns in the "
+ . exists $attrs->{key} ? "$attrs->{key} unique constraint" : "primary key"
+ );
}
# Check the hash we just parsed against our source's unique constraints
"Can't find unless a primary key or unique constraint is defined"
) unless @constraint_names;
- my @unique_hashes;
+ my @unique_queries;
foreach my $name (@constraint_names) {
my @unique_cols = $self->result_source->unique_constraint_columns($name);
- my %unique_hash = $self->_unique_hash(\%hash, \@unique_cols);
-
- # TODO: Check that the ResultSet defines the rest of the query
- push @unique_hashes, \%unique_hash
- if scalar keys %unique_hash;# == scalar @unique_cols;
- }
+ my $unique_query = $self->_build_unique_query($hash, \@unique_cols);
- # Add the ResultSet's alias
- foreach my $unique_hash (@unique_hashes) {
- foreach my $key (grep { ! m/\./ } keys %$unique_hash) {
- $unique_hash->{"$self->{attrs}{alias}.$key"} = delete $unique_hash->{$key};
+ # Add the ResultSet's alias
+ foreach my $key (grep { ! m/\./ } keys %$unique_query) {
+ $unique_query->{"$self->{attrs}{alias}.$key"} = delete $unique_query->{$key};
}
+
+ push @unique_queries, $unique_query if %$unique_query;
}
# Handle cases where the ResultSet already defines the query
- my $query = @unique_hashes ? \@unique_hashes : undef;
+ my $query = @unique_queries ? \@unique_queries : undef;
# Run the query
if (keys %$attrs) {
}
}
-# _unique_hash
+# _build_unique_query
#
-# Constrain the specified hash based on the specific column names.
+# Constrain the specified query hash based on the specified column names.
-sub _unique_hash {
- my ($self, $hash, $unique_cols) = @_;
+sub _build_unique_query {
+ my ($self, $query, $unique_cols) = @_;
- # Ugh, CDBI lowercases column names
- if (exists $INC{'DBIx/Class/CDBICompat/ColumnCase.pm'}) {
- foreach my $key (keys %$hash) {
- $hash->{lc $key} = delete $hash->{$key};
- }
- }
-
- my %unique_hash =
- map { $_ => $hash->{$_} }
- grep { exists $hash->{$_} }
+ my %unique_query =
+ map { $_ => $query->{$_} }
+ grep { exists $query->{$_} }
@$unique_cols;
- return %unique_hash;
+ return \%unique_query;
}
=head2 search_related
sub next {
my ($self) = @_;
- if (@{$self->{all_cache} || []}) {
+ if (my $cache = $self->get_cache) {
$self->{all_cache_position} ||= 0;
- return $self->{all_cache}->[$self->{all_cache_position}++];
+ return $cache->[$self->{all_cache_position}++];
}
if ($self->{attrs}{cache}) {
$self->{all_cache_position} = 1;
last unless (@raw = $self->cursor->next);
$row = $self->{stashed_row} = \@raw;
$tree = $self->_collapse_result($as, $row, $c_prefix);
- #warn Data::Dumper::Dumper($tree, $row);
}
- @$target = @final;
+ @$target = (@final ? @final : [ {}, {} ]);
+ # single empty result to indicate an empty prefetched has_many
}
return $info;
sub count {
my $self = shift;
return $self->search(@_)->count if @_ and defined $_[0];
- return scalar @{ $self->get_cache } if @{ $self->get_cache };
+ return scalar @{ $self->get_cache } if $self->get_cache;
my $count = $self->_count;
return 0 unless $count;
sub all {
my ($self) = @_;
- return @{ $self->get_cache } if @{ $self->get_cache };
+ return @{ $self->get_cache } if $self->get_cache;
my @obj;
my $row = $self->find($hash, $attrs);
if (defined $row) {
- $row->set_columns($hash);
- $row->update;
+ $row->update($hash);
return $row;
}
=cut
sub get_cache {
- shift->{all_cache} || [];
+ shift->{all_cache};
}
=head2 set_cache
sub set_cache {
my ( $self, $data ) = @_;
$self->throw_exception("set_cache requires an arrayref")
- if ref $data ne 'ARRAY';
- my $result_class = $self->result_class;
- foreach( @$data ) {
- $self->throw_exception(
- "cannot cache object of type '$_', expected '$result_class'"
- ) if ref $_ ne $result_class;
- }
+ if defined($data) && (ref $data ne 'ARRAY');
$self->{all_cache} = $data;
}
=cut
sub clear_cache {
- shift->set_cache([]);
+ shift->set_cache(undef);
}
=head2 related_resultset