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