d54deba01ce0634516d362b84dbd85a76ecebfc3
[dbsrgits/DBIx-Class-Historic.git] / t / 96multi_create.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6 use lib qw(t/lib);
7 use DBICTest;
8
9 plan tests => 97;
10
11 my $schema = DBICTest->init_schema();
12
13 # simple create + parent (the stuff $rs belongs_to)
14 eval {
15   my $cd = $schema->resultset('CD')->create({
16     artist => { 
17       name => 'Fred Bloggs' 
18     },
19     title => 'Some CD',
20     year => 1996
21   });
22
23   isa_ok($cd, 'DBICTest::CD', 'Created CD object');
24   isa_ok($cd->artist, 'DBICTest::Artist', 'Created related Artist');
25   is($cd->artist->name, 'Fred Bloggs', 'Artist created correctly');
26 };
27 diag $@ if $@;
28
29 # same as above but the child and parent have no values,
30 # except for an explicit parent pk
31 eval {
32   my $bm_rs = $schema->resultset('Bookmark');
33   my $bookmark = $bm_rs->create({
34     link => {
35       id => 66,
36     },
37   });
38
39   isa_ok($bookmark, 'DBICTest::Bookmark', 'Created Bookrmark object');
40   isa_ok($bookmark->link, 'DBICTest::Link', 'Created related Link');
41   is (
42     $bm_rs->search (
43       { 'link.title' => $bookmark->link->title },
44       { join => 'link' },
45     )->count,
46     1,
47     'Bookmark and link made it to the DB',
48   );
49 };
50 diag $@ if $@;
51
52 # create over > 1 levels of has_many create (A => { has_many => { B => has_many => C } } )
53 eval {
54   my $artist = $schema->resultset('Artist')->first;
55   my $cd = $artist->create_related (cds => {
56     title => 'Music to code by',
57     year => 2007,
58     tags => [
59       { 'tag' => 'rock' },
60     ],
61   });
62
63   isa_ok($cd, 'DBICTest::CD', 'Created CD');
64   is($cd->title, 'Music to code by', 'CD created correctly');
65   is($cd->tags->count, 1, 'One tag created for CD');
66   is($cd->tags->first->tag, 'rock', 'Tag created correctly');
67
68 };
69 diag $@ if $@;
70
71 throws_ok (
72   sub {
73     # Create via update - add a new CD <--- THIS SHOULD HAVE NEVER WORKED!
74     $schema->resultset('Artist')->first->update({
75       cds => [
76         { title => 'Yet another CD',
77           year => 2006,
78         },
79       ],
80     });
81   },
82   qr/Recursive update is not supported over relationships of type multi/,
83   'create via update of multi relationships throws an exception'
84 );
85
86 # Create m2m while originating in the linker table
87 eval {
88   my $artist = $schema->resultset('Artist')->first;
89   my $c2p = $schema->resultset('CD_to_Producer')->create ({
90     cd => {
91       artist => $artist,
92       title => 'Bad investment',
93       year => 2008,
94       tracks => [
95         { position => 1, title => 'Just buy' },
96         { position => 2, title => 'Why did we do it' },
97         { position => 3, title => 'Burn baby burn' },
98       ],
99     },
100     producer => {
101       name => 'Lehman Bros.',
102     },
103   });
104
105   isa_ok ($c2p, 'DBICTest::CD_to_Producer', 'Linker object created');
106   my $prod = $schema->resultset ('Producer')->find ({ name => 'Lehman Bros.' });
107   isa_ok ($prod, 'DBICTest::Producer', 'Producer row found');
108   is ($prod->cds->count, 1, 'Producer has one production');
109   my $cd = $prod->cds->first;
110   is ($cd->title, 'Bad investment', 'CD created correctly');
111   is ($cd->tracks->count, 3, 'CD has 3 tracks');
112
113 };
114 diag $@ if $@;
115
116 # create over > 1 levels of might_have with multiple has_many and multiple m2m
117 # but starting at a has_many level
118 # (A => { might_have => { B => has_many => C <= has_many D} } ) or
119 # CD -> has_many -> Tracks -> might have -> Single -> has_many -> Tracks
120 #                                                \
121 #                                                 \-> has_many \
122 #                                                               --> CD2Producer
123 #                                                 /-> has_many /
124 #                                                /
125 #                                           Producer
126 eval {
127   my $artist = $schema->resultset('Artist')->first;
128   my $cd = $schema->resultset('CD')->create ({
129     artist => $artist,
130     title => 'Music to code by at night',
131     year => 2008,
132     tracks => [
133       {
134         position => 1, # some day me might test this with Ordered
135         title => 'Off by one again',
136       },
137       {
138         position => 2,
139         title => 'The dereferencer',
140         cd_single => {
141           artist => $artist,
142           year => 2008,
143           title => 'Was that a null (Single)',
144           tracks => [
145             { title => 'The dereferencer', position => 1 },
146             { title => 'The dereferencer II', position => 2 },
147           ],
148           cd_to_producer => [
149             {
150               producer => {
151                 name => 'K&R',
152               }
153             },
154             {
155               producer => {
156                 name => 'Don Knuth',
157               }
158             },
159           ]
160         },
161       },
162     ],
163   });
164
165   isa_ok ($cd, 'DBICTest::CD', 'Main CD object created');
166   is ($cd->title, 'Music to code by at night', 'Correct CD title');
167   is ($cd->tracks->count, 2, 'Two tracks on main CD');
168
169   my ($t1, $t2) = $cd->tracks->all;
170   is ($t1->title, 'Off by one again', 'Correct 1st track name');
171   is ($t1->cd_single, undef, 'No single for 1st track');
172   is ($t2->title, 'The dereferencer', 'Correct 2nd track name');
173   isa_ok ($t2->cd_single, 'DBICTest::CD', 'Created a single for 2nd track');
174
175   my $single = $t2->cd_single;
176   is ($single->tracks->count, 2, 'Two tracks on single CD');
177   is ($single->tracks->find ({ position => 1})->title, 'The dereferencer', 'Correct 1st track title');
178   is ($single->tracks->find ({ position => 2})->title, 'The dereferencer II', 'Correct 2nd track title');
179
180   is ($single->cd_to_producer->count, 2, 'Two producers created for the single cd');
181   is_deeply (
182     [ sort map { $_->producer->name } ($single->cd_to_producer->all) ],
183     ['Don Knuth', 'K&R'],
184     'Producers named correctly',
185   );
186 };
187 diag $@ if $@;
188
189 # Same as above but starting at the might_have directly
190 # Track -> might have -> Single -> has_many -> Tracks
191 #                           \
192 #                            \-> has_many \
193 #                                          --> CD2Producer
194 #                            /-> has_many /
195 #                           /
196 #                       Producer
197 eval {
198   my $cd = $schema->resultset('CD')->first;
199   my $track = $schema->resultset('Track')->create ({
200     cd => $cd,
201     position => 77,  # some day me might test this with Ordered
202     title => 'Multicreate rocks',
203     cd_single => {
204       artist => $cd->artist,
205       year => 2008,
206       title => 'Disemboweling MultiCreate',
207       tracks => [
208         { title => 'Why does mst write this way', position => 1 },
209         { title => 'Chainsaw celebration', position => 2 },
210         { title => 'Purl cleans up', position => 3 },
211       ],
212       cd_to_producer => [
213         {
214           producer => {
215             name => 'mst',
216           }
217         },
218         {
219           producer => {
220             name => 'castaway',
221           }
222         },
223         {
224           producer => {
225             name => 'theorbtwo',
226           }
227         },
228       ]
229     },
230   });
231
232   isa_ok ($track, 'DBICTest::Track', 'Main Track object created');
233   is ($track->title, 'Multicreate rocks', 'Correct Track title');
234
235   my $single = $track->cd_single;
236   isa_ok ($single, 'DBICTest::CD', 'Created a single with the track');
237   is ($single->tracks->count, 3, '3 tracks on single CD');
238   is ($single->tracks->find ({ position => 1})->title, 'Why does mst write this way', 'Correct 1st track title');
239   is ($single->tracks->find ({ position => 2})->title, 'Chainsaw celebration', 'Correct 2nd track title');
240   is ($single->tracks->find ({ position => 3})->title, 'Purl cleans up', 'Correct 3rd track title');
241
242   is ($single->cd_to_producer->count, 3, '3 producers created for the single cd');
243   is_deeply (
244     [ sort map { $_->producer->name } ($single->cd_to_producer->all) ],
245     ['castaway', 'mst', 'theorbtwo'],
246     'Producers named correctly',
247   );
248 };
249 diag $@ if $@;
250
251 # test might_have again but with a PK == FK in the middle (obviously not specified)
252 eval {
253   my $artist = $schema->resultset('Artist')->first;
254   my $cd = $schema->resultset('CD')->create ({
255     artist => $artist,
256     title => 'Music to code by at twilight',
257     year => 2008,
258     artwork => {
259       images => [
260         { name => 'recursive descent' },
261         { name => 'tail packing' },
262       ],
263     },
264   });
265
266   isa_ok ($cd, 'DBICTest::CD', 'Main CD object created');
267   is ($cd->title, 'Music to code by at twilight', 'Correct CD title');
268   isa_ok ($cd->artwork, 'DBICTest::Artwork', 'Artwork created');
269
270   # this test might look weird, but it failed at one point, keep it there
271   my $art_obj = $cd->artwork;
272   ok ($art_obj->has_column_loaded ('cd_id'), 'PK/FK present on artwork object');
273   is ($art_obj->images->count, 2, 'Correct artwork image count via the new object');
274   is_deeply (
275     [ sort $art_obj->images->get_column ('name')->all ],
276     [ 'recursive descent', 'tail packing' ],
277     'Images named correctly in objects',
278   );
279
280
281   my $artwork = $schema->resultset('Artwork')->search (
282     { 'cd.title' => 'Music to code by at twilight' },
283     { join => 'cd' },
284   )->single;
285
286   is ($artwork->images->count, 2, 'Correct artwork image count via a new search');
287
288   is_deeply (
289     [ sort $artwork->images->get_column ('name')->all ],
290     [ 'recursive descent', 'tail packing' ],
291     'Images named correctly after search',
292   );
293 };
294 diag $@ if $@;
295
296 # test might_have again but with just a PK and FK (neither specified) in the mid-table
297 eval {
298   my $cd = $schema->resultset('CD')->first;
299   my $track = $schema->resultset ('Track')->create ({
300     cd => $cd,
301     position => 66,
302     title => 'Black',
303     lyrics => {
304       lyric_versions => [
305         { text => 'The color black' },
306         { text => 'The colour black' },
307       ],
308     },
309   });
310
311   isa_ok ($track, 'DBICTest::Track', 'Main track object created');
312   is ($track->title, 'Black', 'Correct track title');
313   isa_ok ($track->lyrics, 'DBICTest::Lyrics', 'Lyrics created');
314
315   # this test might look weird, but it was failing at one point, keep it there
316   my $lyric_obj = $track->lyrics;
317   ok ($lyric_obj->has_column_loaded ('lyric_id'), 'PK present on lyric object');
318   ok ($lyric_obj->has_column_loaded ('track_id'), 'FK present on lyric object');
319   is ($lyric_obj->lyric_versions->count, 2, 'Correct lyric versions count via the new object');
320   is_deeply (
321     [ sort $lyric_obj->lyric_versions->get_column ('text')->all ],
322     [ 'The color black', 'The colour black' ],
323     'Lyrics text in objects matches',
324   );
325
326
327   my $lyric = $schema->resultset('Lyrics')->search (
328     { 'track.title' => 'Black' },
329     { join => 'track' },
330   )->single;
331
332   is ($lyric->lyric_versions->count, 2, 'Correct lyric versions count via a new search');
333
334   is_deeply (
335     [ sort $lyric->lyric_versions->get_column ('text')->all ],
336     [ 'The color black', 'The colour black' ],
337     'Lyrics text via search matches',
338   );
339 };
340 diag $@ if $@;
341
342 # nested find_or_create
343 eval {
344   my $newartist2 = $schema->resultset('Artist')->find_or_create({ 
345     name => 'Fred 3',
346     cds => [
347       { 
348         title => 'Noah Act',
349         year => 2007,
350       },
351     ],
352   });
353   is($newartist2->name, 'Fred 3', 'Created new artist with cds via find_or_create');
354 };
355 diag $@ if $@;
356
357 # multiple same level has_many create
358 eval {
359   my $artist2 = $schema->resultset('Artist')->create({
360     name => 'Fred 4',
361     cds => [
362       {
363         title => 'Music to code by',
364         year => 2007,
365       },
366     ],
367     cds_unordered => [
368       {
369         title => 'Music to code by',
370         year => 2007,
371       },
372     ]
373   });
374
375   is($artist2->in_storage, 1, 'artist with duplicate rels inserted okay');
376 };
377 diag $@ if $@;
378
379 # first create_related pass
380 eval {
381         my $artist = $schema->resultset('Artist')->first;
382         
383         my $cd_result = $artist->create_related('cds', {
384         
385                 title => 'TestOneCD1',
386                 year => 2007,
387                 tracks => [
388                 
389                         { position=>111,
390                           title => 'TrackOne',
391                         },
392                         { position=>112,
393                           title => 'TrackTwo',
394                         }
395                 ],
396
397         });
398         
399         ok( $cd_result && ref $cd_result eq 'DBICTest::CD', "Got Good CD Class");
400         ok( $cd_result->title eq "TestOneCD1", "Got Expected Title");
401         
402         my $tracks = $cd_result->tracks;
403         
404         ok( ref $tracks eq "DBIx::Class::ResultSet", "Got Expected Tracks ResultSet");
405         
406         foreach my $track ($tracks->all)
407         {
408                 ok( $track && ref $track eq 'DBICTest::Track', 'Got Expected Track Class');
409         }
410 };
411 diag $@ if $@;
412
413 # second create_related with same arguments
414 eval {
415         my $artist = $schema->resultset('Artist')->first;
416         
417         my $cd_result = $artist->create_related('cds', {
418         
419                 title => 'TestOneCD2',
420                 year => 2007,
421                 tracks => [
422                 
423                         { position=>111,
424                           title => 'TrackOne',
425                         },
426                         { position=>112,
427                           title => 'TrackTwo',
428                         }
429                 ],
430
431     liner_notes => { notes => 'I can haz liner notes?' },
432
433         });
434         
435         ok( $cd_result && ref $cd_result eq 'DBICTest::CD', "Got Good CD Class");
436         ok( $cd_result->title eq "TestOneCD2", "Got Expected Title");
437   ok( $cd_result->notes eq 'I can haz liner notes?', 'Liner notes');
438         
439         my $tracks = $cd_result->tracks;
440         
441         ok( ref $tracks eq "DBIx::Class::ResultSet", "Got Expected Tracks ResultSet");
442         
443         foreach my $track ($tracks->all)
444         {
445                 ok( $track && ref $track eq 'DBICTest::Track', 'Got Expected Track Class');
446         }
447 };
448 diag $@ if $@;
449
450 # create of parents of a record linker table
451 eval {
452   my $cdp = $schema->resultset('CD_to_Producer')->create({
453     cd => { artist => 1, title => 'foo', year => 2000 },
454     producer => { name => 'jorge' }
455   });
456   ok($cdp, 'join table record created ok');
457 };
458 diag $@ if $@;
459
460 #SPECIAL_CASE
461 eval {
462   my $kurt_cobain = { name => 'Kurt Cobain' };
463
464   my $in_utero = $schema->resultset('CD')->new({
465       title => 'In Utero',
466       year  => 1993
467     });
468
469   $kurt_cobain->{cds} = [ $in_utero ];
470
471
472   $schema->resultset('Artist')->populate([ $kurt_cobain ]); # %)
473   $a = $schema->resultset('Artist')->find({name => 'Kurt Cobain'});
474
475   is($a->name, 'Kurt Cobain', 'Artist insertion ok');
476   is($a->cds && $a->cds->first && $a->cds->first->title, 
477                   'In Utero', 'CD insertion ok');
478 };
479 diag $@ if $@;
480
481 #SPECIAL_CASE2
482 eval {
483   my $pink_floyd = { name => 'Pink Floyd' };
484
485   my $the_wall = { title => 'The Wall', year  => 1979 };
486
487   $pink_floyd->{cds} = [ $the_wall ];
488
489
490   $schema->resultset('Artist')->populate([ $pink_floyd ]); # %)
491   $a = $schema->resultset('Artist')->find({name => 'Pink Floyd'});
492
493   is($a->name, 'Pink Floyd', 'Artist insertion ok');
494   is($a->cds && $a->cds->first->title, 'The Wall', 'CD insertion ok');
495 };
496 diag $@ if $@;
497
498 ## Create foreign key col obj including PK
499 ## See test 20 in 66relationships.t
500 eval {
501   my $new_cd_hashref = { 
502     cdid => 27, 
503     title => 'Boogie Woogie', 
504     year => '2007', 
505     artist => { artistid => 17, name => 'king luke' }
506   };
507
508   my $cd = $schema->resultset("CD")->find(1);
509
510   is($cd->artist->id, 1, 'rel okay');
511
512   my $new_cd = $schema->resultset("CD")->create($new_cd_hashref);
513   is($new_cd->artist->id, 17, 'new id retained okay');
514 };
515 diag $@ if $@;
516
517 eval {
518         $schema->resultset("CD")->create({ 
519               cdid => 28, 
520               title => 'Boogie Wiggle', 
521               year => '2007', 
522               artist => { artistid => 18, name => 'larry' }
523              });
524 };
525 is($@, '', 'new cd created without clash on related artist');
526
527 # Make sure exceptions from errors in created rels propogate
528 eval {
529     my $t = $schema->resultset("Track")->new({ cd => { artist => undef } });
530     #$t->cd($t->new_related('cd', { artist => undef } ) );
531     #$t->{_rel_in_storage} = 0;
532     $t->insert;
533 };
534 like($@, qr/cd.artist may not be NULL/, "Exception propogated properly");
535
536 # Test multi create over many_to_many
537 eval {
538   $schema->resultset('CD')->create ({
539     artist => {
540       name => 'larry', # should already exist
541     },
542     title => 'Warble Marble',
543     year => '2009',
544     cd_to_producer => [
545       { producer => { name => 'Cowboy Neal' } },
546     ],
547   });
548
549   my $m2m_cd = $schema->resultset('CD')->search ({ title => 'Warble Marble'});
550   is ($m2m_cd->count, 1, 'One CD row created via M2M create');
551   is ($m2m_cd->first->producers->count, 1, 'CD row created with one producer');
552   is ($m2m_cd->first->producers->first->name, 'Cowboy Neal', 'Correct producer row created');
553 };
554
555 # and some insane multicreate 
556 # (should work, despite the fact that no one will probably use it this way)
557
558 # first count how many rows do we initially have
559 my $counts;
560 $counts->{$_} = $schema->resultset($_)->count for qw/Artist CD Genre Producer Tag/;
561
562 # do the crazy create
563 eval {
564   $schema->resultset('CD')->create ({
565     artist => {
566       name => 'james',
567     },
568     title => 'Greatest hits 1',
569     year => '2012',
570     genre => {
571       name => '"Greatest" collections',
572     },
573     tags => [
574       { tag => 'A' },
575       { tag => 'B' },
576     ],
577     cd_to_producer => [
578       {
579         producer => {
580           name => 'bob',
581           producer_to_cd => [
582             {
583               cd => { 
584                 artist => {
585                   name => 'lars',
586                   cds => [
587                     {
588                       title => 'Greatest hits 2',
589                       year => 2012,
590                       genre => {
591                         name => '"Greatest" collections',
592                       },
593                       tags => [
594                         { tag => 'A' },
595                         { tag => 'B' },
596                       ],
597                       # This cd is created via artist so it doesn't know about producers
598                       cd_to_producer => [
599                         # if we specify 'bob' here things bomb
600                         # as the producer attached to Greatest Hits 1 is
601                         # already created, but not yet inserted.
602                         # Maybe this can be fixed, but things are hairy
603                         # enough already.
604                         #
605                         #{ producer => { name => 'bob' } },
606                         { producer => { name => 'paul' } },
607                         { producer => {
608                           name => 'flemming',
609                           producer_to_cd => [
610                             { cd => {
611                               artist => {
612                                 name => 'kirk',
613                                 cds => [
614                                   {
615                                     title => 'Greatest hits 3',
616                                     year => 2012,
617                                     genre => {
618                                       name => '"Greatest" collections',
619                                     },
620                                     tags => [
621                                       { tag => 'A' },
622                                       { tag => 'B' },
623                                     ],
624                                   },
625                                   {
626                                     title => 'Greatest hits 4',
627                                     year => 2012,
628                                     genre => {
629                                       name => '"Greatest" collections2',
630                                     },
631                                     tags => [
632                                       { tag => 'A' },
633                                       { tag => 'B' },
634                                     ],
635                                   },
636                                 ],
637                               },
638                               title => 'Greatest hits 5',
639                               year => 2013,
640                               genre => {
641                                 name => '"Greatest" collections2',
642                               },
643                             }},
644                           ],
645                         }},
646                       ],
647                     },
648                   ],
649                 },
650                 title => 'Greatest hits 6',
651                 year => 2012,
652                 genre => {
653                   name => '"Greatest" collections',
654                 },
655                 tags => [
656                   { tag => 'A' },
657                   { tag => 'B' },
658                 ],
659               },
660             },
661             {
662               cd => { 
663                 artist => {
664                   name => 'lars',    # should already exist
665                   # even though the artist 'name' is not uniquely constrained
666                   # find_or_create will arguably DWIM 
667                 },
668                 title => 'Greatest hits 7',
669                 year => 2013,
670               },
671             },
672           ],
673         },
674       },
675     ],
676   });
677
678   is ($schema->resultset ('Artist')->count, $counts->{Artist} + 3, '3 new artists created');
679   is ($schema->resultset ('Genre')->count, $counts->{Genre} + 2, '2 additional genres created');
680   is ($schema->resultset ('Producer')->count, $counts->{Producer} + 3, '3 new producer');
681   is ($schema->resultset ('CD')->count, $counts->{CD} + 7, '7 new CDs');
682   is ($schema->resultset ('Tag')->count, $counts->{Tag} + 10, '10 new Tags');
683
684   my $cd_rs = $schema->resultset ('CD')
685     ->search ({ title => { -like => 'Greatest hits %' }}, { order_by => 'title'} );
686   is ($cd_rs->count, 7, '7 greatest hits created');
687
688   my $cds_2012 = $cd_rs->search ({ year => 2012});
689   is ($cds_2012->count, 5, '5 CDs created in 2012');
690
691   is (
692     $cds_2012->search(
693       { 'tags.tag' => { -in => [qw/A B/] } },
694       { join => 'tags', group_by => 'me.cdid' }
695     ),
696     5,
697     'All 10 tags were pairwise distributed between 5 year-2012 CDs'
698   );
699
700   my $paul_prod = $cd_rs->search (
701     { 'producer.name' => 'paul'},
702     { join => { cd_to_producer => 'producer' } }
703   );
704   is ($paul_prod->count, 1, 'Paul had 1 production');
705   my $pauls_cd = $paul_prod->single;
706   is ($pauls_cd->cd_to_producer->count, 2, 'Paul had one co-producer');
707   is (
708     $pauls_cd->search_related ('cd_to_producer',
709       { 'producer.name' => 'flemming'},
710       { join => 'producer' }
711     )->count,
712     1,
713     'The second producer is flemming',
714   );
715
716   my $kirk_cds = $cd_rs->search ({ 'artist.name' => 'kirk' }, { join => 'artist' });
717   is ($kirk_cds, 3, 'Kirk had 3 CDs');
718   is (
719     $kirk_cds->search (
720       { 'cd_to_producer.cd' => { '!=', undef } },
721       { join => 'cd_to_producer' },
722     ),
723     1,
724     'Kirk had a producer only on one cd',
725   );
726
727   my $lars_cds = $cd_rs->search ({ 'artist.name' => 'lars' }, { join => 'artist' });
728   is ($lars_cds->count, 3, 'Lars had 3 CDs');
729   is (
730     $lars_cds->search (
731       { 'cd_to_producer.cd' => undef },
732       { join => 'cd_to_producer' },
733     ),
734     0,
735     'Lars always had a producer',
736   );
737   is (
738     $lars_cds->search_related ('cd_to_producer',
739       { 'producer.name' => 'flemming'},
740       { join => 'producer' }
741     )->count,
742     1,
743     'Lars produced 1 CD with flemming',
744   );
745   is (
746     $lars_cds->search_related ('cd_to_producer',
747       { 'producer.name' => 'bob'},
748       { join => 'producer' }
749     )->count,
750     2,
751     'Lars produced 2 CDs with bob',
752   );
753
754   my $bob_prod = $cd_rs->search (
755     { 'producer.name' => 'bob'},
756     { join => { cd_to_producer => 'producer' } }
757   );
758   is ($bob_prod->count, 3, 'Bob produced a total of 3 CDs');
759
760   is (
761     $bob_prod->search ({ 'artist.name' => 'james' }, { join => 'artist' })->count,
762     1,
763     "Bob produced james' only CD",
764   );
765 };
766 diag $@ if $@;
767
768 1;