use Try::Tiny;
use List::Util qw(first max);
-use B 'perlstring';
use DBIx::Class::ResultSource::RowParser::Util qw(
assemble_simple_parser
assemble_collapsing_parser
);
+use DBIx::Class::Carp;
+
use namespace::clean;
-# Accepts one or more relationships for the current source and returns an
-# array of column names for each of those relationships. Column names are
-# prefixed relative to the current source, in accordance with where they appear
-# in the supplied relationships.
-sub _resolve_prefetch {
- my ($self, $pre, $alias, $alias_map, $order, $pref_path) = @_;
+# Accepts a prefetch map (one or more relationships for the current source),
+# returns a set of select/as pairs for each of those relationships. Columns
+# are fully qualified inflation_slot names
+sub _resolve_selection_from_prefetch {
+ my ($self, $pre, $alias_map, $pref_path) = @_;
+
+ # internal recursion marker
$pref_path ||= [];
if (not defined $pre or not length $pre) {
return ();
}
elsif( ref $pre eq 'ARRAY' ) {
- return
- map { $self->_resolve_prefetch( $_, $alias, $alias_map, $order, [ @$pref_path ] ) }
- @$pre;
+ map { $self->_resolve_selection_from_prefetch( $_, $alias_map, [ @$pref_path ] ) }
+ @$pre;
}
elsif( ref $pre eq 'HASH' ) {
- my @ret =
map {
- $self->_resolve_prefetch($_, $alias, $alias_map, $order, [ @$pref_path ] ),
- $self->related_source($_)->_resolve_prefetch(
- $pre->{$_}, "${alias}.$_", $alias_map, $order, [ @$pref_path, $_] )
+ $self->_resolve_selection_from_prefetch($_, $alias_map, [ @$pref_path ] ),
+ $self->related_source($_)->_resolve_selection_from_prefetch(
+ $pre->{$_}, $alias_map, [ @$pref_path, $_] )
} keys %$pre;
- return @ret;
}
elsif( ref $pre ) {
$self->throw_exception(
}
else {
my $p = $alias_map;
- $p = $p->{$_} for (@$pref_path, $pre);
+ $p = $p->{$_} for @$pref_path, $pre;
$self->throw_exception (
"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 );
- $self->throw_exception( $self->source_name . " has no such relationship '$pre'" )
- unless $rel_info;
-
- my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
-
- return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
- $self->related_source($pre)->columns;
+ # this shift() is critical - it is what allows prefetch => [ (foo) x 2 ] to work
+ my $src_alias = shift @{$p->{-join_aliases}};
+
+ # ordered [select => as] pairs
+ map { [
+ "${src_alias}.$_" => join ( '.',
+ @$pref_path,
+ $pre,
+ $_,
+ )
+ ] } $self->related_source($pre)->columns;
}
}
+sub _resolve_prefetch {
+ carp_unique(
+ 'There is no good reason to call this internal deprecated method - '
+ . 'please open a ticket detailing your usage, so that a better plan can '
+ . 'be devised for your case. In either case _resolve_prefetch() is '
+ . 'deprecated in favor of _resolve_selection_from_prefetch(), which has '
+ . 'a greatly simplified arglist.'
+ );
+
+ $_[0]->_resolve_selection_from_prefetch( $_[1], $_[3] );
+}
+
+
# Takes an arrayref of {as} dbic column aliases and the collapse and select
# attributes from the same $rs (the selector requirement is a temporary
# workaround... I hope), and returns a coderef capable of:
# any sort of adjustment/rewrite should be relatively easy (fsvo relatively)
#
sub _mk_row_parser {
- my ($self, $args) = @_;
+ # $args and $attrs are separated to delineate what is core collapser stuff and
+ # what is dbic $rs specific
+ my ($self, $args, $attrs) = @_;
- my $val_index = { map
- { $args->{inflate_map}[$_] => $_ }
- ( 0 .. $#{$args->{inflate_map}} )
- };
+ die "HRI without pruning makes zero sense"
+ if ( $args->{hri_style} && ! $args->{prune_null_branches} );
- my $src;
+ my %common = (
+ hri_style => $args->{hri_style},
+ prune_null_branches => $args->{prune_null_branches},
+ val_index => { map
+ { $args->{inflate_map}[$_] => $_ }
+ ( 0 .. $#{$args->{inflate_map}} )
+ },
+ );
- if (! $args->{collapse} ) {
- $src = assemble_simple_parser({
- val_index => $val_index,
- hri_style => $args->{hri_style},
- });
- }
- else {
+ my $check_null_columns;
+
+ my $src = (! $args->{collapse} ) ? assemble_simple_parser(\%common) : do {
my $collapse_map = $self->_resolve_collapse ({
- premultiplied => $args->{premultiplied},
# FIXME
# only consider real columns (not functions) during collapse resolution
# this check shouldn't really be here, as fucktards are not supposed to
# (it is now trivial as the attrs specify where things go out of sync
# needs MOAR tests)
as => { map
- { ref $args->{selection}[$val_index->{$_}] ? () : ( $_ => $val_index->{$_} ) }
- keys %$val_index
- }
+ { ref $attrs->{select}[$common{val_index}{$_}] ? () : ( $_ => $common{val_index}{$_} ) }
+ keys %{$common{val_index}}
+ },
+ premultiplied => $args->{premultiplied},
});
- $src = assemble_collapsing_parser({
- val_index => $val_index,
+ $check_null_columns = $collapse_map->{-identifying_columns}
+ if @{$collapse_map->{-identifying_columns}};
+
+ assemble_collapsing_parser({
+ %common,
collapse_map => $collapse_map,
- hri_style => $args->{hri_style},
});
- }
+ };
+
+ utf8::upgrade($src)
+ if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
- return $args->{eval}
- ? ( eval "sub { $src }" || die $@ )
- : $src
- ;
+ return (
+ $args->{eval} ? ( eval "sub $src" || die $@ ) : $src,
+ $check_null_columns,
+ );
}
is_single => ( $inf->{attrs}{accessor} && $inf->{attrs}{accessor} ne 'multi' ),
is_inner => ( ( $inf->{attrs}{join_type} || '' ) !~ /^left/i),
rsrc => $self->related_source($rel),
+ fk_map => $self->_resolve_relationship_condition(
+ rel_name => $rel,
+ self_alias => "\xFE", # irrelevant
+ foreign_alias => "\xFF", # irrelevant
+ )->{identity_map},
};
-
- # FIME - need to use _resolve_cond here instead
- my $cond = $inf->{cond};
-
- if (
- ref $cond eq 'HASH'
- and
- keys %$cond
- and
- ! defined first { $_ !~ /^foreign\./ } (keys %$cond)
- and
- ! defined first { $_ !~ /^self\./ } (values %$cond)
- ) {
- for my $f (keys %$cond) {
- my $s = $cond->{$f};
- $_ =~ s/^ (?: foreign | self ) \.//x for ($f, $s);
- $relinfo->{$rel}{fk_map}{$s} = $f;
- }
- }
}
# inject non-left fk-bridges from *INNER-JOINED* children (if any)
if $args->{_parent_info}{collapser_reusable};
}
- # Still dont know how to collapse - try to resolve based on our columns (plus already inserted FK bridges)
+ # Still don't know how to collapse - try to resolve based on our columns (plus already inserted FK bridges)
if (
! $collapse_map->{-identifying_columns}
and
# if we got here - we are good to go, but the construction is tricky
# since our children will want to include our collapse criteria - we
# don't give them anything (safe, since they are all collapsible on their own)
- # in addition we record the individual collapse posibilities
+ # in addition we record the individual collapse possibilities
# of all left children node collapsers, and merge them in the rowparser
# coderef later
$collapse_map->{-identifying_columns} = [];