From: Yuval Kogman Date: Tue, 29 Jul 2008 19:08:51 +0000 (+0000) Subject: nested txn_do doesn't create nested changesets X-Git-Tag: v0.900201~91 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=aba934919d04916618ce9b441b210ed516d5b067;p=dbsrgits%2FDBIx-Class-Journal.git nested txn_do doesn't create nested changesets --- diff --git a/lib/DBIx/Class/Schema/Journal.pm b/lib/DBIx/Class/Schema/Journal.pm index c056b29..8b50081 100644 --- a/lib/DBIx/Class/Schema/Journal.pm +++ b/lib/DBIx/Class/Schema/Journal.pm @@ -7,11 +7,12 @@ use DBIx::Class::Schema::Journal::DB; __PACKAGE__->mk_classdata('journal_storage_type'); __PACKAGE__->mk_classdata('journal_connection'); -__PACKAGE__->mk_classdata('journal_no_automatic_deploy'); +__PACKAGE__->mk_classdata('journal_deploy_on_connect'); __PACKAGE__->mk_classdata('journal_sources'); ## [ source names ] __PACKAGE__->mk_classdata('journal_user'); ## [ class, field for user id ] __PACKAGE__->mk_classdata('_journal_schema'); ## schema object for journal __PACKAGE__->mk_classdata('_journal_internal_sources'); # the sources used to journal journal_sources +__PACKAGE__->mk_classdata('journal_nested_changesets'); our $VERSION = '0.01'; @@ -63,7 +64,7 @@ sub connection } ## get our own private version of the journaling sources - $self->_journal_schema($journal_schema->compose_namespace(blessed($self) . '::Journal')); + $self->_journal_schema($journal_schema->compose_namespace(blessed($self) . '::Journal')); ## Create auditlog+history per table my %j_sources = map { $_ => 1 } $self->journal_sources @@ -82,8 +83,13 @@ sub connection $self->_journal_internal_sources(\@journal_sources); + if ( $self->journal_nested_changesets ) { + $self->_journal_schema->nested_changesets(1); + die "FIXME nested changeset schema not yet supported... add parent_id to ChangeSet here"; + } + $self->journal_schema_deploy() - unless $self->journal_no_automatic_deploy; + if $self->journal_deploy_on_connect; ## Set up relationship between changeset->user_id and this schema's user if(!@{$self->journal_user || []}) @@ -98,6 +104,17 @@ sub connection return $schema; } +sub deploy +{ + my ( $self, $sqlt_args, @args ) = @_; + + $self->next::method($sqlt_args, @args); + + $sqlt_args ||= {}; + local $sqlt_args->{sources} = $self->_journal_internal_sources; + $self->journal_schema_deploy($sqlt_args, @args); +} + sub journal_schema_deploy { my ( $self, $sqlt_args, @args ) = @_; @@ -151,38 +168,32 @@ sub create_journal_for sub txn_do { - my ($self, $code) = @_; + my ($self, $user_code, @args) = @_; - ## Create a new changeset, then run $code as a transaction - my $cs = $self->_journal_schema->resultset('ChangeSet'); + my $jschema = $self->_journal_schema; - $self->txn_begin; - my %changesetdata; - if( defined $self->_journal_schema->current_user() ) - { - $changesetdata{user_id} = $self->_journal_schema->current_user(); - } - if( defined $self->_journal_schema->current_session() ) - { - $changesetdata{session_id} = $self->_journal_schema->current_session(); - } + my $code; -# ( -# $self->_journal_schema->current_user() -# ? ( user_id => $self->_journal_schema->current_user()) -# : (), -# $self->_journal_schema->current_session() -# ? ( session_id => $self->_journal_schema->current_session() ) -# : () -# ); - if(!%changesetdata) + my $current_changeset = $jschema->current_changeset; + if ( !$current_changeset || $self->journal_nested_changesets ) { - %changesetdata = ( ID => undef ); + my $current_changeset_ref = $jschema->_current_changeset_container; + + unless ( $current_changeset_ref ) { + # this is a hash because scalar refs can't be localized + $current_changeset_ref = { }; + $jschema->_current_changeset_container($current_changeset_ref); + } + + # wrap the thunk with a new changeset creation + $code = sub { + my $changeset = $jschema->journal_create_changeset( parent_id => $current_changeset ); + local $current_changeset_ref->{changeset} = $changeset->ID; + $user_code->(@_); + }; } - my $changeset = $cs->create({ %changesetdata }); - $self->_journal_schema->current_changeset($changeset->ID); - $self->next::method($code); + $self->next::method($code || $user_code); } sub changeset_user diff --git a/lib/DBIx/Class/Schema/Journal/DB.pm b/lib/DBIx/Class/Schema/Journal/DB.pm index 7e2ac82..4f31cb1 100644 --- a/lib/DBIx/Class/Schema/Journal/DB.pm +++ b/lib/DBIx/Class/Schema/Journal/DB.pm @@ -2,9 +2,21 @@ package DBIx::Class::Schema::Journal::DB; use base 'DBIx::Class::Schema'; -__PACKAGE__->mk_classdata('current_user'); -__PACKAGE__->mk_classdata('current_session'); -__PACKAGE__->mk_classdata('current_changeset'); +__PACKAGE__->mk_classdata('nested_changesets'); +__PACKAGE__->mk_group_accessors( simple => 'current_user' ); +__PACKAGE__->mk_group_accessors( simple => 'current_session' ); +__PACKAGE__->mk_group_accessors( simple => '_current_changeset_container' ); + +# this is for localization of the current changeset +sub current_changeset { + my ( $self, @args ) = @_; + + $self->throw_error("setting current_changeset is not supported, use txn_do to create a new changeset") if @args; + + my $ref = $self->_current_changeset_container; + + return $ref && $ref->{changeset}; +} DBIx::Class::Schema::Journal::DB->load_classes(qw/ ChangeSet @@ -13,4 +25,26 @@ DBIx::Class::Schema::Journal::DB->load_classes(qw/ AuditHistory /); +sub journal_create_changeset { + my ( $self, @args ) = @_; + + my %changesetdata = ( @args, ID => undef ); + + delete $changesetdata{parent_id} unless $self->nested_changesets; + + if( defined( my $user = $self->current_user() ) ) + { + $changesetdata{user_id} = $user; + } + if( defined( my $session = $self->current_session() ) ) + { + $changesetdata{session_id} = $session; + } + + ## Create a new changeset, then run $code as a transaction + my $cs = $self->resultset('ChangeSet'); + + $cs->create({ %changesetdata }); +} + 1; diff --git a/t/01test.t b/t/01test.t index 9f419af..8de5a54 100644 --- a/t/01test.t +++ b/t/01test.t @@ -10,7 +10,7 @@ BEGIN { eval "use DBD::SQLite"; plan $@ ? ( skip_all => 'needs DBD::SQLite for testing' ) - : ( tests => 14 ); + : ( tests => 15 ); } my $schema = DBICTest->init_schema(no_populate => 1); @@ -20,31 +20,28 @@ isa_ok($schema->_journal_schema, 'DBIx::Class::Schema::Journal::DB', 'Actually h isa_ok($schema->_journal_schema->source('CDAuditHistory'), 'DBIx::Class::ResultSource', 'CDAuditHistory source exists'); isa_ok($schema->_journal_schema->source('ArtistAuditLog'), 'DBIx::Class::ResultSource', 'ArtistAuditLog source exists'); -{ - my $count = eval { - warn $schema->_journal_schema->resultset('ArtistAuditLog')->count; - }; - my $e = $@; - - is( $count, undef, "no count" ); - like( $e, qr/table.*artist_audit_log/i, "missing table error" ); -} - -$schema->journal_schema_deploy(); - my $artist; my $new_cd = $schema->txn_do( sub { + my $current_changeset = $schema->_journal_schema->current_changeset; + ok( $current_changeset, "have a current changeset" ); + $artist = $schema->resultset('Artist')->create({ name => 'Fred Bloggs', }); - return $schema->resultset('CD')->create({ - title => 'Angry young man', - artist => $artist, - year => 2000, + + $schema->txn_do(sub { + is( $current_changeset, $schema->_journal_schema->current_changeset, "nested txn doesn't create a new changeset" ); + return $schema->resultset('CD')->create({ + title => 'Angry young man', + artist => $artist, + year => 2000, + }); }); }); isa_ok($new_cd, 'DBIx::Class::Journal', 'Created CD object'); +is( $schema->_journal_schema->current_changeset, undef, "no current changeset" ); + my $search = $schema->_journal_schema->resultset('CDAuditLog')->search(); ok($search->count, 'Created an entry in the CD audit log'); diff --git a/t/02noautodeploy.t b/t/02noautodeploy.t new file mode 100644 index 0000000..17a6024 --- /dev/null +++ b/t/02noautodeploy.t @@ -0,0 +1,37 @@ +use strict; +use warnings; + +use Test::More; +use lib qw(t/lib); +use DBICTest; +use Data::Dumper; + +BEGIN { + eval "use DBD::SQLite"; + plan $@ + ? ( skip_all => 'needs DBD::SQLite for testing' ) + : ( 'no_plan' ); +} + +my $schema = DBICTest->init_schema(no_populate => 1, no_deploy => 1); + +ok($schema, 'Created a Schema'); +isa_ok($schema->_journal_schema, 'DBIx::Class::Schema::Journal::DB', 'Actually have a schema object for the journaling'); +isa_ok($schema->_journal_schema->source('CDAuditHistory'), 'DBIx::Class::ResultSource', 'CDAuditHistory source exists'); +isa_ok($schema->_journal_schema->source('ArtistAuditLog'), 'DBIx::Class::ResultSource', 'ArtistAuditLog source exists'); + +my $count = eval { + $schema->_journal_schema->resultset('ArtistAuditLog')->count; +}; +my $e = $@; + +is( $count, undef, "no count" ); +like( $e, qr/table.*artist_audit_log/i, "missing table error" ); + +$schema->journal_schema_deploy(); + +$count = eval { $schema->_journal_schema->resultset('ArtistAuditLog')->count }; + +is( $@, '', "no error" ); +is( $count, 0, "count is 0" ); + diff --git a/t/lib/DBICTest/Schema.pm b/t/lib/DBICTest/Schema.pm index ffe1777..3e58f95 100644 --- a/t/lib/DBICTest/Schema.pm +++ b/t/lib/DBICTest/Schema.pm @@ -5,8 +5,6 @@ use base qw/DBIx::Class::Schema/; __PACKAGE__->load_components(qw/+DBIx::Class::Schema::Journal/); -__PACKAGE__->journal_no_automatic_deploy(1); - __PACKAGE__->journal_connection(['dbi:SQLite:t/var/Audit.db']); no warnings qw/qw/;