added more many_to_many tests and changed add_to_rel to accept linking table column...
Justin Guenther [Sat, 17 Jun 2006 13:51:00 +0000 (13:51 +0000)]
lib/DBIx/Class/Relationship.pm
lib/DBIx/Class/Relationship/ManyToMany.pm
t/66relationship.t
t/lib/DBICTest.pm
t/lib/DBICTest/Schema.pm
t/lib/DBICTest/Schema/FourKeys.pm
t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm [new file with mode: 0644]
t/lib/DBICTest/Schema/TwoKeys.pm
t/lib/sqlite.sql

index dd36166..9420ab7 100644 (file)
@@ -216,29 +216,50 @@ relation names are then used in the many_to_many call.
 
 =head4 $rel
 
+=over 4
+
+=item Arguments: $vals?, $attrs
+
+=back
+
   my $role_rs = $actor->roles;
 
   my $role1 = $actor->roles({ name => 'role1' })->first;
 
-Returns a resultset for the table on the far-right side of the many-to-many
-relationship. (e.g., in the above example, a CD's producers).
+Returns a resultset for the foreign table on the right side of the
+many-to-many relationship. (e.g., in the above example, a CD's
+producers). Takes the same arguments as L<DBIx::Class::ResultSet/"search">.
 
 =head4 add_to_$rel
 
+=over 4
+
+=item Arguments: ($foreign_vals | $obj), $link_vals?
+
+=back
+
   my $role = $schema->resultset('Role')->find(1);
   $actor->add_to_roles($role);
       # creates a My::DBIC::Schema::ActorRoles linking table row object
 
-  $actor->add_to_roles({ name => 'role1' });
-      # creates a new My::DBIC::Schema::Role row object, as well as the
-      # linking table object
+  $actor->add_to_roles({ name => 'lead' }, { salary => 15_000_000 });
+      # creates a new My::DBIC::Schema::Role row object and the linking table
+      # object with an extra column in the link
 
-Adds a linking table object for the specified object, or if a hash is given
-instead the related object is created before the linking table object is
-created.
+Adds a linking table object for C<$obj> or C<$foreign_vals>. If the first
+argument is a hash reference, the related object is created first with the
+column values in the hash. If an object reference is given, just the linking
+table object is created. In either case, any additional column values for the
+linking table object can be specified in C<$link_vals>.
 
 =head4 remove_from_$rel
 
+=over 4
+
+=item Arguments: $obj
+
+=back
+
   my $role = $schema->resultset('Role')->find(1);
   $actor->remove_from_roles($role);
       # removes $role's My::DBIC::Schema::ActorRoles linking table row object
index 8b29bf4..417c65d 100644 (file)
@@ -35,8 +35,10 @@ sub many_to_many {
       my $obj = ref $_[0]
         ? ( ref $_[0] eq 'HASH' ? $f_rel_rs->create($_[0]) : $_[0] )
         : ( $f_rel_rs->create({@_}) );
+      my $link_vals = @_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {};
       my $link = $self->search_related($rel)->new_result({});
       $link->set_from_related($f_rel, $obj);
+      $link->set_columns($link_vals);
       $link->insert();
     };
 
index 868ce15..5edbb34 100644 (file)
@@ -7,7 +7,7 @@ use DBICTest;
 
 my $schema = DBICTest->init_schema();
 
-plan tests => 40;
+plan tests => 49;
 
 # has_a test
 my $cd = $schema->resultset("CD")->find(4);
@@ -154,6 +154,20 @@ like( $@, qr/needs an object/, 'remove_from_$rel($hash) dies correctly' );
 eval { $cd->add_to_producers(); };
 like( $@, qr/needs an object or hashref/, 'add_to_$rel(undef) dies correctly' );
 
+# many_to_many stresstest
+my $twokey = $schema->resultset('TwoKeys')->find(1,1);
+my $fourkey = $schema->resultset('FourKeys')->find(1,2,3,4);
+
+is( $twokey->fourkeys->count, 0, 'twokey has no fourkeys' );
+$twokey->add_to_fourkeys($fourkey, { autopilot => 'engaged' });
+my $got_fourkey = $twokey->fourkeys({ sensors => 'online' })->first;
+is( $twokey->fourkeys->count, 1, 'twokey has one fourkey' );
+is( $got_fourkey->$_, $fourkey->$_,
+    'fourkeys row has the correct value for column '.$_ )
+  for (qw(foo bar hello goodbye sensors));
+$twokey->remove_from_fourkeys($fourkey);
+is( $twokey->fourkeys->count, 0, 'twokey has no fourkeys' );
+is( $twokey->fourkeys_to_twokeys->count, 0, 'twokey has no links to fourkey' );
 
 # test undirected many-to-many relationship (e.g. "related artists")
 my $undir_maps = $schema->resultset("Artist")->find(1)->artist_undirected_maps;
index 9dbbf55..963eb4c 100755 (executable)
@@ -149,9 +149,9 @@ sub populate_schema {
     ]);
 
     $schema->populate('FourKeys', [
-        [ qw/foo bar hello goodbye/ ],
-        [ 1, 2, 3, 4 ],
-        [ 5, 4, 3, 6 ],
+        [ qw/foo bar hello goodbye sensors/ ],
+        [ 1, 2, 3, 4, 'online' ],
+        [ 5, 4, 3, 6, 'offline' ],
     ]);
 
     $schema->populate('OneKey', [
index 72e1da6..9de55a1 100644 (file)
@@ -24,6 +24,7 @@ __PACKAGE__->load_classes(qw/
   /]},
   (
     'FourKeys',
+    'FourKeys_to_TwoKeys',
     '#dummy',
     'SelfRef',
     'ArtistUndirectedMap',
index 71659e6..cdffa2f 100644 (file)
@@ -9,7 +9,20 @@ DBICTest::Schema::FourKeys->add_columns(
   'bar' => { data_type => 'integer' },
   'hello' => { data_type => 'integer' },
   'goodbye' => { data_type => 'integer' },
+  'sensors' => { data_type => 'character' },
 );
 DBICTest::Schema::FourKeys->set_primary_key(qw/foo bar hello goodbye/);
 
+DBICTest::Schema::FourKeys->has_many(
+  'fourkeys_to_twokeys', 'DBICTest::Schema::FourKeys_to_TwoKeys', {
+    'foreign.f_foo' => 'self.foo',
+    'foreign.f_bar' => 'self.bar',
+    'foreign.f_hello' => 'self.hello',
+    'foreign.f_goodbye' => 'self.goodbye',
+});
+
+DBICTest::Schema::FourKeys->many_to_many(
+  'twokeys', 'fourkeys_to_twokeys', 'twokeys',
+);
+
 1;
diff --git a/t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm b/t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm
new file mode 100644 (file)
index 0000000..6e86313
--- /dev/null
@@ -0,0 +1,32 @@
+package # hide from PAUSE 
+    DBICTest::Schema::FourKeys_to_TwoKeys;
+
+use base 'DBIx::Class::Core';
+
+__PACKAGE__->table('fourkeys_to_twokeys');
+__PACKAGE__->add_columns(
+  'f_foo' => { data_type => 'integer' },
+  'f_bar' => { data_type => 'integer' },
+  'f_hello' => { data_type => 'integer' },
+  'f_goodbye' => { data_type => 'integer' },
+  't_artist' => { data_type => 'integer' },
+  't_cd' => { data_type => 'integer' },
+  'autopilot' => { data_type => 'character' },
+);
+__PACKAGE__->set_primary_key(
+  qw/f_foo f_bar f_hello f_goodbye t_artist t_cd/
+);
+
+__PACKAGE__->belongs_to('fourkeys', 'DBICTest::Schema::FourKeys', {
+  'foreign.foo' => 'self.f_foo',
+  'foreign.bar' => 'self.f_bar',
+  'foreign.hello' => 'self.f_hello',
+  'foreign.goodbye' => 'self.f_goodbye',
+});
+
+__PACKAGE__->belongs_to('twokeys', 'DBICTest::Schema::TwoKeys', {
+  'foreign.artist' => 'self.t_artist',
+  'foreign.cd' => 'self.t_cd',
+});
+
+1;
index 8483d0b..7bb1965 100755 (executable)
@@ -13,4 +13,14 @@ __PACKAGE__->set_primary_key(qw/artist cd/);
 __PACKAGE__->belongs_to( artist => 'DBICTest::Schema::Artist' );
 __PACKAGE__->belongs_to( cd => 'DBICTest::Schema::CD' );
 
+__PACKAGE__->has_many(
+  'fourkeys_to_twokeys', 'DBICTest::Schema::FourKeys_to_TwoKeys', {
+    'foreign.t_artist' => 'self.artist',
+    'foreign.t_cd' => 'self.cd',
+});
+
+__PACKAGE__->many_to_many(
+  'fourkeys', 'fourkeys_to_twokeys', 'fourkeys',
+);
+
 1;
index d7fa393..551d159 100644 (file)
@@ -1,6 +1,6 @@
 -- 
 -- Created by SQL::Translator::Producer::SQLite
--- Created on Sat May 27 21:28:05 2006
+-- Created on Sat Jun 17 07:46:56 2006
 -- 
 BEGIN TRANSACTION;
 
@@ -23,14 +23,6 @@ CREATE TABLE serialized (
 );
 
 --
--- Table: liner_notes
---
-CREATE TABLE liner_notes (
-  liner_id INTEGER PRIMARY KEY NOT NULL,
-  notes varchar(100) NOT NULL
-);
-
---
 -- Table: cd_to_producer
 --
 CREATE TABLE cd_to_producer (
@@ -40,6 +32,14 @@ CREATE TABLE cd_to_producer (
 );
 
 --
+-- Table: liner_notes
+--
+CREATE TABLE liner_notes (
+  liner_id INTEGER PRIMARY KEY NOT NULL,
+  notes varchar(100) NOT NULL
+);
+
+--
 -- Table: artist
 --
 CREATE TABLE artist (
@@ -48,6 +48,20 @@ CREATE TABLE artist (
 );
 
 --
+-- Table: fourkeys_to_twokeys
+--
+CREATE TABLE fourkeys_to_twokeys (
+  f_foo integer NOT NULL,
+  f_bar integer NOT NULL,
+  f_hello integer NOT NULL,
+  f_goodbye integer NOT NULL,
+  t_artist integer NOT NULL,
+  t_cd integer NOT NULL,
+  autopilot character NOT NULL,
+  PRIMARY KEY (f_foo, f_bar, f_hello, f_goodbye, t_artist, t_cd)
+);
+
+--
 -- Table: twokeytreelike
 --
 CREATE TABLE twokeytreelike (
@@ -97,28 +111,19 @@ CREATE TABLE track (
 );
 
 --
--- Table: self_ref
+-- Table: treelike
 --
-CREATE TABLE self_ref (
+CREATE TABLE treelike (
   id INTEGER PRIMARY KEY NOT NULL,
+  parent integer NOT NULL,
   name varchar(100) NOT NULL
 );
 
 --
--- Table: tags
---
-CREATE TABLE tags (
-  tagid INTEGER PRIMARY KEY NOT NULL,
-  cd integer NOT NULL,
-  tag varchar(100) NOT NULL
-);
-
---
--- Table: treelike
+-- Table: self_ref
 --
-CREATE TABLE treelike (
+CREATE TABLE self_ref (
   id INTEGER PRIMARY KEY NOT NULL,
-  parent integer NOT NULL,
   name varchar(100) NOT NULL
 );
 
@@ -132,6 +137,15 @@ CREATE TABLE link (
 );
 
 --
+-- Table: tags
+--
+CREATE TABLE tags (
+  tagid INTEGER PRIMARY KEY NOT NULL,
+  cd integer NOT NULL,
+  tag varchar(100) NOT NULL
+);
+
+--
 -- Table: event
 --
 CREATE TABLE event (
@@ -156,6 +170,7 @@ CREATE TABLE fourkeys (
   bar integer NOT NULL,
   hello integer NOT NULL,
   goodbye integer NOT NULL,
+  sensors character NOT NULL,
   PRIMARY KEY (foo, bar, hello, goodbye)
 );
 
@@ -169,6 +184,14 @@ CREATE TABLE artist_undirected_map (
 );
 
 --
+-- Table: producer
+--
+CREATE TABLE producer (
+  producerid INTEGER PRIMARY KEY NOT NULL,
+  name varchar(100) NOT NULL
+);
+
+--
 -- Table: onekey
 --
 CREATE TABLE onekey (
@@ -177,14 +200,6 @@ CREATE TABLE onekey (
   cd integer NOT NULL
 );
 
---
--- Table: producer
---
-CREATE TABLE producer (
-  producerid INTEGER PRIMARY KEY NOT NULL,
-  name varchar(100) NOT NULL
-);
-
 CREATE UNIQUE INDEX tktlnameunique_twokeytreelike on twokeytreelike (name);
 CREATE UNIQUE INDEX cd_artist_title_cd on cd (artist, title);
 CREATE UNIQUE INDEX prod_name_producer on producer (name);