my ($source, $attrs) = @_;
#weaken $source;
+ $attrs = { %{$attrs||{}} };
if ($attrs->{page}) {
$attrs->{rows} ||= 10;
my $cond = (@_
? (
(@_ == 1 || ref $_[0] eq "HASH")
- ? shift
+ ? (
+ (ref $_[0] eq 'HASH')
+ ? (
+ (keys %{ $_[0] } > 0)
+ ? shift
+ : undef
+ )
+ : shift
+ )
: (
(@_ % 2)
? $self->throw_exception("Odd number of arguments to search")
}
: $where);
}
+
if (defined $cond) {
$new_attrs->{where} = (
defined $new_attrs->{where}
$input_query = {@_};
}
+ my (%related, $info);
+
+ foreach my $key (keys %$input_query) {
+ if (ref($input_query->{$key})
+ && ($info = $self->result_source->relationship_info($key))) {
+ my $rel_q = $self->result_source->resolve_condition(
+ $info->{cond}, delete $input_query->{$key}, $key
+ );
+ die "Can't handle OR join condition in find" if ref($rel_q) eq 'ARRAY';
+ @related{keys %$rel_q} = values %$rel_q;
+ }
+ }
+ if (my @keys = keys %related) {
+ @{$input_query}{@keys} = values %related;
+ }
+
my @unique_queries = $self->_unique_queries($input_query, $attrs);
# Build the final query: Default to the disjunction of the unique queries,
? ($attrs->{key})
: $self->result_source->unique_constraint_names;
+ my $where = $self->_collapse_cond($self->{attrs}{where} || {});
+ my $num_where = scalar keys %$where;
+
my @unique_queries;
foreach my $name (@constraint_names) {
my @unique_cols = $self->result_source->unique_constraint_columns($name);
my $unique_query = $self->_build_unique_query($query, \@unique_cols);
+ my $num_cols = scalar @unique_cols;
my $num_query = scalar keys %$unique_query;
- next unless $num_query;
- # XXX: Assuming quite a bit about $self->{attrs}{where}
- my $num_cols = scalar @unique_cols;
- my $num_where = exists $self->{attrs}{where}
- ? scalar keys %{ $self->{attrs}{where} }
- : 0;
- push @unique_queries, $unique_query
- if $num_query + $num_where == $num_cols;
+ my $total = $num_query + $num_where;
+ if ($num_query && ($num_query == $num_cols || $total == $num_cols)) {
+ # The query is either unique on its own or is unique in combination with
+ # the existing where clause
+ push @unique_queries, $unique_query;
+ }
}
return @unique_queries;
$attrs->{where}, $attrs
);
- return (@data ? $self->_construct_object(@data) : ());
+ return (@data ? ($self->_construct_object(@data))[0] : ());
}
# _is_unique_query
$self->{all_cache_position} = 1;
return ($self->all)[0];
}
+ if ($self->{stashed_objects}) {
+ my $obj = shift(@{$self->{stashed_objects}});
+ delete $self->{stashed_objects} unless @{$self->{stashed_objects}};
+ return $obj;
+ }
my @row = (
exists $self->{stashed_row}
? @{delete $self->{stashed_row}}
: $self->cursor->next
);
return unless (@row);
- return $self->_construct_object(@row);
+ my ($row, @more) = $self->_construct_object(@row);
+ $self->{stashed_objects} = \@more if @more;
+ return $row;
}
sub _construct_object {
my ($self, @row) = @_;
my $info = $self->_collapse_result($self->{_attrs}{as}, \@row);
- my $new = $self->result_class->inflate_result($self->result_source, @$info);
- $new = $self->{_attrs}{record_filter}->($new)
+ my @new = $self->result_class->inflate_result($self->result_source, @$info);
+ @new = $self->{_attrs}{record_filter}->(@new)
if exists $self->{_attrs}{record_filter};
- return $new;
+ return @new;
}
sub _collapse_result {
my %new = (
%{ $self->_remove_alias($values, $alias) },
%{ $self->_remove_alias($collapsed_cond, $alias) },
+ -result_source => $self->result_source,
);
my $obj = $self->result_class->new(\%new);
- $obj->result_source($self->result_source) if $obj->can('result_source');
return $obj;
}
sub _remove_alias {
my ($self, $query, $alias) = @_;
- my %unaliased = %{ $query || {} };
- foreach my $key (keys %unaliased) {
- $unaliased{$1} = delete $unaliased{$key}
+ my %orig = %{ $query || {} };
+ my %unaliased;
+
+ foreach my $key (keys %orig) {
+ if ($key !~ /\./) {
+ $unaliased{$key} = $orig{$key};
+ next;
+ }
+ $unaliased{$1} = $orig{$key}
if $key =~ m/^(?:\Q$alias\E\.)?([^.]+)$/;
}