might_have test for castaway to break
[dbsrgits/DBIx-Class.git] / t / 96multi_create.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use lib qw(t/lib);
6 use DBICTest;
7
8 plan tests => 70;
9
10 my $schema = DBICTest->init_schema();
11
12 # simple create + parent (the stuff $rs belongs_to)
13 eval {
14   my $cd = $schema->resultset('CD')->create({
15     artist => { 
16       name => 'Fred Bloggs' 
17     },
18     title => 'Some CD',
19     year => 1996
20   });
21
22   isa_ok($cd, 'DBICTest::CD', 'Created CD object');
23   isa_ok($cd->artist, 'DBICTest::Artist', 'Created related Artist');
24   is($cd->artist->name, 'Fred Bloggs', 'Artist created correctly');
25 };
26 diag $@ if $@;
27
28 # same as above but the child and parent have no values, 
29 # except for an explicit parent pk
30 eval {
31   my $bm_rs = $schema->resultset('Bookmark');
32   my $bookmark = $bm_rs->create({
33     link => {
34       id => 66,
35     },
36   });
37
38   isa_ok($bookmark, 'DBICTest::Bookmark', 'Created Bookrmark object');
39   isa_ok($bookmark->link, 'DBICTest::Link', 'Created related Link');
40   is (
41     $bm_rs->search (
42       { 'link.title' => $bookmark->link->title },
43       { join => 'link' },
44     )->count,
45     1,
46     'Bookmark and link made it to the DB',
47   );
48 };
49 diag $@ if $@;
50
51 # create over > 1 levels of has_many create (A => { has_many => { B => has_many => C } } )
52 eval {
53   my $artist = $schema->resultset('Artist')->create(
54     { name => 'Fred 2',
55       cds => [
56         { title => 'Music to code by',
57           year => 2007,
58           tags => [
59             { 'tag' => 'rock' },
60           ],
61         },
62       ],
63     }
64   );
65
66   isa_ok($artist, 'DBICTest::Artist', 'Created Artist');
67   is($artist->name, 'Fred 2', 'Artist created correctly');
68   is($artist->cds->count, 1, 'One CD created for artist');
69   is($artist->cds->first->title, 'Music to code by', 'CD created correctly');
70   is($artist->cds->first->tags->count, 1, 'One tag created for CD');
71   is($artist->cds->first->tags->first->tag, 'rock', 'Tag created correctly');
72
73   # Create via update - add a new CD
74   $artist->update({
75     cds => [ $artist->cds,
76       { title => 'Yet another CD',
77         year => 2006,
78       },
79     ],
80   });
81   is(($artist->cds->search({}, { order_by => 'year' }))[0]->title, 'Yet another CD', 'Updated and added another CD');
82
83   my $newartist = $schema->resultset('Artist')->find_or_create({ name => 'Fred 2'});
84
85   is($newartist->name, 'Fred 2', 'Retrieved the artist');
86 };
87 diag $@ if $@;
88
89 # create over > 1 levels of might_have (A => { might_have => { B => has_many => C } } )
90 eval {
91   my $artist = $schema->resultset('Artist')->first;
92   my $cd = $schema->resultset('CD')->create ({
93     artist => $artist,
94     title => 'Music to code by at night',
95     year => 2008,
96     tracks => [
97       {
98         position => 1,
99         title => 'Off by one again',
100       },
101       {
102         position => 2,
103         title => 'The dereferencer',
104         cd_single => {
105           artist => $artist,
106           year => 2008,
107           title => 'Was that a null (Single)',
108           tracks => [
109             { title => 'The dereferencer', position => 1 },
110             { title => 'The dereferencer II', position => 2 },
111           ],
112           cd_to_producer => [
113             {
114               producer => {
115                 name => 'K&R',
116               }
117             }
118           ]
119         },
120       },
121     ],
122   });
123
124   isa_ok ($cd, 'DBICTest::CD', 'Main CD object created');
125   is ($cd->title, 'Music to code by at night', 'Correct CD title');
126   is ($cd->tracks->count, 2, 'Two tracks on main CD');
127
128   my ($t1, $t2) = $cd->tracks->all;
129   is ($t1->title, 'Off by one again', 'Correct 1st track name');
130   is ($t1->cd_single, undef, 'No single for 1st track');
131   is ($t2->title, 'The dereferencer', 'Correct 2nd track name');
132   isa_ok ($t2->cd_single, 'DBICTest::CD', 'Created a single for 2nd track');
133
134   my $single = $t2->cd_single;
135   is ($single->tracks->count, 2, 'Two tracks on single CD');
136   is ($single->tracks->find ({ position => 1})->title, 'The dereferencer', 'Correct 1st track title');
137   is ($single->tracks->find ({ position => 2})->title, 'The dereferencer II', 'Correct 2nd track title');
138
139   is ($single->cd_to_producer->count, 1, 'One producer created with the single cd');
140   is ($single->cd_to_producer->first->producer->name, 'K&R', 'Producer name correct');
141 };
142 diag $@ if $@;
143
144 # nested find_or_create
145 eval {
146   my $newartist2 = $schema->resultset('Artist')->find_or_create({ 
147     name => 'Fred 3',
148     cds => [
149       { 
150         title => 'Noah Act',
151         year => 2007,
152       },
153     ],
154   });
155   is($newartist2->name, 'Fred 3', 'Created new artist with cds via find_or_create');
156 };
157 diag $@ if $@;
158
159 # multiple same level has_many create
160 eval {
161   my $artist2 = $schema->resultset('Artist')->create({
162     name => 'Fred 4',
163     cds => [
164       {
165         title => 'Music to code by',
166         year => 2007,
167       },
168     ],
169     cds_unordered => [
170       {
171         title => 'Music to code by',
172         year => 2007,
173       },
174     ]
175   });
176
177   is($artist2->in_storage, 1, 'artist with duplicate rels inserted okay');
178 };
179 diag $@ if $@;
180
181 # first create_related pass
182 eval {
183         my $artist = $schema->resultset('Artist')->first;
184         
185         my $cd_result = $artist->create_related('cds', {
186         
187                 title => 'TestOneCD1',
188                 year => 2007,
189                 tracks => [
190                 
191                         { position=>111,
192                           title => 'TrackOne',
193                         },
194                         { position=>112,
195                           title => 'TrackTwo',
196                         }
197                 ],
198
199         });
200         
201         ok( $cd_result && ref $cd_result eq 'DBICTest::CD', "Got Good CD Class");
202         ok( $cd_result->title eq "TestOneCD1", "Got Expected Title");
203         
204         my $tracks = $cd_result->tracks;
205         
206         ok( ref $tracks eq "DBIx::Class::ResultSet", "Got Expected Tracks ResultSet");
207         
208         foreach my $track ($tracks->all)
209         {
210                 ok( $track && ref $track eq 'DBICTest::Track', 'Got Expected Track Class');
211         }
212 };
213 diag $@ if $@;
214
215 # second create_related with same arguments
216 eval {
217         my $artist = $schema->resultset('Artist')->first;
218         
219         my $cd_result = $artist->create_related('cds', {
220         
221                 title => 'TestOneCD2',
222                 year => 2007,
223                 tracks => [
224                 
225                         { position=>111,
226                           title => 'TrackOne',
227                         },
228                         { position=>112,
229                           title => 'TrackTwo',
230                         }
231                 ],
232
233     liner_notes => { notes => 'I can haz liner notes?' },
234
235         });
236         
237         ok( $cd_result && ref $cd_result eq 'DBICTest::CD', "Got Good CD Class");
238         ok( $cd_result->title eq "TestOneCD2", "Got Expected Title");
239   ok( $cd_result->notes eq 'I can haz liner notes?', 'Liner notes');
240         
241         my $tracks = $cd_result->tracks;
242         
243         ok( ref $tracks eq "DBIx::Class::ResultSet", "Got Expected Tracks ResultSet");
244         
245         foreach my $track ($tracks->all)
246         {
247                 ok( $track && ref $track eq 'DBICTest::Track', 'Got Expected Track Class');
248         }
249 };
250 diag $@ if $@;
251
252 # create of parents of a record linker table
253 eval {
254   my $cdp = $schema->resultset('CD_to_Producer')->create({
255     cd => { artist => 1, title => 'foo', year => 2000 },
256     producer => { name => 'jorge' }
257   });
258   ok($cdp, 'join table record created ok');
259 };
260 diag $@ if $@;
261
262 #SPECIAL_CASE
263 eval {
264   my $kurt_cobain = { name => 'Kurt Cobain' };
265
266   my $in_utero = $schema->resultset('CD')->new({
267       title => 'In Utero',
268       year  => 1993
269     });
270
271   $kurt_cobain->{cds} = [ $in_utero ];
272
273
274   $schema->resultset('Artist')->populate([ $kurt_cobain ]); # %)
275   $a = $schema->resultset('Artist')->find({name => 'Kurt Cobain'});
276
277   is($a->name, 'Kurt Cobain', 'Artist insertion ok');
278   is($a->cds && $a->cds->first && $a->cds->first->title, 
279                   'In Utero', 'CD insertion ok');
280 };
281 diag $@ if $@;
282
283 #SPECIAL_CASE2
284 eval {
285   my $pink_floyd = { name => 'Pink Floyd' };
286
287   my $the_wall = { title => 'The Wall', year  => 1979 };
288
289   $pink_floyd->{cds} = [ $the_wall ];
290
291
292   $schema->resultset('Artist')->populate([ $pink_floyd ]); # %)
293   $a = $schema->resultset('Artist')->find({name => 'Pink Floyd'});
294
295   is($a->name, 'Pink Floyd', 'Artist insertion ok');
296   is($a->cds && $a->cds->first->title, 'The Wall', 'CD insertion ok');
297 };
298 diag $@ if $@;
299
300 ## Create foreign key col obj including PK
301 ## See test 20 in 66relationships.t
302 eval {
303   my $new_cd_hashref = { 
304     cdid => 27, 
305     title => 'Boogie Woogie', 
306     year => '2007', 
307     artist => { artistid => 17, name => 'king luke' }
308   };
309
310   my $cd = $schema->resultset("CD")->find(1);
311
312   is($cd->artist->id, 1, 'rel okay');
313
314   my $new_cd = $schema->resultset("CD")->create($new_cd_hashref);
315   is($new_cd->artist->id, 17, 'new id retained okay');
316 };
317 diag $@ if $@;
318
319 eval {
320         $schema->resultset("CD")->create({ 
321               cdid => 28, 
322               title => 'Boogie Wiggle', 
323               year => '2007', 
324               artist => { artistid => 18, name => 'larry' }
325              });
326 };
327 is($@, '', 'new cd created without clash on related artist');
328
329 # Make sure exceptions from errors in created rels propogate
330 eval {
331     my $t = $schema->resultset("Track")->new({ cd => { artist => undef } });
332     #$t->cd($t->new_related('cd', { artist => undef } ) );
333     #$t->{_rel_in_storage} = 0;
334     $t->insert;
335 };
336 like($@, qr/cd.artist may not be NULL/, "Exception propogated properly");
337
338 # Test multi create over many_to_many
339 eval {
340   $schema->resultset('CD')->create ({
341     artist => {
342       name => 'larry', # should already exist
343     },
344     title => 'Warble Marble',
345     year => '2009',
346     cd_to_producer => [
347       { producer => { name => 'Cowboy Neal' } },
348     ],
349   });
350
351   my $m2m_cd = $schema->resultset('CD')->search ({ title => 'Warble Marble'});
352   is ($m2m_cd->count, 1, 'One CD row created via M2M create');
353   is ($m2m_cd->first->producers->count, 1, 'CD row created with one producer');
354   is ($m2m_cd->first->producers->first->name, 'Cowboy Neal', 'Correct producer row created');
355 };
356
357 # and some insane multicreate 
358 # (should work, despite the fact that no one will probably use it this way)
359
360 # first count how many rows do we initially have
361 my $counts;
362 $counts->{$_} = $schema->resultset($_)->count for qw/Artist CD Genre Producer Tag/;
363
364 # do the crazy create
365 eval {
366   $schema->resultset('CD')->create ({
367     artist => {
368       name => 'james',
369     },
370     title => 'Greatest hits 1',
371     year => '2012',
372     genre => {
373       name => '"Greatest" collections',
374     },
375     tags => [
376       { tag => 'A' },
377       { tag => 'B' },
378     ],
379     cd_to_producer => [
380       {
381         producer => {
382           name => 'bob',
383           producer_to_cd => [
384             {
385               cd => { 
386                 artist => {
387                   name => 'lars',
388                   cds => [
389                     {
390                       title => 'Greatest hits 2',
391                       year => 2012,
392                       genre => {
393                         name => '"Greatest" collections',
394                       },
395                       tags => [
396                         { tag => 'A' },
397                         { tag => 'B' },
398                       ],
399                       # This cd is created via artist so it doesn't know about producers
400                       cd_to_producer => [
401                         # if we specify 'bob' here things bomb
402                         # as the producer attached to Greatest Hits 1 is
403                         # already created, but not yet inserted.
404                         # Maybe this can be fixed, but things are hairy
405                         # enough already.
406                         #
407                         #{ producer => { name => 'bob' } },
408                         { producer => { name => 'paul' } },
409                         { producer => {
410                           name => 'flemming',
411                           producer_to_cd => [
412                             { cd => {
413                               artist => {
414                                 name => 'kirk',
415                                 cds => [
416                                   {
417                                     title => 'Greatest hits 3',
418                                     year => 2012,
419                                     genre => {
420                                       name => '"Greatest" collections',
421                                     },
422                                     tags => [
423                                       { tag => 'A' },
424                                       { tag => 'B' },
425                                     ],
426                                   },
427                                   {
428                                     title => 'Greatest hits 4',
429                                     year => 2012,
430                                     genre => {
431                                       name => '"Greatest" collections2',
432                                     },
433                                     tags => [
434                                       { tag => 'A' },
435                                       { tag => 'B' },
436                                     ],
437                                   },
438                                 ],
439                               },
440                               title => 'Greatest hits 5',
441                               year => 2013,
442                               genre => {
443                                 name => '"Greatest" collections2',
444                               },
445                             }},
446                           ],
447                         }},
448                       ],
449                     },
450                   ],
451                 },
452                 title => 'Greatest hits 6',
453                 year => 2012,
454                 genre => {
455                   name => '"Greatest" collections',
456                 },
457                 tags => [
458                   { tag => 'A' },
459                   { tag => 'B' },
460                 ],
461               },
462             },
463             {
464               cd => { 
465                 artist => {
466                   name => 'lars',    # should already exist
467                   # even though the artist 'name' is not uniquely constrained
468                   # find_or_create will arguably DWIM 
469                 },
470                 title => 'Greatest hits 7',
471                 year => 2013,
472               },
473             },
474           ],
475         },
476       },
477     ],
478   });
479
480   is ($schema->resultset ('Artist')->count, $counts->{Artist} + 3, '3 new artists created');
481   is ($schema->resultset ('Genre')->count, $counts->{Genre} + 2, '2 additional genres created');
482   is ($schema->resultset ('Producer')->count, $counts->{Producer} + 3, '3 new producer');
483   is ($schema->resultset ('CD')->count, $counts->{CD} + 7, '7 new CDs');
484   is ($schema->resultset ('Tag')->count, $counts->{Tag} + 10, '10 new Tags');
485
486   my $cd_rs = $schema->resultset ('CD')
487     ->search ({ title => { -like => 'Greatest hits %' }}, { order_by => 'title'} );
488   is ($cd_rs->count, 7, '7 greatest hits created');
489
490   my $cds_2012 = $cd_rs->search ({ year => 2012});
491   is ($cds_2012->count, 5, '5 CDs created in 2012');
492
493   is (
494     $cds_2012->search(
495       { 'tags.tag' => { -in => [qw/A B/] } },
496       { join => 'tags', group_by => 'me.cdid' }
497     ),
498     5,
499     'All 10 tags were pairwise distributed between 5 year-2012 CDs'
500   );
501
502   my $paul_prod = $cd_rs->search (
503     { 'producer.name' => 'paul'},
504     { join => { cd_to_producer => 'producer' } }
505   );
506   is ($paul_prod->count, 1, 'Paul had 1 production');
507   my $pauls_cd = $paul_prod->single;
508   is ($pauls_cd->cd_to_producer->count, 2, 'Paul had one co-producer');
509   is (
510     $pauls_cd->search_related ('cd_to_producer',
511       { 'producer.name' => 'flemming'},
512       { join => 'producer' }
513     )->count,
514     1,
515     'The second producer is flemming',
516   );
517
518   my $kirk_cds = $cd_rs->search ({ 'artist.name' => 'kirk' }, { join => 'artist' });
519   is ($kirk_cds, 3, 'Kirk had 3 CDs');
520   is (
521     $kirk_cds->search (
522       { 'cd_to_producer.cd' => { '!=', undef } },
523       { join => 'cd_to_producer' },
524     ),
525     1,
526     'Kirk had a producer only on one cd',
527   );
528
529   my $lars_cds = $cd_rs->search ({ 'artist.name' => 'lars' }, { join => 'artist' });
530   is ($lars_cds->count, 3, 'Lars had 3 CDs');
531   is (
532     $lars_cds->search (
533       { 'cd_to_producer.cd' => undef },
534       { join => 'cd_to_producer' },
535     ),
536     0,
537     'Lars always had a producer',
538   );
539   is (
540     $lars_cds->search_related ('cd_to_producer',
541       { 'producer.name' => 'flemming'},
542       { join => 'producer' }
543     )->count,
544     1,
545     'Lars produced 1 CD with flemming',
546   );
547   is (
548     $lars_cds->search_related ('cd_to_producer',
549       { 'producer.name' => 'bob'},
550       { join => 'producer' }
551     )->count,
552     2,
553     'Lars produced 2 CDs with bob',
554   );
555
556   my $bob_prod = $cd_rs->search (
557     { 'producer.name' => 'bob'},
558     { join => { cd_to_producer => 'producer' } }
559   );
560   is ($bob_prod->count, 3, 'Bob produced a total of 3 CDs');
561
562   is (
563     $bob_prod->search ({ 'artist.name' => 'james' }, { join => 'artist' })->count,
564     1,
565     "Bob produced james' only CD",
566   );
567 };
568 diag $@ if $@;