diff options
author | Jason Cooper <J.L.Cooper@lboro.ac.uk> | 2020-09-17 15:30:10 +0100 |
---|---|---|
committer | Jason Cooper <J.L.Cooper@lboro.ac.uk> | 2020-09-17 15:30:10 +0100 |
commit | 17d40d073057917794629b8cea934c1ea9198bb0 (patch) | |
tree | 5dbf00b20a2deadd779c1724fc740ccb4069ca03 | |
parent | ea3e7426d986f7d43206e8c2989e74910b444783 (diff) |
Added support to result set callbacks to specify the `last_insert_id`
-rw-r--r-- | Changes | 1 | ||||
-rw-r--r-- | README.md | 23 | ||||
-rw-r--r-- | lib/DBD/Mock.pm | 24 | ||||
-rw-r--r-- | lib/DBD/Mock/StatementTrack.pm | 4 | ||||
-rw-r--r-- | lib/DBD/Mock/st.pm | 5 | ||||
-rw-r--r-- | t/016_mock_add_resultset_test.t | 51 |
6 files changed, 107 insertions, 1 deletions
@@ -2,6 +2,7 @@ Revision history for Perl extension DBD::Mock. {{$NEXT}} - The DBD::st module now supports the last_insert_id method + - Result sets with callbacks can now specify a last_insert_id 1.55 2019-12-30T14:20:00Z - Fixed bug rt131264 t/033_table_info.t fails (with older DBI) @@ -1202,6 +1202,29 @@ great caution (if at all). property to be undef in this situation then set the `$DBD::Mock::DefaultFieldsToUndef` flag to `1`. + If you're mocking an INSERT statement with a callback and you want to + explicitly set the database's `last_insert_id` value then you can use the + `last_insert_id` key in the result set. If you don't specify a + `last_insert_id` then the standard `DBD::Mock` logic for generating an value + for the last inserted item will be followed. This will allow you to mock + MySQL/MariaDB INSERT queries that use `ON DUPLICATE KEY UPDATE` logic to set + the `last_insert_id`. + + $dbh->{mock_add_resultset} = { + sql => 'INSERT INTO y ( x ) VALUES ( ? ) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID( id )', + callback => sub { + my @bound_params = @_; + + my %result = ( + fields => [], + rows => [], + last_insert_id => 99, + ); + + return %result; + }, + }; + # BUGS - Odd `$dbh` attribute behavior diff --git a/lib/DBD/Mock.pm b/lib/DBD/Mock.pm index 3402c1e..91ae8f4 100644 --- a/lib/DBD/Mock.pm +++ b/lib/DBD/Mock.pm @@ -1398,6 +1398,30 @@ stays compatible with previous versions. If you need the C<NUM_OF_FIELDS> property to be undef in this situation then set the C<$DBD::Mock::DefaultFieldsToUndef> flag to C<1>. +If you're mocking an INSERT statement with a callback and you want to +explicitly set the database's C<last_insert_id> value then you can use the +C<last_insert_id> key in the result set. If you don't specify a +C<last_insert_id> then the standard C<DBD::Mock> logic for generating an value +for the last inserted item will be followed. This will allow you to mock +MySQL/MariaDB INSERT queries that use C<ON DUPLICATE KEY UPDATE> logic to set +the C<last_insert_id>. + + + $dbh->{mock_add_resultset} = { + sql => 'INSERT INTO y ( x ) VALUES ( ? ) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID( id )', + callback => sub { + my @bound_params = @_; + + my %result = ( + fields => [], + rows => [], + last_insert_id => 99, + ); + + return %result; + }, + }; + =back diff --git a/lib/DBD/Mock/StatementTrack.pm b/lib/DBD/Mock/StatementTrack.pm index 31dedda..60fae31 100644 --- a/lib/DBD/Mock/StatementTrack.pm +++ b/lib/DBD/Mock/StatementTrack.pm @@ -141,6 +141,10 @@ sub mark_executed { if (ref $recordSet{rows} eq "ARRAY") { $self->{return_data} = $recordSet{rows}; } + + if (defined $recordSet{last_insert_id}) { + $self->{last_insert_id} = $recordSet{last_insert_id}; + } } } diff --git a/lib/DBD/Mock/st.pm b/lib/DBD/Mock/st.pm index bb2b20a..44229d3 100644 --- a/lib/DBD/Mock/st.pm +++ b/lib/DBD/Mock/st.pm @@ -131,7 +131,10 @@ sub execute { #use Data::Dumper;warn Dumper $dbh->{mock_last_insert_ids}; if ( $dbh->{Statement} =~ /^\s*?insert(?:\s+ignore)?\s+into\s+(\S+)/i ) { - if ( $dbh->{mock_last_insert_ids} + if ( $tracker->{last_insert_id} ) { + $dbh->{mock_last_insert_id} = $tracker->{last_insert_id}; + + } elsif ( $dbh->{mock_last_insert_ids} && exists $dbh->{mock_last_insert_ids}{$1} ) { $dbh->{mock_last_insert_id} = $dbh->{mock_last_insert_ids}{$1}++; diff --git a/t/016_mock_add_resultset_test.t b/t/016_mock_add_resultset_test.t index 6743a82..9ddf98a 100644 --- a/t/016_mock_add_resultset_test.t +++ b/t/016_mock_add_resultset_test.t @@ -317,4 +317,55 @@ $dbh->{mock_add_resultset} = { $sth->finish(); } +$dbh->{mock_start_insert_id} = [ 'y', 4 ]; + +$dbh->{mock_add_resultset} = { + sql => 'INSERT INTO y ( x ) VALUES ( ? )', + callback => sub { + my @bound_params = @_; + + my %result = ( + fields => [], + rows => [] + ); + + return %result; + }, +}; + +{ + my $sth = $dbh->prepare( 'INSERT INTO y ( x ) VALUES ( ? )' ); + + $sth->execute( 'test' ); + + is( $dbh->last_insert_id(), 4, "last_insert_id should return the next Id value after an insert as our callback doesn't override it") +} + + +$dbh->{mock_add_resultset} = { + sql => 'INSERT INTO y ( x ) VALUES ( ? )', + callback => sub { + my @bound_params = @_; + + my %result = ( + fields => [], + rows => [], + last_insert_id => 99, + ); + + return %result; + }, +}; + +{ + my $sth = $dbh->prepare( 'INSERT INTO y ( x ) VALUES ( ? )' ); + + $sth->execute( 'test' ); + + is( $dbh->last_insert_id(), 99, "last_insert_id should return the id the callback has provided"); + + is( $dbh->{mock_last_insert_ids}{y}, 5, "If we provide a last_insert_id value then the one stored against the table shouldn't be updated"); +} + + done_testing(); |