Categories
Uncategorized

Class::DBI transactions

This is something I did at work just before Christmas, which is kind of useful.

Some years ago, I came up with the original method do_transaction() for Class::DBI. However, it’s kind of clunky to use, as the example shows.

Music::DBI->do_transaction( sub {
  my $artist = Music::Artist->insert({ name => 'Pink Floyd' });
  my $cd = $artist->add_to_cds({
    title => 'Dark Side Of The Moon',
    year  => 1974,
  });
});

The thing that bugs me in particular is the mandatory use of sub {}. I’d rather it be like ruby’s blocks, more of a language feature. Thankfully, Perl allows you to do this with prototypes.

So I modified my base class for Class::DBI to look like this:

use Exporter 'import';
our @EXPORT = qw( do_transaction );
sub do_transaction (&) {
  my $class = __PACKAGE__;
  # Rest of function remains the same.
}

This lets you call do_transaction in a much simpler fashion:

use Music::DBI;
do_transaction {
  my $artist = Music::Artist->insert({ name => 'Pink Floyd' });
  my $cd = $artist->add_to_cds({
    title => 'Dark Side Of The Moon',
    year  => 1974,
  });
}

Now I have committed one of the cardinal sins of Perl OO here—I’m exporting from an OO module. In this case though, I feel it’s justified. Firstly, you need to call the function as a function and not a method for the prototype to have any effect. Secondly, it greatly reduces the amount of typing that I have to do. Overall, it’s a much nicer solution.

Of course, Ruby on Rails makes this much simpler, because it’s notion of blocks is so deeply embedded into the language. See ActiveRecord::Transactions::ClassMethods for details.