Add find_or_new and find_or_new_related
Daniel Westermann-Clark [Mon, 17 Apr 2006 20:51:37 +0000 (16:51 -0400)]
Changes
lib/DBIx/Class/Relationship/Base.pm
lib/DBIx/Class/ResultSet.pm
t/run/01core.tl
t/run/06relationship.tl

diff --git a/Changes b/Changes
index c77d47b..e96305e 100644 (file)
--- 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
index 034e5cc..c30c8e2 100644 (file)
@@ -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<DBIx::Class::Row/insert> 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<DBIx::Class::ResultSet/"find_or_create"> for details.
+L<DBIx::Class::ResultSet/find_or_create> for details.
 
 =cut
 
index d4f8fab..7c7958c 100644 (file)
@@ -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</DBIx::Class::Row/insert> on it.
+
+If you want objects to be saved immediately, use L</find_or_create> 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
index 1901380..c1a5b46 100644 (file)
@@ -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;
 
index 04d1e36..19fceb8 100644 (file)
@@ -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