Merge 'DBIx-Class-current' into 'collapse_result_rewrite'
Jess Robinson [Fri, 11 May 2007 02:52:45 +0000 (02:52 +0000)]
1  2 
lib/DBIx/Class/ResultSet.pm

@@@ -98,8 -98,8 +98,8 @@@ sub new 
    $attrs->{alias} ||= 'me';
  
    my $self = {
 -    _source_handle => $source,
 -    result_class => $attrs->{result_class} || $source->resolve->result_class,
 +    result_source => $source,
 +    result_class => $attrs->{result_class} || $source->result_class,
      cond => $attrs->{where},
      count => undef,
      pager => undef,
@@@ -135,7 -135,10 +135,10 @@@ call it as C<search(undef, \%attrs)>
      columns => [qw/name artistid/],
    });
  
- For a list of attributes that can be passed to C<search>, see L</ATTRIBUTES>. For more examples of using this function, see L<Searching|DBIx::Class::Manual::Cookbook/Searching>.
+ For a list of attributes that can be passed to C<search>, see
+ L</ATTRIBUTES>. For more examples of using this function, see
+ L<Searching|DBIx::Class::Manual::Cookbook/Searching>. For a complete
+ documentation for the first argument, see L<SQL::Abstract>.
  
  =cut
  
@@@ -240,7 -243,7 +243,7 @@@ sub search_rs 
          : $having);
    }
  
 -  my $rs = (ref $self)->new($self->_source_handle, $new_attrs);
 +  my $rs = (ref $self)->new($self->result_source, $new_attrs);
    if ($rows) {
      $rs->set_cache($rows);
    }
@@@ -744,82 -747,32 +747,82 @@@ sub next 
  sub _construct_object {
    my ($self, @row) = @_;
    my $info = $self->_collapse_result($self->{_attrs}{as}, \@row);
 -  my @new = $self->result_class->inflate_result($self->_source_handle, @$info);
 +  my @new = $self->result_class->inflate_result($self->result_source, @$info);
    @new = $self->{_attrs}{record_filter}->(@new)
      if exists $self->{_attrs}{record_filter};
    return @new;
  }
  
  sub _collapse_result {
 -  my ($self, $as, $row, $prefix) = @_;
 +  my ($self, $as_proto, $row) = @_;
  
 -  my %const;
    my @copy = @$row;
 -  
 -  foreach my $this_as (@$as) {
 -    my $val = shift @copy;
 -    if (defined $prefix) {
 -      if ($this_as =~ m/^\Q${prefix}.\E(.+)$/) {
 -        my $remain = $1;
 -        $remain =~ /^(?:(.*)\.)?([^.]+)$/;
 -        $const{$1||''}{$2} = $val;
 +
 +  # 'foo'         => [ undef, 'foo' ]
 +  # 'foo.bar'     => [ 'foo', 'bar' ]
 +  # 'foo.bar.baz' => [ 'foo.bar', 'baz' ]
 +
 +  my @construct_as = map { [ (/^(?:(.*)\.)?([^.]+)$/) ] } @$as_proto;
 +
 +  my %collapse = %{$self->{_attrs}{collapse}||{}};
 +
 +  my @pri_index;
 +
 +  # if we're doing collapsing (has_many prefetch) we need to grab records
 +  # until the PK changes, so fill @pri_index. if not, we leave it empty so
 +  # we know we don't have to bother.
 +
 +  # the reason for not using the collapse stuff directly is because if you
 +  # had for e.g. two artists in a row with no cds, the collapse info for
 +  # both would be NULL (undef) so you'd lose the second artist
 +
 +  # store just the index so we can check the array positions from the row
 +  # without having to contruct the full hash
 +
 +  if (keys %collapse) {
 +    my %pri = map { ($_ => 1) } $self->result_source->primary_columns;
 +    foreach my $i (0 .. $#construct_as) {
 +      if (delete $pri{$construct_as[$i]}) {
 +        push(@pri_index, $i);
        }
 -    } else {
 -      $this_as =~ /^(?:(.*)\.)?([^.]+)$/;
 -      $const{$1||''}{$2} = $val;
 +      last unless keys %pri; # short circuit (Johnny Five Is Alive!)
      }
    }
  
 +  # no need to do an if, it'll be empty if @pri_index is empty anyway
 +
 +  my %pri_vals = map { ($_ => $copy[$_]) } @pri_index;
 +
 +  my %const;
 +
 +  do { # no need to check anything at the front, we always want the first row
 +  
 +    foreach my $this_as (@construct_as) {
 +      $const{$this_as->[0]||''}{$this_as->[1]} = shift(@copy);
 +    }
 +
 +  } until ( # no pri_index => no collapse => drop straight out
 +      !@pri_index
 +    or
 +      do { # get another row, stash it, drop out if different PK
 +
 +        @copy = $self->cursor->next;
 +        $self->{stashed_row} = \@copy;
 +
 +        # last thing in do block, counts as true if anything doesn't match
 +
 +        # check xor defined first for NULL vs. NOT NULL then if one is
 +        # defined the other must be so check string equality
 +
 +        grep {
 +          (defined $pri_vals{$_} ^ defined $copy[$_])
 +          || (defined $pri_vals{$_} && ($pri_vals{$_} ne $copy[$_]))
 +        } @pri_index;
 +      }
 +  );
 +
 +  # THIS BIT STILL NEEDS TO DO THE COLLAPSE
 +
    my $alias = $self->{attrs}{alias};
    my $info = [ {}, {} ];
    foreach my $key (keys %const) {
        $info->[0] = $const{$key};
      }
    }
 -  
 -  my @collapse;
 -  if (defined $prefix) {
 -    @collapse = map {
 -        m/^\Q${prefix}.\E(.+)$/ ? ($1) : ()
 -    } keys %{$self->{_attrs}{collapse}}
 -  } else {
 -    @collapse = keys %{$self->{_attrs}{collapse}};
 -  };
 -
 -  if (@collapse) {
 -    my ($c) = sort { length $a <=> length $b } @collapse;
 -    my $target = $info;
 -    foreach my $p (split(/\./, $c)) {
 -      $target = $target->[1]->{$p} ||= [];
 -    }
 -    my $c_prefix = (defined($prefix) ? "${prefix}.${c}" : $c);
 -    my @co_key = @{$self->{_attrs}{collapse}{$c_prefix}};
 -    my $tree = $self->_collapse_result($as, $row, $c_prefix);
 -    my %co_check = map { ($_, $tree->[0]->{$_}); } @co_key;
 -    my (@final, @raw);
 -
 -    while (
 -      !(
 -        grep {
 -          !defined($tree->[0]->{$_}) || $co_check{$_} ne $tree->[0]->{$_}
 -        } @co_key
 -        )
 -    ) {
 -      push(@final, $tree);
 -      last unless (@raw = $self->cursor->next);
 -      $row = $self->{stashed_row} = \@raw;
 -      $tree = $self->_collapse_result($as, $row, $c_prefix);
 -    }
 -    @$target = (@final ? @final : [ {}, {} ]);
 -      # single empty result to indicate an empty prefetched has_many
 -  }
  
 -  #print "final info: " . Dumper($info);
    return $info;
  }
  
@@@ -1273,9 -1264,10 +1276,10 @@@ sub new_result 
    my %new = (
      %{ $self->_remove_alias($values, $alias) },
      %{ $self->_remove_alias($collapsed_cond, $alias) },
+     -source_handle => $self->_source_handle
    );
  
-   return $self->result_class->new(\%new,$self->_source_handle);
+   return $self->result_class->new(\%new);
  }
  
  # _collapse_cond
@@@ -1825,7 -1817,9 +1829,9 @@@ Shortcut to include additional columns 
    });
  
  would return all CDs and include a 'name' column to the information
- passed to object inflation
+ passed to object inflation. Note that the 'artist' is the name of the
+ column (or relationship) accessor, and 'name' is the name of the column
+ accessor in the related table.
  
  =head2 select
  
@@@ -1876,8 -1870,14 +1882,14 @@@ Indicates additional column names for t
  
  =back
  
- Indicates column names for object inflation. This is used in conjunction with
- C<select>, usually when C<select> contains one or more function or stored
+ Indicates column names for object inflation. That is, c< as >
+ indicates the name that the column can be accessed as via the
+ C<get_column> method (or via the object accessor, B<if one already
+ exists>).  It has nothing to do with the SQL code C< SELECT foo AS bar
+ >.
+ The C< as > attribute is used in conjunction with C<select>,
+ usually when C<select> contains one or more function or stored
  procedure names:
  
    $rs = $schema->resultset('Employee')->search(undef, {