From: Daniel Westermann-Clark Date: Mon, 17 Apr 2006 20:51:37 +0000 (-0400) Subject: Add find_or_new and find_or_new_related X-Git-Tag: v0.07002~75^2~237^2~12 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b3e1f1f59a5a9010c6023f9fe5c231fe69352c20;p=dbsrgits%2FDBIx-Class.git Add find_or_new and find_or_new_related --- diff --git a/Changes b/Changes index c77d47b..e96305e 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,7 @@ Revision history for DBIx::Class - added source_name to ResultSource - load_classes now uses source_name and sets it if necessary - add update_or_create_related + - add find_or_new and find_or_new_related 0.06002 - fix for -and conditions when updating or deleting on a ResultSet diff --git a/lib/DBIx/Class/Relationship/Base.pm b/lib/DBIx/Class/Relationship/Base.pm index 034e5cc..c30c8e2 100644 --- a/lib/DBIx/Class/Relationship/Base.pm +++ b/lib/DBIx/Class/Relationship/Base.pm @@ -238,12 +238,27 @@ sub find_related { return $self->search_related($rel)->find(@_); } +=head2 find_or_new_related + + my $new_obj = $obj->find_or_new_related('relname', \%col_data); + +Find an item of a related class. If none exists, instantiate a new item of the +related class. The object will not be saved into your storage until you call +L on it. + +=cut + +sub find_or_new_related { + my $self = shift; + return $self->find_related(@_) || $self->new_related(@_); +} + =head2 find_or_create_related my $new_obj = $obj->find_or_create_related('relname', \%col_data); Find or create an item of a related class. See -L for details. +L for details. =cut diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index d4f8fab..7c7958c 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -1079,6 +1079,32 @@ sub new_result { return $obj; } +=head2 find_or_new + +=over 4 + +=item Arguments: \%vals, \%attrs? + +=item Return Value: $object + +=back + +Find an existing record from this resultset. If none exists, instantiate a new +result object and return it. The object will not be saved into your storage +until you call L on it. + +If you want objects to be saved immediately, use L instead. + +=cut + +sub find_or_new { + my $self = shift; + my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {}); + my $hash = ref $_[0] eq 'HASH' ? shift : {@_}; + my $exists = $self->find($hash, $attrs); + return defined $exists ? $exists : $self->new_result($hash); +} + =head2 create =over 4 diff --git a/t/run/01core.tl b/t/run/01core.tl index 1901380..c1a5b46 100644 --- a/t/run/01core.tl +++ b/t/run/01core.tl @@ -1,7 +1,7 @@ sub run_tests { my $schema = shift; -plan tests => 51; +plan tests => 55; # figure out if we've got a version of sqlite that is older than 3.2.6, in # which case COUNT(DISTINCT()) doesn't work @@ -88,6 +88,24 @@ is($new_again->ID, 'DBICTest::Artist|artist|artistid=4', 'unique object id gener is($schema->resultset("Artist")->count, 4, 'count ok'); +# test find_or_new +{ + my $existing_obj = $schema->resultset('Artist')->find_or_new({ + artistid => 4, + }); + + is($existing_obj->name, 'Man With A Spoon', 'find_or_new: found existing artist'); + ok($existing_obj->in_storage, 'existing artist is in storage'); + + my $new_obj = $schema->resultset('Artist')->find_or_new({ + artistid => 5, + name => 'find_or_new', + }); + + is($new_obj->name, 'find_or_new', 'find_or_new: instantiated a new artist'); + ok(! $new_obj->in_storage, 'new artist is not in storage'); +} + my $cd = $schema->resultset("CD")->find(1); my %cols = $cd->get_columns; diff --git a/t/run/06relationship.tl b/t/run/06relationship.tl index 04d1e36..19fceb8 100644 --- a/t/run/06relationship.tl +++ b/t/run/06relationship.tl @@ -3,7 +3,7 @@ my $schema = shift; use strict; use warnings; -plan tests => 25; +plan tests => 29; # has_a test my $cd = $schema->resultset("CD")->find(4); @@ -89,6 +89,19 @@ is( ($artist->search_related('cds'))[4]->title, 'Greatest Hits', 'find_or_create $artist->delete_related( cds => { title => 'Greatest Hits' }); cmp_ok( $schema->resultset("CD")->search( title => 'Greatest Hits' ), '==', 0, 'delete_related ok' ); +# find_or_new_related with an existing record +$cd = $artist->find_or_new_related( 'cds', { title => 'Big Flop' } ); +is( $cd->year, 2005, 'find_or_new_related on existing record ok' ); +ok( $cd->in_storage, 'find_or_new_related on existing record: is in_storage' ); + +# find_or_new_related instantiating a new record +$cd = $artist->find_or_new_related( 'cds', { + title => 'Greatest Hits 2: Louder Than Ever', + year => 2007, +} ); +is( $cd->title, 'Greatest Hits 2: Louder Than Ever', 'find_or_new_related new record ok' ); +ok( ! $cd->in_storage, 'find_or_new_related on a new record: not in_storage' ); + SKIP: { skip "relationship checking needs fixing", 1; # try to add a bogus relationship using the wrong cols