From 61f680f88388a41259a7980063a1b4f34798e1f0 Mon Sep 17 00:00:00 2001 From: Martin Doppelreiter Date: Mon, 12 Sep 2016 12:32:06 +0200 Subject: [PATCH] Adds nested transactions handling --- lib/DBIx/Class/Schema/AuditLog.pm | 36 ++--- lib/DBIx/Class/Schema/AuditLog/Structure.pm | 7 +- .../Schema/AuditLog/Structure/Changeset.pm | 4 + t/013_nested_transactions.t | 142 ++++++++++++++++++ 4 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 t/013_nested_transactions.t diff --git a/lib/DBIx/Class/Schema/AuditLog.pm b/lib/DBIx/Class/Schema/AuditLog.pm index 36baeed..131ebf3 100644 --- a/lib/DBIx/Class/Schema/AuditLog.pm +++ b/lib/DBIx/Class/Schema/AuditLog.pm @@ -60,25 +60,25 @@ sub txn_do { my $changeset_data = $args[0]; my $current_changeset = $audit_log_schema->_current_changeset; - if ( !$current_changeset ) { - my $current_changeset_ref - = $audit_log_schema->_current_changeset_container; - - unless ($current_changeset_ref) { - $current_changeset_ref = {}; - $audit_log_schema->_current_changeset_container( - $current_changeset_ref); - } - - $code = sub { - # creates local variables in the transaction scope to store - # the changset args, and the changeset id - local $current_changeset_ref->{args} = $args[0]; - local $current_changeset_ref->{changeset} = ''; - $user_code->(@_); - }; + my $parent_id = $current_changeset ? $current_changeset : undef; + + my $current_changeset_ref = $audit_log_schema->_current_changeset_container; + + unless ($current_changeset_ref) { + $current_changeset_ref = {}; + $audit_log_schema->_current_changeset_container( + $current_changeset_ref); } + $code = sub { + # creates local variables in the transaction scope to store + # the changset args, and the changeset id + local $current_changeset_ref->{args} = $args[0]; + local $current_changeset_ref->{changeset} = ''; + $current_changeset_ref->{args}->{parent_id} = $parent_id; + $user_code->(@_); + }; + if ( $audit_log_schema->storage != $self->storage ) { my $inner_code = $code; $code = sub { $audit_log_schema->txn_do( $inner_code, @_ ) }; @@ -103,7 +103,7 @@ sub audited_sources{ =head2 audited_source -=over +=over =item Arguments: $source_name diff --git a/lib/DBIx/Class/Schema/AuditLog/Structure.pm b/lib/DBIx/Class/Schema/AuditLog/Structure.pm index 3b4cbcf..60bc48c 100644 --- a/lib/DBIx/Class/Schema/AuditLog/Structure.pm +++ b/lib/DBIx/Class/Schema/AuditLog/Structure.pm @@ -82,11 +82,14 @@ sub audit_log_create_changeset { ->find_or_create( { name => $user_id } ); $changeset = $user->create_related( 'Changeset', - { description => $changeset_data->{description} } ); + { description => $changeset_data->{description}, + parent_id => $changeset_data->{parent_id} } + ); } else { $changeset = $self->resultset('AuditLogChangeset') - ->create( { description => $changeset_data->{description} } ); + ->create( { description => $changeset_data->{description}, + parent_id => $changeset_data->{parent_id} } ); } return $changeset; diff --git a/lib/DBIx/Class/Schema/AuditLog/Structure/Changeset.pm b/lib/DBIx/Class/Schema/AuditLog/Structure/Changeset.pm index 3893797..4949514 100644 --- a/lib/DBIx/Class/Schema/AuditLog/Structure/Changeset.pm +++ b/lib/DBIx/Class/Schema/AuditLog/Structure/Changeset.pm @@ -29,6 +29,10 @@ __PACKAGE__->add_columns( 'data_type' => 'integer', 'is_nullable' => 1, }, + 'parent_id' => { + 'data_type' => 'integer', + 'is_nullable' => 1, + }, ); __PACKAGE__->set_primary_key('id'); diff --git a/t/013_nested_transactions.t b/t/013_nested_transactions.t new file mode 100644 index 0000000..07354d5 --- /dev/null +++ b/t/013_nested_transactions.t @@ -0,0 +1,142 @@ +use strict; +use warnings; + +use DBICx::TestDatabase; +use Test::More; + +use lib 't/lib'; + +my $schema = DBICx::TestDatabase->new('AuditTest::Schema'); + +$schema->audit_log_schema->deploy; + +my $al_schema = $schema->audit_log_schema; + +$schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + }, + { description => "no nesting", + user => "TestAdminUser01", + }, +); + +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'no nesting' + })->single->parent_id, + undef, + 'no nesting' +); + +$schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + $schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + $schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + $schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + }, + { description => "nesting level 3", + user => "TestAdminUser01", + }, + ); + }, + { description => "nesting level 2", + user => "TestAdminUser01", + }, + ); + }, + { description => "nesting level 1", + user => "TestAdminUser01", + }, + ); + $schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + }, + { description => "2nd nesting level 1", + user => "TestAdminUser01", + }, + ); + }, + { description => "parent", + user => "TestAdminUser01", + }, +); + +my $parent_changeset = $al_schema->resultset('AuditLogChangeset')->search({ + description => 'parent' +})->single; +is ( $parent_changeset->parent_id, undef, 'parent'); + +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'nesting level 1' + })->single->parent_id, + $parent_changeset->id, + 'nested transaction level 1' +); +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'nesting level 2' + })->single->parent_id, + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'nesting level 1' + })->single->id, + 'nested transaction level 2' +); +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'nesting level 3' + })->single->parent_id, + $al_schema->resultset('AuditLogChangeset')->search({ + description => 'nesting level 2' + })->single->id, + 'nested transaction level 3' +); +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => '2nd nesting level 1' + })->single->parent_id, + $parent_changeset->id, + '2nd nested transaction level 1' +); + +$schema->txn_do( + sub { + $schema->resultset('User')->create( + { name => "JohnSample" } + ); + }, + { description => "2nd no nesting", + user => "TestAdminUser01", + }, +); + +is ( + $al_schema->resultset('AuditLogChangeset')->search({ + description => '2nd no nesting' + })->single->parent_id, + undef, + 'no nesting again' +); + +done_testing();