X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSource.pm;h=63a8ddf4ef15db39193ec6e8a068ea50424c7f30;hb=aa56106b252283cef5338312d66fdf62cc92df20;hp=834555aa24fd6716e9568c71172acc2e3bc9fee3;hpb=eb3bb737db34965596d2875f9b21bb4912a35160;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index 834555a..63a8ddf 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -10,7 +10,7 @@ use DBIx::Class::Exception; use Carp::Clan qw/^DBIx::Class/; use Try::Tiny; use List::Util 'first'; -use Scalar::Util qw/weaken isweak/; +use Scalar::Util qw/blessed weaken isweak/; use Storable qw/nfreeze thaw/; use namespace::clean; @@ -1493,7 +1493,8 @@ sub _resolve_join { -alias => $as, -relation_chain_depth => $seen->{-relation_chain_depth} || 0, }, - $self->_resolve_condition($rel_info->{cond}, $as, $alias, $join) ]; + $self->_resolve_condition($rel_info->{cond}, $as, $alias, $join) + ]; } } @@ -1545,26 +1546,63 @@ sub resolve_condition { $self->_resolve_condition (@_); } -# Resolves the passed condition to a concrete query fragment. If given an alias, -# returns a join condition; if given an object, inverts that object to produce -# a related conditional from that object. our $UNRESOLVABLE_CONDITION = \ '1 = 0'; +# Resolves the passed condition to a concrete query fragment and a flag +# indicating whether this is a cross-table condition. sub _resolve_condition { - my ($self, $cond, $as, $for, $rel) = @_; - if (ref $cond eq 'CODE') { + my ($self, $cond, $as, $for, $relname) = @_; + + my $obj_rel = !!blessed $for; - my $obj_rel = !!ref $for; + if (ref $cond eq 'CODE') { + my $relalias = $obj_rel ? 'me' : $as; - return $cond->({ + my ($crosstable_cond, $joinfree_cond) = $cond->({ self_alias => $obj_rel ? $as : $for, - foreign_alias => $obj_rel ? 'me' : $as, + foreign_alias => $relalias, self_resultsource => $self, - foreign_relname => $rel || ($obj_rel ? $as : $for), + foreign_relname => $relname || ($obj_rel ? $as : $for), self_rowobj => $obj_rel ? $for : undef }); - } elsif (ref $cond eq 'HASH') { + if ($joinfree_cond) { + + # FIXME sanity check until things stabilize, remove at some point + $self->throw_exception ( + "A join-free condition returned for relationship '$relname' whithout a row-object to chain from" + ) unless $obj_rel; + + # FIXME another sanity check + if ( + ref $joinfree_cond ne 'HASH' + or + first { $_ !~ /^\Q$relalias.\E.+/ } keys %$joinfree_cond + ) { + $self->throw_exception ( + "The join-free condition returned for relationship '$relname' must be a hash " + .'reference with all keys being valid columns on the related result source' + ); + } + + # normalize + for (values %$joinfree_cond) { + $_ = $_->{'='} if ( + ref $_ eq 'HASH' + and + keys %$_ == 1 + and + exists $_->{'='} + ); + } + + return wantarray ? ($joinfree_cond, 0) : $joinfree_cond; + } + else { + return wantarray ? ($crosstable_cond, 1) : $crosstable_cond; + } + } + elsif (ref $cond eq 'HASH') { my %ret; foreach my $k (keys %{$cond}) { my $v = $cond->{$k}; @@ -1601,14 +1639,26 @@ sub _resolve_condition { } elsif (!defined $as) { # undef, i.e. "no reverse object" $ret{$v} = undef; } else { - $ret{"${as}.${k}"} = "${for}.${v}"; + $ret{"${as}.${k}"} = { -ident => "${for}.${v}" }; } } - return \%ret; - } elsif (ref $cond eq 'ARRAY') { - return [ map { $self->_resolve_condition($_, $as, $for) } @$cond ]; - } else { - $self->throw_exception ("Can't handle condition $cond yet :("); + + return wantarray + ? ( \%ret, ($obj_rel || !defined $as || ref $as) ? 0 : 1 ) + : \%ret + ; + } + elsif (ref $cond eq 'ARRAY') { + my (@ret, $crosstable); + for (@$cond) { + my ($cond, $crosstab) = $self->_resolve_condition($_, $as, $for, $relname); + push @ret, $cond; + $crosstable ||= $crosstab; + } + return wantarray ? (\@ret, $crosstable) : \@ret; + } + else { + $self->throw_exception ("Can't handle condition $cond for relationship '$relname' yet :("); } }