X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=c2b045cf332a9f244bfba837832e2c3f189aa81a;hb=0ed8d3b659c714c617fa211f32f34879c5b224f0;hp=8d9f569bc276df095f0b5986cf23298ca06fa8f1;hpb=7c325d533bf9570ef674fc86bc023a34f5188662;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 8d9f569..c2b045c 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -11,6 +11,7 @@ use Data::Page; use Storable; use DBIx::Class::ResultSetColumn; use DBIx::Class::ResultSourceHandle; +use List::Util (); use base qw/DBIx::Class/; __PACKAGE__->mk_group_accessors('simple' => qw/result_class _source_handle/); @@ -95,6 +96,8 @@ sub new { $attrs->{alias} ||= 'me'; + # Creation of {} and bless separated to mitigate RH perl bug + # see https://bugzilla.redhat.com/show_bug.cgi?id=196836 my $self = { _source_handle => $source, result_class => $attrs->{result_class} || $source->resolve->result_class, @@ -138,6 +141,8 @@ L. For more examples of using this function, see L. For a complete documentation for the first argument, see L. +For more help on using joins with search, see L. + =cut sub search { @@ -164,18 +169,26 @@ always return a resultset, even in list context. sub search_rs { my $self = shift; - my $rows; - - unless (@_) { # no search, effectively just a clone - $rows = $self->get_cache; - } - my $attrs = {}; $attrs = pop(@_) if @_ > 1 and ref $_[$#_] eq 'HASH'; my $our_attrs = { %{$self->{attrs}} }; my $having = delete $our_attrs->{having}; my $where = delete $our_attrs->{where}; + my $rows; + + my %safe = (alias => 1, cache => 1); + + unless ( + (@_ && defined($_[0])) # @_ == () or (undef) + || + (keys %$attrs # empty attrs or only 'safe' attrs + && List::Util::first { !$safe{$_} } keys %$attrs) + ) { + # no search, effectively just a clone + $rows = $self->get_cache; + } + my $new_attrs = { %{$our_attrs}, %{$attrs} }; # merge new attrs into inherited @@ -264,6 +277,13 @@ sub search_rs { Pass a literal chunk of SQL to be added to the conditional part of the resultset query. +CAVEAT: C is provided for Class::DBI compatibility and should +only be used in that context. There are known problems using C +in chained queries; it can result in bind values in the wrong order. See +L and +L for searching techniques that do not +require C. + =cut sub search_literal { @@ -918,7 +938,7 @@ Performs an SQL C with the same query as the resultset was built with to find the number of elements. If passed arguments, does a search on the resultset and counts the results of that. -Note: When using C with C, L emulates C +Note: When using C with C, L emulates C using C. Some databases (notably SQLite) do not support C with multiple columns. If you are using such a database, you should only use columns from the main table in your C @@ -938,6 +958,7 @@ sub count { $count -= $self->{_attrs}{offset} if $self->{_attrs}{offset}; $count = $self->{attrs}{rows} if $self->{attrs}{rows} and $self->{attrs}{rows} < $count; + $count = 0 if ($count < 0); return $count; } @@ -970,7 +991,7 @@ sub _count { # Separated out so pager can get the full count # offset, order by and page are not needed to count. record_filter is cdbi delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/; - my $tmp_rs = (ref $self)->new($self->_source_handle, $attrs); + my $tmp_rs = (ref $self)->new($self->result_source, $attrs); my ($count) = $tmp_rs->cursor->next; return $count; } @@ -1250,7 +1271,7 @@ Pass an arrayref of hashrefs. Each hashref should be a structure suitable for submitting to a $resultset->create(...) method. In void context, C in L is used -to insert the data, as this is a faster method. +to insert the data, as this is a faster method. Otherwise, each set of data is inserted into the database using L, and a arrayref of the resulting row @@ -1287,6 +1308,14 @@ Example: Assuming an Artist Class that has many CDs Classes relating: print $ArtistOne->name; ## response is 'Artist One' print $ArtistThree->cds->count ## reponse is '2' + +Please note an important effect on your data when choosing between void and +wantarray context. Since void context goes straight to C in +L this will skip any component that is overriding +c. So if you are using something like L to +create primary keys for you, you will find that your PKs are empty. In this +case you will have to use the wantarray context in order to create those +values. =cut @@ -1408,7 +1437,7 @@ attribute set on the resultset (10 by default). sub page { my ($self, $page) = @_; - return (ref $self)->new($self->_source_handle, { %{$self->{attrs}}, page => $page }); + return (ref $self)->new($self->result_source, { %{$self->{attrs}}, page => $page }); } =head2 new_result @@ -1421,7 +1450,12 @@ sub page { =back -Creates an object in the resultset's result class and returns it. +Creates a new row object in the resultset's result class and returns +it. The row is not inserted into the database at this point, call +L to do that. Calling L +will tell you whether the row object has been inserted or not. + +Passes the hashref of input on to L. =cut @@ -1435,9 +1469,12 @@ sub new_result { my $alias = $self->{attrs}{alias}; my $collapsed_cond = $self->{cond} ? $self->_collapse_cond($self->{cond}) : {}; + + # precendence must be given to passed values over values inherited from the cond, + # so the order here is important. my %new = ( - %{ $self->_remove_alias($values, $alias) }, %{ $self->_remove_alias($collapsed_cond, $alias) }, + %{ $self->_remove_alias($values, $alias) }, -source_handle => $self->_source_handle, -result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED ); @@ -1535,14 +1572,63 @@ sub find_or_new { =item Arguments: \%vals -=item Return Value: $object +=item Return Value: a L $object =back -Inserts a record into the resultset and returns the object representing it. +Attempt to create a single new row or a row with multiple related rows +in the table represented by the resultset (and related tables). This +will not check for duplicate rows before inserting, use +L to do that. + +To create one row for this resultset, pass a hashref of key/value +pairs representing the columns of the table and the values you wish to +store. If the appropriate relationships are set up, foreign key fields +can also be passed an object representing the foreign row, and the +value will be set to it's primary key. + +To create related objects, pass a hashref for the value if the related +item is a foreign key relationship (L), +and use the name of the relationship as the key. (NOT the name of the field, +necessarily). For C and C relationships, pass an arrayref +of hashrefs containing the data for each of the rows to create in the foreign +tables, again using the relationship name as the key. + +Instead of hashrefs of plain related data (key/value pairs), you may +also pass new or inserted objects. New objects (not inserted yet, see +L), will be inserted into their appropriate tables. Effectively a shortcut for C<< ->new_result(\%vals)->insert >>. +Example of creating a new row. + + $person_rs->create({ + name=>"Some Person", + email=>"somebody@someplace.com" + }); + +Example of creating a new row and also creating rows in a related C +or C resultset. Note Arrayref. + + $artist_rs->create( + { artistid => 4, name => 'Manufactured Crap', cds => [ + { title => 'My First CD', year => 2006 }, + { title => 'Yet More Tweeny-Pop crap', year => 2007 }, + ], + }, + ); + +Example of creating a new row and also creating a row in a related +Cresultset. Note Hashref. + + $cd_rs->create({ + title=>"Music for Silly Walks", + year=>2000, + artist => { + name=>"Silly Musician", + } + }); + =cut sub create { @@ -1736,7 +1822,7 @@ sub related_resultset { my $rel_obj = $self->result_source->relationship_info($rel); $self->throw_exception( - "search_related: result source '" . $self->_source_handle->source_moniker . + "search_related: result source '" . $self->result_source->source_name . "' has no such relationship $rel") unless $rel_obj; @@ -1747,7 +1833,7 @@ sub related_resultset { #XXX - temp fix for result_class bug. There likely is a more elegant fix -groditi my %attrs = %{$self->{attrs}||{}}; - delete $attrs{result_class}; + delete @attrs{qw(result_class alias)}; my $new_cache; @@ -1758,21 +1844,32 @@ sub related_resultset { } } - my $new = $self->_source_handle - ->schema - ->resultset($rel_obj->{class}) - ->search_rs( - undef, { - %attrs, - join => undef, - prefetch => undef, - select => undef, - as => undef, - alias => $alias, - where => $self->{cond}, - seen_join => $seen, - from => $from, - }); + my $rel_source = $self->result_source->related_source($rel); + + my $new = do { + + # The reason we do this now instead of passing the alias to the + # search_rs below is that if you wrap/overload resultset on the + # source you need to know what alias it's -going- to have for things + # to work sanely (e.g. RestrictWithObject wants to be able to add + # extra query restrictions, and these may need to be $alias.) + + my $attrs = $rel_source->resultset_attributes; + local $attrs->{alias} = $alias; + + $rel_source->resultset + ->search_rs( + undef, { + %attrs, + join => undef, + prefetch => undef, + select => undef, + as => undef, + where => $self->{cond}, + seen_join => $seen, + from => $from, + }); + }; $new->set_cache($new_cache) if $new_cache; $new; }; @@ -1990,10 +2087,10 @@ sub _merge_attr { $position++; } my ($b_key) = ( ref $b_element eq 'HASH' ) ? keys %{$b_element} : ($b_element); + if ($best_candidate->{score} == 0 || exists $seen_keys->{$b_key}) { push( @{$a}, $b_element ); } else { - $seen_keys->{$b_key} = 1; # don't merge the same key twice my $a_best = $a->[$best_candidate->{position}]; # merge a_best and b_element together and replace original with merged if (ref $a_best ne 'HASH') { @@ -2003,6 +2100,7 @@ sub _merge_attr { $a->[$best_candidate->{position}] = { $key => $self->_merge_attr($a_best->{$key}, $b_element->{$key}) }; } } + $seen_keys->{$b_key} = 1; # don't merge the same key twice } return $a; @@ -2115,7 +2213,7 @@ return a column named C in the above example. =over 4 Indicates additional columns to be selected from storage. Works the same as -L but adds columns to the selection. =back @@ -2123,7 +2221,7 @@ L. -The C< as > attribute is used in conjunction with C, usually when C