From: Peter Rabbitson Date: Wed, 24 Jun 2009 10:12:49 +0000 (+0000) Subject: find_related fix for single-type relationships X-Git-Tag: v0.08108~64 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=2284af7e437db36ac5ab4defa6dd7085a16a58fe;p=dbsrgits%2FDBIx-Class.git find_related fix for single-type relationships --- diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 117563d..796bde7 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -513,6 +513,14 @@ sub find { my $unique_query = $self->_build_unique_query($input_query, \@unique_cols); $query = $self->_add_alias($unique_query, $alias); } + elsif ($self->{attrs}{accessor} and $self->{attrs}{accessor} eq 'single') { + # This means that we got here after a merger of relationship conditions + # 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 + # relationship + } else { my @unique_queries = $self->_unique_queries($input_query, $attrs); $query = @unique_queries @@ -521,27 +529,14 @@ sub find { } # Run the query - if (keys %$attrs) { - my $rs = $self->search($query, $attrs); - if (keys %{$rs->_resolved_attrs->{collapse}}) { - my $row = $rs->next; - carp "Query returned more than one row" if $rs->next; - return $row; - } - else { - return $rs->single; - } + my $rs = $self->search ($query, $attrs); + if (keys %{$rs->_resolved_attrs->{collapse}}) { + my $row = $rs->next; + carp "Query returned more than one row" if $rs->next; + return $row; } else { - if (keys %{$self->_resolved_attrs->{collapse}}) { - my $rs = $self->search($query); - my $row = $rs->next; - carp "Query returned more than one row" if $rs->next; - return $row; - } - else { - return $self->single($query); - } + return $rs->single; } } @@ -2448,12 +2443,12 @@ sub related_resultset { $self->{related_resultsets} ||= {}; return $self->{related_resultsets}{$rel} ||= do { - my $rel_obj = $self->result_source->relationship_info($rel); + my $rel_info = $self->result_source->relationship_info($rel); $self->throw_exception( "search_related: result source '" . $self->result_source->source_name . "' has no such relationship $rel") - unless $rel_obj; + unless $rel_info; my ($from,$seen) = $self->_resolve_from($rel); @@ -2554,7 +2549,7 @@ sub current_source_alias { # with a relation_chain_depth less than the depth of the # current prefetch is not considered) sub _resolve_from { - my ($self, $extra_join) = @_; + my ($self, $rel) = @_; my $source = $self->result_source; my $attrs = $self->{attrs}; @@ -2578,7 +2573,7 @@ sub _resolve_from { ++$seen->{-relation_chain_depth}; - push @$from, $source->_resolve_join($extra_join, $attrs->{alias}, $seen); + push @$from, $source->_resolve_join($rel, $attrs->{alias}, $seen); ++$seen->{-relation_chain_depth}; diff --git a/t/lib/DBICTest/Schema/Genre.pm b/t/lib/DBICTest/Schema/Genre.pm index 3b3675a..dceabc9 100644 --- a/t/lib/DBICTest/Schema/Genre.pm +++ b/t/lib/DBICTest/Schema/Genre.pm @@ -20,4 +20,6 @@ __PACKAGE__->add_unique_constraint ( genre_name => [qw/name/] ); __PACKAGE__->has_many (cds => 'DBICTest::Schema::CD', 'genreid'); +__PACKAGE__->has_one (model_cd => 'DBICTest::Schema::CD', 'genreid'); + 1; diff --git a/t/lib/DBICTest/Schema/Track.pm b/t/lib/DBICTest/Schema/Track.pm index 70dc805..4966800 100644 --- a/t/lib/DBICTest/Schema/Track.pm +++ b/t/lib/DBICTest/Schema/Track.pm @@ -46,6 +46,4 @@ __PACKAGE__->belongs_to( disc => 'DBICTest::Schema::CD' => 'cd'); __PACKAGE__->might_have( cd_single => 'DBICTest::Schema::CD', 'single_track' ); __PACKAGE__->might_have( lyrics => 'DBICTest::Schema::Lyrics', 'track_id' ); -__PACKAGE__->has_one( undying_lyric => 'DBICTest::Schema::Lyrics', 'track_id' ); - 1; diff --git a/t/relationship/update_or_create_multi.t b/t/relationship/update_or_create_multi.t new file mode 100644 index 0000000..e75fede --- /dev/null +++ b/t/relationship/update_or_create_multi.t @@ -0,0 +1,88 @@ +use strict; +use warnings; + +use Test::More; +use Test::Exception; +use lib qw(t/lib); +use DBICTest; +use DBIC::SqlMakerTest; + +my $schema = DBICTest->init_schema(); + +#plan tests => 4; +plan 'no_plan'; + +my $artist = $schema->resultset ('Artist')->first; + +my $genre = $schema->resultset ('Genre') + ->create ({ name => 'par excellence' }); + +is ($genre->search_related( 'cds' )->count, 0, 'No cds yet'); + +# expect a create +$genre->update_or_create_related ('cds', { + artist => $artist, + year => 2009, + title => 'the best thing since sliced bread', +}); + +# verify cd was inserted ok +is ($genre->search_related( 'cds' )->count, 1, 'One cd'); +my $cd = $genre->find_related ('cds', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2009, + title => 'the best thing since sliced bread', + }, + 'CD created correctly', +); + +# expect a year update on the only related row +# (non-qunique column + unique column as disambiguator) +$genre->update_or_create_related ('cds', { + year => 2010, + title => 'the best thing since sliced bread', +}); + +# re-fetch the cd, verify update +is ($genre->search_related( 'cds' )->count, 1, 'Still one cd'); +$cd = $genre->find_related ('cds', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2010, + title => 'the best thing since sliced bread', + }, + 'CD year column updated correctly', +); + + +# expect a create, after a failed search using *only* the +# *current* relationship and the unique column constraints +# (so no year) +my @sql; +$schema->storage->debugcb(sub { push @sql, $_[1] }); +$schema->storage->debug (1); + +$genre->update_or_create_related ('cds', { + title => 'the best thing since vertical toasters', + artist => $artist, + year => 2012, +}); + +$schema->storage->debugcb(undef); + +is_same_sql ( + $sql[0], + 'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track + FROM cd me + WHERE ( me.artist = ? AND me.title = ? AND me.genreid = ? ) + ', + 'expected select issued', +); + +# a has_many search without a unique constraint makes no sense +# but I am not sure what to test for - leaving open diff --git a/t/relationship/update_or_create_single.t b/t/relationship/update_or_create_single.t new file mode 100644 index 0000000..63ae4b1 --- /dev/null +++ b/t/relationship/update_or_create_single.t @@ -0,0 +1,100 @@ +use strict; +use warnings; + +use Test::More; +use lib qw(t/lib); +use DBICTest; + +my $schema = DBICTest->init_schema(); + +#plan tests => 4; +plan 'no_plan'; + +my $artist = $schema->resultset ('Artist')->first; + +my $genre = $schema->resultset ('Genre') + ->create ({ name => 'par excellence' }); + +is ($genre->search_related( 'model_cd' )->count, 0, 'No cds yet'); + +# expect a create +$genre->update_or_create_related ('model_cd', { + artist => $artist, + year => 2009, + title => 'the best thing since sliced bread', +}); + +# verify cd was inserted ok +is ($genre->search_related( 'model_cd' )->count, 1, 'One cd'); +my $cd = $genre->find_related ('model_cd', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2009, + title => 'the best thing since sliced bread', + }, + 'CD created correctly', +); + +# expect a year update on the only related row +# (non-qunique column + unique column as disambiguator) +$genre->update_or_create_related ('model_cd', { + year => 2010, + title => 'the best thing since sliced bread', +}); + +# re-fetch the cd, verify update +is ($genre->search_related( 'model_cd' )->count, 1, 'Still one cd'); +$cd = $genre->find_related ('model_cd', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2010, + title => 'the best thing since sliced bread', + }, + 'CD year column updated correctly', +); + + +# expect an update of the only related row +# (update a unique column) +$genre->update_or_create_related ('model_cd', { + title => 'the best thing since vertical toasters', +}); + +# re-fetch the cd, verify update +is ($genre->search_related( 'model_cd' )->count, 1, 'Still one cd'); +$cd = $genre->find_related ('model_cd', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2010, + title => 'the best thing since vertical toasters', + }, + 'CD title column updated correctly', +); + + +# expect a year update on the only related row +# (non-qunique column only) +$genre->update_or_create_related ('model_cd', { + year => 2011, +}); + +# re-fetch the cd, verify update +is ($genre->search_related( 'model_cd' )->count, 1, 'Still one cd'); +$cd = $genre->find_related ('model_cd', {}); +is_deeply ( + { map { $_, $cd->get_column ($_) } qw/artist year title/ }, + { + artist => $artist->id, + year => 2011, + title => 'the best thing since vertical toasters', + }, + 'CD year column updated correctly without a disambiguator', +); + +