X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSource.pm;h=aa636a7c90de0afb31f9e7d2a25750a7b8f93bb0;hb=c7d3a087b07143d0612bd44fa35b1fb085041aac;hp=1ef8dce20fc93c4ee399bc0a70bd1423ad6f7fc2;hpb=6d0ee587eb31c41e28a432de3caf261a66b4c2ca;p=dbsrgits%2FDBIx-Class-Historic.git diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index 1ef8dce..aa636a7 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -113,9 +113,21 @@ NULL values. This is currently only used by L. Set this to a true value for a column whose value is somehow automatically set. This is used to determine which columns to empty -when cloning objects using C. It is also used by +when cloning objects using L. It is also used by L. +=item is_numeric + +Set this to a true or false value (not C) to explicitly specify +if this column contains numeric data. This controls how set_column +decides whether to consider a column dirty after an update: if +C is true a numeric comparison C<< != >> will take place +instead of the usual C + +If not specified the storage class will attempt to figure this out on +first access to the column, based on the column C. The +result will be cached in this attribute. + =item is_foreign_key Set this to a true value for a column that contains a key from a @@ -1120,10 +1132,13 @@ sub _resolve_join { $type = $rel_info->{attrs}{join_type} || ''; $force_left->{force} = 1 if lc($type) eq 'left'; } - return [ { $as => $self->related_source($join)->from, + + my $rel_src = $self->related_source($join); + return [ { $as => $rel_src->from, + -result_source => $rel_src, -join_type => $type, -join_path => [@$jpath, $join], - -join_alias => $as, + -alias => $as, -relation_chain_depth => $seen->{-relation_chain_depth} || 0, }, $self->_resolve_condition($rel_info->{cond}, $as, $alias) ]; @@ -1198,7 +1213,7 @@ sub _resolve_condition { $self->throw_exception( "Column ${v} not loaded or not passed to new() prior to insert()" ." on ${for} trying to resolve relationship (maybe you forgot " - ."to call ->reload_from_storage to get defaults from the db)" + ."to call ->discard_changes to get defaults from the db)" ); } return $UNRESOLVABLE_CONDITION; @@ -1226,10 +1241,76 @@ sub _resolve_condition { } } +# Legacy code, needs to go entirely away (fully replaced by _resolve_prefetch) sub resolve_prefetch { carp 'resolve_prefetch is a private method, stop calling it'; - my $self = shift; - $self->_resolve_prefetch (@_); + + my ($self, $pre, $alias, $seen, $order, $collapse) = @_; + $seen ||= {}; + if( ref $pre eq 'ARRAY' ) { + return + map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) } + @$pre; + } + elsif( ref $pre eq 'HASH' ) { + my @ret = + map { + $self->resolve_prefetch($_, $alias, $seen, $order, $collapse), + $self->related_source($_)->resolve_prefetch( + $pre->{$_}, "${alias}.$_", $seen, $order, $collapse) + } keys %$pre; + return @ret; + } + elsif( ref $pre ) { + $self->throw_exception( + "don't know how to resolve prefetch reftype ".ref($pre)); + } + else { + my $count = ++$seen->{$pre}; + my $as = ($count > 1 ? "${pre}_${count}" : $pre); + my $rel_info = $self->relationship_info( $pre ); + $self->throw_exception( $self->name . " has no such relationship '$pre'" ) + unless $rel_info; + my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : ''); + my $rel_source = $self->related_source($pre); + + if (exists $rel_info->{attrs}{accessor} + && $rel_info->{attrs}{accessor} eq 'multi') { + $self->throw_exception( + "Can't prefetch has_many ${pre} (join cond too complex)") + unless ref($rel_info->{cond}) eq 'HASH'; + my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}" + if (my ($fail) = grep { @{[$_ =~ m/\./g]} == $dots } + keys %{$collapse}) { + my ($last) = ($fail =~ /([^\.]+)$/); + carp ( + "Prefetching multiple has_many rels ${last} and ${pre} " + .(length($as_prefix) + ? "at the same level (${as_prefix}) " + : "at top level " + ) + . 'will explode the number of row objects retrievable via ->next or ->all. ' + . 'Use at your own risk.' + ); + } + #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); } + # values %{$rel_info->{cond}}; + $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ]; + # action at a distance. prepending the '.' allows simpler code + # in ResultSet->_collapse_result + my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); } + keys %{$rel_info->{cond}}; + my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY' + ? @{$rel_info->{attrs}{order_by}} + : (defined $rel_info->{attrs}{order_by} + ? ($rel_info->{attrs}{order_by}) + : ())); + push(@$order, map { "${as}.$_" } (@key, @ord)); + } + + return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] } + $rel_source->columns; + } } # Accepts one or more relationships for the current source and returns an @@ -1293,8 +1374,7 @@ sub _resolve_prefetch { ? "at the same level (${as_prefix}) " : "at top level " ) - . 'will currently disrupt both the functionality of $rs->count(), ' - . 'and the amount of objects retrievable via $rs->next(). ' + . 'will explode the number of row objects retrievable via ->next or ->all. ' . 'Use at your own risk.' ); }