# in order to properly resolve prefetch aliases (any alias
# with a relation_chain_depth less than the depth of the
# current prefetch is not considered)
+#
+# The increments happen in 1/2s to make it easier to correlate the
+# join depth with the join path. An integer means a relationship
+# specified via a search_related, whereas a fraction means an added
+# join/prefetch via attributes
sub _chain_relationship {
my ($self, $rel) = @_;
my $source = $self->result_source;
}];
my $seen = { %{$attrs->{seen_join} || {} } };
+ my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}})
+ ? $from->[-1][0]{-join_path}
+ : [];
+
# we need to take the prefetch the attrs into account before we
# ->_resolve_join as otherwise they get lost - captainL
my $merged = $self->_merge_attr( $attrs->{join}, $attrs->{prefetch} );
- my @requested_joins = $source->_resolve_join($merged, $attrs->{alias}, $seen);
+ my @requested_joins = $source->_resolve_join(
+ $merged,
+ $attrs->{alias},
+ $seen,
+ $jpath,
+ );
push @$from, @requested_joins;
- ++$seen->{-relation_chain_depth};
+ $seen->{-relation_chain_depth} += 0.5;
# if $self already had a join/prefetch specified on it, the requested
# $rel might very well be already included. What we do in this case
# we consider the last one thus reverse
for my $j (reverse @requested_joins) {
if ($rel eq $j->[0]{-join_path}[-1]) {
- $j->[0]{-relation_chain_depth}++;
+ $j->[0]{-relation_chain_depth} += 0.5;
$already_joined++;
last;
}
# for my $j (reverse @$from) {
# next unless ref $j eq 'ARRAY';
# if ($j->[0]{-join_path} && $j->[0]{-join_path}[-1] eq $rel) {
-# $j->[0]{-relation_chain_depth}++;
+# $j->[0]{-relation_chain_depth} += 0.5;
# $already_joined++;
# last;
# }
# }
unless ($already_joined) {
- push @$from, $source->_resolve_join($rel, $attrs->{alias}, $seen);
+ push @$from, $source->_resolve_join(
+ $rel,
+ $attrs->{alias},
+ $seen,
+ $jpath,
+ );
}
- ++$seen->{-relation_chain_depth};
+ $seen->{-relation_chain_depth} += 0.5;
return ($from,$seen);
}
[
@{ $attrs->{from} },
$source->_resolve_join(
- $join, $alias, { %{ $attrs->{seen_join} || {} } }
+ $join,
+ $alias,
+ { %{ $attrs->{seen_join} || {} } },
+ ($attrs->{seen_join} && keys %{$attrs->{seen_join}})
+ ? $attrs->{from}[-1][0]{-join_path}
+ : []
+ ,
)
];
}
# even though it doesn't make much sense, this is what pre 081xx has
# been doing
if (my $page = delete $attrs->{page}) {
- $attrs->{offset} = ($attrs->{rows} * ($page - 1)) +
- ($attrs->{offset} || 0);
+ $attrs->{offset} =
+ ($attrs->{rows} * ($page - 1))
+ +
+ ($attrs->{offset} || 0)
+ ;
}
return $self->{_attrs} = $attrs;
my $paths = {};
return $paths unless ref $fromspec eq 'ARRAY';
+ my $cur_depth = $seen->{-relation_chain_depth} || 0;
+
+ if (int ($cur_depth) != $cur_depth) {
+ $self->throw_exception ("-relation_chain_depth is not an integer, something went horribly wrong ($cur_depth)");
+ }
+
for my $j (@$fromspec) {
next if ref $j ne 'ARRAY';
- next if $j->[0]{-relation_chain_depth} < ( $seen->{-relation_chain_depth} || 0);
+ next if $j->[0]{-relation_chain_depth} < $cur_depth;
+
+ my $jpath = $j->[0]{-join_path};
my $p = $paths;
- $p = $p->{$_} ||= {} for @{$j->[0]{-join_path}};
+ $p = $p->{$_} ||= {} for @{$jpath}[$cur_depth .. $#$jpath];
push @{$p->{-join_aliases} }, $j->[0]{-alias};
}
}
return unless $f_source; # Can't test rel without f_source
- eval { $self->_resolve_join($rel, 'me', {}) };
+ eval { $self->_resolve_join($rel, 'me', {}, []) };
if ($@) { # If the resolve failed, back out and re-throw the error
delete $rels{$rel}; #
# we need a supplied one, because we do in-place modifications, no returns
$self->throw_exception ('You must supply a seen hashref as the 3rd argument to _resolve_join')
- unless $seen;
+ unless ref $seen eq 'HASH';
- # This isn't quite right, we should actually dive into $seen and reconstruct
- # the entire path (the reference entry point would be the join conditional
- # with depth == current_depth - 1. At this point however nothing depends on
- # having the entire path, transcending related_resultset, so just leave it
- # as is, hairy enough already.
- $jpath ||= [];
+ $self->throw_exception ('You must supply a joinpath arrayref as the 4th argument to _resolve_join')
+ unless ref $jpath eq 'ARRAY';
+
+ $jpath = [@$jpath];
if (ref $join eq 'ARRAY') {
return
map {
- $self->_resolve_join($_, $alias, $seen, [@$jpath], $force_left);
+ $self->_resolve_join($_, $alias, $seen, $jpath, $force_left);
} @$join;
} elsif (ref $join eq 'HASH') {
return
"don't know how to resolve prefetch reftype ".ref($pre));
}
else {
-
my $p = $alias_map;
$p = $p->{$_} for (@$pref_path, $pre);
$self->throw_exception (
- "Unable to resolve prefetch $pre - join alias map does not contain an entry for path "
+ "Unable to resolve prefetch $pre - join alias map does not contain an entry for path: "
. join (' -> ', @$pref_path, $pre)
) if (ref $p->{-join_aliases} ne 'ARRAY' or not @{$p->{-join_aliases}} );
-
+
my $as = shift @{$p->{-join_aliases}};
my $rel_info = $self->relationship_info( $pre );