use DBIx::Class::Carp;
use DBIx::Class::ResultSetColumn;
use DBIx::Class::ResultClass::HashRefInflator;
-use Scalar::Util qw/blessed weaken reftype/;
+use Scalar::Util qw( blessed reftype );
use DBIx::Class::_Util qw(
dbic_internal_try dump_value
fail_on_internal_wantarray fail_on_internal_call UNRESOLVABLE_CONDITION
);
use Try::Tiny;
-# not importing first() as it will clash with our own method
-use List::Util ();
-
BEGIN {
# De-duplication in _merge_attr() is disabled, but left in for reference
# (the merger is used for other things that ought not to be de-duped)
# see if we can keep the cache (no $rs changes)
my $cache;
my %safe = (alias => 1, cache => 1);
- if ( ! List::Util::first { !$safe{$_} } keys %$call_attrs and (
+ if ( ! grep { !$safe{$_} } keys %$call_attrs and (
! defined $call_cond
or
ref $call_cond eq 'HASH' && ! keys %$call_cond
my @selector_attrs = qw/select as columns cols +select +as +columns include_columns/;
# reset the current selector list if new selectors are supplied
- if (List::Util::first { exists $call_attrs->{$_} } qw/columns cols select as/) {
- delete @{$old_attrs}{(@selector_attrs, '_dark_selector')};
- }
+ delete @{$old_attrs}{(@selector_attrs, '_dark_selector')}
+ if grep { exists $call_attrs->{$_} } qw(columns cols select as);
# Normalize the new selector list (operates on the passed-in attr structure)
# Need to do it on every chain instead of only once on _resolved_attrs, in
: '@$rows = map { $inflator_cref->($res_class, $rsrc, { %s } ) } @$rows'
),
( join (', ', map { "\$infmap->[$_] => \$_->[$_]" } 0..$#$infmap ) )
- );
+ ) . '; 1' or die;
}
}
else {
: 'classic_nonpruning'
;
- # $args and $attrs to _mk_row_parser are separated to delineate what is
- # core collapser stuff and what is dbic $rs specific
- @{$self->{_row_parser}{$parser_type}}{qw(cref nullcheck)} = $rsrc->_mk_row_parser({
- eval => 1,
- inflate_map => $infmap,
- collapse => $attrs->{collapse},
- premultiplied => $attrs->{_main_source_premultiplied},
- hri_style => $self->{_result_inflator}{is_hri},
- prune_null_branches => $self->{_result_inflator}{is_hri} || $self->{_result_inflator}{is_core_row},
- }, $attrs) unless $self->{_row_parser}{$parser_type}{cref};
-
- # column_info metadata historically hasn't been too reliable.
- # We need to start fixing this somehow (the collapse resolver
- # can't work without it). Add an explicit check for the *main*
- # result, hopefully this will gradually weed out such errors
- #
- # FIXME - this is a temporary kludge that reduces performance
- # It is however necessary for the time being
- my ($unrolled_non_null_cols_to_check, $err);
+ unless( $self->{_row_parser}{$parser_type}{cref} ) {
- if (my $check_non_null_cols = $self->{_row_parser}{$parser_type}{nullcheck} ) {
+ # $args and $attrs to _mk_row_parser are separated to delineate what is
+ # core collapser stuff and what is dbic $rs specific
+ $self->{_row_parser}{$parser_type}{src} = $rsrc->_mk_row_parser({
+ inflate_map => $infmap,
+ collapse => $attrs->{collapse},
+ premultiplied => $attrs->{_main_source_premultiplied},
+ hri_style => $self->{_result_inflator}{is_hri},
+ prune_null_branches => $self->{_result_inflator}{is_hri} || $self->{_result_inflator}{is_core_row},
+ }, $attrs);
- $err =
- 'Collapse aborted due to invalid ResultSource metadata - the following '
- . 'selections are declared non-nullable but NULLs were retrieved: '
- ;
-
- my @violating_idx;
- COL: for my $i (@$check_non_null_cols) {
- ! defined $_->[$i] and push @violating_idx, $i and next COL for @$rows;
- }
+ $self->{_row_parser}{$parser_type}{cref} = do {
+ package # hide form PAUSE
+ DBIx::Class::__GENERATED_ROW_PARSER__;
- $self->throw_exception( $err . join (', ', map { "'$infmap->[$_]'" } @violating_idx ) )
- if @violating_idx;
-
- $unrolled_non_null_cols_to_check = join (',', @$check_non_null_cols);
-
- utf8::upgrade($unrolled_non_null_cols_to_check)
- if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
+ eval $self->{_row_parser}{$parser_type}{src};
+ } || die $@;
}
- my $next_cref =
- ($did_fetch_all or ! $attrs->{collapse}) ? undef
- : defined $unrolled_non_null_cols_to_check ? eval sprintf <<'EOS', $unrolled_non_null_cols_to_check
-sub {
- # FIXME SUBOPTIMAL - we can do better, cursor->next/all (well diff. methods) should return a ref
- my @r = $cursor->next or return;
- if (my @violating_idx = grep { ! defined $r[$_] } (%s) ) {
- $self->throw_exception( $err . join (', ', map { "'$infmap->[$_]'" } @violating_idx ) )
- }
- \@r
-}
-EOS
- : sub {
+ # this needs to close over the *current* cursor, hence why it is not cached above
+ my $next_cref = ($did_fetch_all or ! $attrs->{collapse})
+ ? undef
+ : sub {
# FIXME SUBOPTIMAL - we can do better, cursor->next/all (well diff. methods) should return a ref
my @r = $cursor->next or return;
\@r
$self->{_row_parser}{$parser_type}{cref}->(
$rows,
- $next_cref ? ( $next_cref, $self->{_stashed_rows} = [] ) : (),
+ $next_cref,
+ ( $self->{_stashed_rows} = [] ),
+ ( my $null_violations = {} ),
);
+ $self->throw_exception(
+ 'Collapse aborted - the following columns are declared (or defaulted to) '
+ . 'non-nullable within DBIC but NULLs were retrieved from storage: '
+ . join( ', ', map { "'$infmap->[$_]'" } sort { $a <=> $b } keys %$null_violations )
+ . ' within data row ' . dump_value({
+ map {
+ $infmap->[$_] =>
+ ( ! defined $self->{_stashed_rows}[0][$_] or length $self->{_stashed_rows}[0][$_] < 50 )
+ ? $self->{_stashed_rows}[0][$_]
+ : substr( $self->{_stashed_rows}[0][$_], 0, 50 ) . '...'
+ } 0 .. $#{$self->{_stashed_rows}[0]}
+ })
+ ) if keys %$null_violations;
+
# simple in-place substitution, does not regrow $rows
if ($self->{_result_inflator}{is_core_row}) {
$_ = $inflator_cref->($res_class, $rsrc, @$_) for @$rows
$storage->_prune_unused_joins ($attrs);
# any non-pruneable non-local restricting joins imply subq
- $needs_subq = defined List::Util::first { $_ ne $attrs->{alias} } keys %{ $join_classifications->{restricting} || {} };
+ $needs_subq = grep { $_ ne $attrs->{alias} } keys %{ $join_classifications->{restricting} || {} };
}
# check if the head is composite (by now all joins are thrown out unless $needs_subq)
# default selection list
$attrs->{columns} = [ $source->columns ]
- unless List::Util::first { exists $attrs->{$_} } qw/columns cols select as/;
+ unless grep { exists $attrs->{$_} } qw/columns cols select as/;
# merge selectors together
for (qw/columns select as/) {
if (
! $attrs->{_main_source_premultiplied}
and
- ! List::Util::first { ! $_->[0]{-is_single} } @fromlist
+ ! grep { ! $_->[0]{-is_single} } @fromlist
) {
$attrs->{collapse} = 0;
}
},
ARRAY => sub {
return $_[1] if !defined $_[0];
- return $_[1] if __HM_DEDUP and List::Util::first { $_ eq $_[0] } @{$_[1]};
+ return $_[1] if __HM_DEDUP and grep { $_ eq $_[0] } @{$_[1]};
return [$_[0], @{$_[1]}]
},
HASH => sub {
ARRAY => {
SCALAR => sub {
return $_[0] if !defined $_[1];
- return $_[0] if __HM_DEDUP and List::Util::first { $_ eq $_[1] } @{$_[0]};
+ return $_[0] if __HM_DEDUP and grep { $_ eq $_[1] } @{$_[0]};
return [@{$_[0]}, $_[1]]
},
ARRAY => sub {
HASH => sub {
return [ $_[1] ] if ! @{$_[0]};
return $_[0] if !keys %{$_[1]};
- return $_[0] if __HM_DEDUP and List::Util::first { $_ eq $_[1] } @{$_[0]};
+ return $_[0] if __HM_DEDUP and grep { $_ eq $_[1] } @{$_[0]};
return [ @{$_[0]}, $_[1] ];
},
},
return [] if !keys %{$_[0]} and !@{$_[1]};
return [ $_[0] ] if !@{$_[1]};
return $_[1] if !keys %{$_[0]};
- return $_[1] if __HM_DEDUP and List::Util::first { $_ eq $_[0] } @{$_[1]};
+ return $_[1] if __HM_DEDUP and grep { $_ eq $_[0] } @{$_[1]};
return [ $_[0], @{$_[1]} ];
},
HASH => sub {