X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2F100populate.t;h=57efc7232de648167d252099164e1e95da70ae01;hb=0a768c9067712d4f9512748c315c617367fe8dc4;hp=f2a39367a6de11115da829aefb9bb00c5cd67fbd;hpb=eed5492fecb339252aaad11adb22651e5bd06d7b;p=dbsrgits%2FDBIx-Class.git diff --git a/t/100populate.t b/t/100populate.t index f2a3936..57efc72 100644 --- a/t/100populate.t +++ b/t/100populate.t @@ -6,6 +6,7 @@ use Test::Exception; use Test::Warn; use lib qw(t/lib); use DBICTest; +use DBIx::Class::_Util 'sigwarn_silencer'; use Path::Class::File (); use Math::BigInt; use List::Util qw/shuffle/; @@ -87,6 +88,15 @@ is($link4->id, 4, 'Link 4 id'); is($link4->url, undef, 'Link 4 url'); is($link4->title, 'dtitle', 'Link 4 title'); +## variable size dataset +@links = $schema->populate('Link', [ +[ qw/id title url/ ], +[ 41 ], +[ 42, undef, 'url42' ], +]); +is(scalar @links, 2); +is($links[0]->url, undef); +is($links[1]->url, 'url42'); ## make sure populate -> insert_bulk honors fields/orders in void context ## schema order @@ -119,6 +129,63 @@ is($link7->id, 7, 'Link 7 id'); is($link7->url, undef, 'Link 7 url'); is($link7->title, 'gtitle', 'Link 7 title'); +## variable size dataset in void ctx +$schema->populate('Link', [ +[ qw/id title url/ ], +[ 71 ], +[ 72, undef, 'url72' ], +]); +@links = $schema->resultset('Link')->search({ id => [71, 72]}, { order_by => 'id' })->all; +is(scalar @links, 2); +is($links[0]->url, undef); +is($links[1]->url, 'url72'); + +## variable size dataset in void ctx, hash version +$schema->populate('Link', [ + { id => 73 }, + { id => 74, title => 't74' }, + { id => 75, url => 'u75' }, +]); +@links = $schema->resultset('Link')->search({ id => [73..75]}, { order_by => 'id' })->all; +is(scalar @links, 3); +is($links[0]->url, undef); +is($links[0]->title, undef); +is($links[1]->url, undef); +is($links[1]->title, 't74'); +is($links[2]->url, 'u75'); +is($links[2]->title, undef); + +## Make sure the void ctx trace is sane +{ + for ( + [ + [ qw/id title url/ ], + [ 81 ], + [ 82, 't82' ], + [ 83, undef, 'url83' ], + ], + [ + { id => 91 }, + { id => 92, title => 't92' }, + { id => 93, url => 'url93' }, + ] + ) { + $schema->is_executed_sql_bind( + sub { + $schema->populate('Link', $_); + }, + [ + [ 'BEGIN' ], + [ + 'INSERT INTO link( id, title, url ) VALUES( ?, ?, ? )', + "__BULK_INSERT__" + ], + [ 'COMMIT' ], + ] + ); + } +} + # populate with literals { my $rs = $schema->resultset('Link'); @@ -195,7 +262,7 @@ is($link7->title, 'gtitle', 'Link 7 title'); # test mixed binds with literal sql/bind $rs->populate([ map { +{ - url => \[ '? || ?', [ {} => 'cpan.org_' ], [ undef, $_ ] ], + url => \[ '? || ?', [ {} => 'cpan.org_' ], $_ ], title => "The 'best of' cpan", } } (1 .. 5) ]); @@ -209,6 +276,11 @@ is($link7->title, 'gtitle', 'Link 7 title'); my $rs = $schema->resultset('Artist'); $rs->delete; throws_ok { + # this warning is correct, but we are not testing it here + # what we are after is the correct exception when an int + # fails to coerce into a sqlite rownum + local $SIG{__WARN__} = sigwarn_silencer( qr/datatype mismatch.+ foo as integer/ ); + $rs->populate([ { artistid => 1, @@ -223,7 +295,7 @@ throws_ok { name => 'foo3', }, ]); -} qr/\Qexecute_for_fetch() aborted with 'datatype mismatch\E\b/, 'bad slice'; +} qr/\Qexecute_for_fetch() aborted with 'datatype mismatch\E\b/, 'bad slice fails PK insert'; is($rs->count, 0, 'populate is atomic'); @@ -323,79 +395,108 @@ warnings_like { my $rank = Math::BigInt->new(42); my $args = { - 'stringifying objects after regular values' => [ map - { { name => $_, rank => $rank } } - ( + 'stringifying objects after regular values' => { AoA => [ + [qw( name rank )], + ( map { [ $_, $rank ] } ( 'supplied before stringifying objects', 'supplied before stringifying objects 2', $fn, $fn2, - ) - ], - 'stringifying objects before regular values' => [ map - { { name => $_, rank => $rank } } - ( + )), + ]}, + + 'stringifying objects before regular values' => { AoA => [ + [qw( rank name )], + ( map { [ $rank, $_ ] } ( $fn, $fn2, 'supplied after stringifying objects', 'supplied after stringifying objects 2', - ) - ], - 'stringifying objects between regular values' => [ map - { { name => $_, rank => $rank } } - ( + )), + ]}, + + 'stringifying objects between regular values' => { AoA => [ + [qw( name rank )], + ( map { [ $_, $rank ] } ( 'supplied before stringifying objects', $fn, $fn2, 'supplied after stringifying objects', - ) - ], - 'stringifying objects around regular values' => [ map - { { name => $_, rank => $rank } } - ( + )) + ]}, + + 'stringifying objects around regular values' => { AoA => [ + [qw( rank name )], + ( map { [ $rank, $_ ] } ( $fn, 'supplied between stringifying objects', $fn2, - ) - ], + )) + ]}, + + 'single stringifying object' => { AoA => [ + [qw( rank name )], + [ $rank, $fn ], + ]}, }; - local $Storable::canonical = 1; - my $preimage = nfreeze([$fn, $fn2, $rank, $args]); + # generate the AoH equivalent based on the AoAs above + for my $bag (values %$args) { + my @hdr = @{$bag->{AoA}[0]}; + for my $v ( @{$bag->{AoA}}[1..$#{$bag->{AoA}}] ) { + push @{$bag->{AoH}}, my $h = {}; + @{$h}{@hdr} = @$v; + } + } - for my $tst (keys %$args) { + local $Storable::canonical = 1; + my $preimage = nfreeze($args); - # test void ctx - $rs->delete; - $rs->populate($args->{$tst}); - is_deeply( - $rs->all_hri, - $args->{$tst}, - "Populate() $tst in void context" - ); - # test non-void ctx - $rs->delete; - my $dummy = $rs->populate($args->{$tst}); - is_deeply( - $rs->all_hri, - $args->{$tst}, - "Populate() $tst in non-void context" - ); + for my $tst (keys %$args) { + for my $type (qw(AoA AoH)) { + + # test void ctx + $rs->delete; + $rs->populate($args->{$tst}{$type}); + is_deeply( + $rs->all_hri, + $args->{$tst}{AoH}, + "Populate() $tst in void context" + ); + + # test scalar ctx + $rs->delete; + my $dummy = $rs->populate($args->{$tst}{$type}); + is_deeply( + $rs->all_hri, + $args->{$tst}{AoH}, + "Populate() $tst in non-void context" + ); + + # test list ctx + $rs->delete; + my @dummy = $rs->populate($args->{$tst}{$type}); + is_deeply( + $rs->all_hri, + $args->{$tst}{AoH}, + "Populate() $tst in non-void context" + ); + } # test create() as we have everything set up already $rs->delete; - $rs->create($_) for @{$args->{$tst}}; + $rs->create($_) for @{$args->{$tst}{AoH}}; is_deeply( $rs->all_hri, - $args->{$tst}, + $args->{$tst}{AoH}, "Create() $tst" ); } ok ( - ($preimage eq nfreeze( [$fn, $fn2, $rank, $args] )), + ($preimage eq nfreeze($args)), 'Arguments fed to populate()/create() unchanged' ); @@ -410,10 +511,11 @@ warnings_like { ) ? () # one unique for populate() and create() each - : (qr/\QPOSSIBLE *PAST* DATA CORRUPTION detected \E.+\QTrigger condition encountered at @{[ __FILE__ ]} line\E \d/) x 2 + : (qr/\QPOSSIBLE *PAST* DATA CORRUPTION detected \E.+\QTrigger condition encountered at @{[ __FILE__ ]} line\E \d/) x 4 ], 'Data integrity warnings as planned'; -lives_ok { +$schema->is_executed_sql_bind( + sub { $schema->resultset('TwoKeys')->populate([{ artist => 1, cd => 5, @@ -431,7 +533,26 @@ lives_ok { autopilot => 'b', }] }]) -} 'multicol-PK has_many populate works'; + }, + [ + [ 'BEGIN' ], + [ 'INSERT INTO twokeys ( artist, cd) + VALUES ( ?, ? )', + '__BULK_INSERT__' + ], + [ 'INSERT INTO fourkeys_to_twokeys ( autopilot, f_bar, f_foo, f_goodbye, f_hello, t_artist, t_cd) + VALUES ( + ?, ?, ?, ?, ?, + ( SELECT me.artist FROM twokeys me WHERE artist = ? AND cd = ? ), + ( SELECT me.cd FROM twokeys me WHERE artist = ? AND cd = ? ) + ) + ', + '__BULK_INSERT__' + ], + [ 'COMMIT' ], + ], + 'multicol-PK has_many populate expected trace' +); lives_ok ( sub { $schema->populate('CD', [