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