X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=9c278fee6fb7eb0883267bcf9054869eff0b5b3a;hb=0fcfe456c1255339f94fa1c218451760e65d24bc;hp=6b856855a6d5e11e13accffc44253e78cdde4e1f;hpb=1a58752c42ba9acf33e2943b678de4948cf3ee3f;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 6b85685..9c278fe 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -357,9 +357,9 @@ sub search_rs { } my $rs = (ref $self)->new($self->result_source, $new_attrs); - if ($rows) { - $rs->set_cache($rows); - } + + $rs->set_cache($rows) if ($rows); + return $rs; } @@ -519,7 +519,7 @@ sub find { # in ::Relationship::Base::search_related (the row method), and furthermore # the relationship is of the 'single' type. This means that the condition # provided by the relationship (already attached to $self) is sufficient, - # as there can be only one row in the databse that would satisfy the + # as there can be only one row in the databse that would satisfy the # relationship } else { @@ -530,7 +530,7 @@ sub find { } # Run the query - my $rs = $self->search ($query, $attrs); + my $rs = $self->search ($query, {result_class => $self->result_class, %$attrs}); if (keys %{$rs->_resolved_attrs->{collapse}}) { my $row = $rs->next; carp "Query returned more than one row" if $rs->next; @@ -1240,7 +1240,7 @@ sub _count_rs { my $tmp_attrs = { %$attrs }; - # take off any limits, record_filter is cdbi, and no point of ordering a count + # take off any limits, record_filter is cdbi, and no point of ordering a count delete $tmp_attrs->{$_} for (qw/select as rows offset order_by record_filter/); # overwrite the selector (supplied by the storage) @@ -1794,10 +1794,19 @@ sub populate { } return wantarray ? @created : \@created; } else { - my ($first, @rest) = @$data; + my $first = $data->[0]; + + # if a column is a registered relationship, and is a non-blessed hash/array, consider + # it relationship data + my (@rels, @columns); + for (keys %$first) { + my $ref = ref $first->{$_}; + $self->result_source->has_relationship($_) && ($ref eq 'ARRAY' or $ref eq 'HASH') + ? push @rels, $_ + : push @columns, $_ + ; + } - my @names = grep {!ref $first->{$_}} keys %$first; - my @rels = grep { $self->result_source->has_relationship($_) } keys %$first; my @pks = $self->result_source->primary_columns; ## do the belongs_to relationships @@ -1826,17 +1835,15 @@ sub populate { delete $data->[$index]->{$rel}; $data->[$index] = {%{$data->[$index]}, %$related}; - push @names, keys %$related if $index == 0; + push @columns, keys %$related if $index == 0; } } ## do bulk insert on current row - my @values = map { [ @$_{@names} ] } @$data; - $self->result_source->storage->insert_bulk( $self->result_source, - \@names, - \@values, + \@columns, + [ map { [ @$_{@columns} ] } @$data ], ); ## do the has_many relationships @@ -1845,7 +1852,7 @@ sub populate { foreach my $rel (@rels) { next unless $item->{$rel} && ref $item->{$rel} eq "ARRAY"; - my $parent = $self->find(map {{$_=>$item->{$_}} } @pks) + my $parent = $self->find({map { $_ => $item->{$_} } @pks}) || $self->throw_exception('Cannot find the relating object.'); my $child = $parent->$rel; @@ -2564,6 +2571,23 @@ sub clear_cache { shift->set_cache(undef); } +=head2 is_paged + +=over 4 + +=item Arguments: none + +=item Return Value: true, if the resultset has been paginated + +=back + +=cut + +sub is_paged { + my ($self) = @_; + return !!$self->{attrs}{page}; +} + =head2 related_resultset =over 4 @@ -2711,8 +2735,8 @@ sub _chain_relationship { }]; my $seen = { %{$attrs->{seen_join} || {} } }; - my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}}) - ? $from->[-1][0]{-join_path} + my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}}) + ? $from->[-1][0]{-join_path} : []; @@ -2796,10 +2820,7 @@ sub _resolved_attrs { : ( ( delete $attrs->{columns} ) || - $source->storage->_order_select_columns( - $source, - [ $source->columns ], - ) + $source->columns ) ; @@ -2951,7 +2972,7 @@ sub _resolved_attrs { # 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->{offset} = ($attrs->{rows} * ($page - 1)) + ($attrs->{offset} || 0) @@ -3146,7 +3167,7 @@ These are in no particular order: =back -Which column(s) to order the results by. +Which column(s) to order the results by. [The full list of suitable values is documented in L; the following is a summary of @@ -3241,6 +3262,9 @@ When you use function/stored procedure names and do not supply an C attribute, the column names returned are storage-dependent. E.g. MySQL would return a column named C in the above example. +B You will almost always need a corresponding 'as' entry when you use +'select'. + =head2 +select =over 4 @@ -3438,12 +3462,12 @@ exactly as you might expect. =over 4 -=item * +=item * Prefetch uses the L to populate the prefetched relationships. This may or may not be what you want. -=item * +=item * If you specify a condition on a prefetched relationship, ONLY those rows that match the prefetched condition will be fetched into that relationship. @@ -3555,8 +3579,8 @@ Adds to the WHERE clause. # only return rows WHERE deleted IS NULL for all searches __PACKAGE__->resultset_attributes({ where => { deleted => undef } }); ) -Can be overridden by passing C<{ where => undef }> as an attribute -to a resulset. +Can be overridden by passing C<< { where => undef } >> as an attribute +to a resultset. =back @@ -3578,177 +3602,6 @@ By default, searches are not cached. For more examples of using these attributes, see L. -=head2 from - -=over 4 - -=item Value: \@from_clause - -=back - -The C attribute gives you manual control over the C clause of SQL -statements generated by L, allowing you to express custom C -clauses. - -NOTE: Use this on your own risk. This allows you to shoot off your foot! - -C will usually do what you need and it is strongly recommended that you -avoid using C unless you cannot achieve the desired result using C. -And we really do mean "cannot", not just tried and failed. Attempting to use -this because you're having problems with C is like trying to use x86 -ASM because you've got a syntax error in your C. Trust us on this. - -Now, if you're still really, really sure you need to use this (and if you're -not 100% sure, ask the mailing list first), here's an explanation of how this -works. - -The syntax is as follows - - - [ - { => }, - [ - { => , -join_type => 'inner|left|right' }, - [], # nested JOIN (optional) - { => , ... (more conditions) }, - ], - # More of the above [ ] may follow for additional joins - ] - - - JOIN - - [JOIN ...] - ON = - - -An easy way to follow the examples below is to remember the following: - - Anything inside "[]" is a JOIN - Anything inside "{}" is a condition for the enclosing JOIN - -The following examples utilize a "person" table in a family tree application. -In order to express parent->child relationships, this table is self-joined: - - # Person->belongs_to('father' => 'Person'); - # Person->belongs_to('mother' => 'Person'); - -C can be used to nest joins. Here we return all children with a father, -then search against all mothers of those children: - - $rs = $schema->resultset('Person')->search( - undef, - { - alias => 'mother', # alias columns in accordance with "from" - from => [ - { mother => 'person' }, - [ - [ - { child => 'person' }, - [ - { father => 'person' }, - { 'father.person_id' => 'child.father_id' } - ] - ], - { 'mother.person_id' => 'child.mother_id' } - ], - ] - }, - ); - - # Equivalent SQL: - # SELECT mother.* FROM person mother - # JOIN ( - # person child - # JOIN person father - # ON ( father.person_id = child.father_id ) - # ) - # ON ( mother.person_id = child.mother_id ) - -The type of any join can be controlled manually. To search against only people -with a father in the person table, we could explicitly use C: - - $rs = $schema->resultset('Person')->search( - undef, - { - alias => 'child', # alias columns in accordance with "from" - from => [ - { child => 'person' }, - [ - { father => 'person', -join_type => 'inner' }, - { 'father.id' => 'child.father_id' } - ], - ] - }, - ); - - # Equivalent SQL: - # SELECT child.* FROM person child - # INNER JOIN person father ON child.father_id = father.id - -You can select from a subquery by passing a resultset to from as follows. - - $schema->resultset('Artist')->search( - undef, - { alias => 'artist2', - from => [ { artist2 => $artist_rs->as_query } ], - } ); - - # and you'll get sql like this.. - # SELECT artist2.artistid, artist2.name, artist2.rank, artist2.charfield FROM - # ( SELECT me.artistid, me.name, me.rank, me.charfield FROM artists me ) artist2 - -If you need to express really complex joins, you -can supply literal SQL to C via a scalar reference. In this case -the contents of the scalar will replace the table name associated with the -resultsource. - -WARNING: This technique might very well not work as expected on chained -searches - you have been warned. - - # Assuming the Event resultsource is defined as: - - MySchema::Event->add_columns ( - sequence => { - data_type => 'INT', - is_auto_increment => 1, - }, - location => { - data_type => 'INT', - }, - type => { - data_type => 'INT', - }, - ); - MySchema::Event->set_primary_key ('sequence'); - - # This will get back the latest event for every location. The column - # selector is still provided by DBIC, all we do is add a JOIN/WHERE - # combo to limit the resultset - - $rs = $schema->resultset('Event'); - $table = $rs->result_source->name; - $latest = $rs->search ( - undef, - { from => \ " - (SELECT e1.* FROM $table e1 - JOIN $table e2 - ON e1.location = e2.location - AND e1.sequence < e2.sequence - WHERE e2.sequence is NULL - ) me", - }, - ); - - # Equivalent SQL (with the DBIC chunks added): - - SELECT me.sequence, me.location, me.type FROM - (SELECT e1.* FROM events e1 - JOIN events e2 - ON e1.location = e2.location - AND e1.sequence < e2.sequence - WHERE e2.sequence is NULL - ) me; - =head2 for =over 4