__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';
}
## 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
$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 || []})
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 ) = @_;
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
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
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;
eval "use DBD::SQLite";
plan $@
? ( skip_all => 'needs DBD::SQLite for testing' )
- : ( tests => 14 );
+ : ( tests => 15 );
}
my $schema = DBICTest->init_schema(no_populate => 1);
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');
--- /dev/null
+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" );
+
__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/;