Perl resources, modules, and sample code

How to auto-generate UUID primary keys via DBIx::Class

Wednesday, 14 January 2009—subject to ongoing, unnanounced updates

Modern Perl Modern Perl at Powell’s, Modern Perl at Barnes and Noble, Modern Perl at Amazon.com, or download Modern Perl for free and then recommend it to your friends, write a great review, or otherwise spread the word.

Here’s a little hard-won knowledge for you today. How to generate UUID primary keys via DBIC. I am trying to use them for the primary keys for a new project. It has to be portable so there are no auto_increment or built-in sequence ids. The component assumes that any non-compound (one column only) primary keys are UUID and auto-populates them before insertion into the database.

The DBIC component

package DBIx::Class::PK::UUID;
use parent "DBIx::Class::Row";
use Data::UUID;

sub insert {
    my $self = shift;
    my ( $pk, $other ) = $self->primary_columns;
    return $self->next::method(@_) if $other;     # Multiple key.
    return $self->next::method(@_) if $self->$pk; # Already set.
    # Size must be 36 or it can't be a UUID column.
    return $self->next::method(@_)
        unless 36 == $self->result_source->column_info($pk)->{size};
    $self->$pk( lc Data::UUID->new->create_str );
    return $self->next::method(@_);
}

1;

Usage

And then in your schema-dumping–

make_schema_at(
               $class,
               { dump_directory => $lib,
                 components => [qw( PK::UUID )],},
               \@ARGV
              );

–or your manual classes–

package Yesh::Schema::Result::Article;
use strict;
use warnings;
use parent "DBIx::Class";
__PACKAGE__->load_components("PK::UUID", "Core");

Looks simple, doesn’t it. After two hours of screwing around with trying to subclass DBIx::Class 5 different clever and horrible ways and seeing nothing but—Can't load Yesh::Schema::Result::Article: Inconsistent hierarchy during C3 merge of class 'Yesh::Schema::Result::Article': merging failed on parent 'DBIx::Class' at /usr/local/lib/perl5/5.10.0/mro.pm line 26—it sure doesn’t feel easy.

Now you have UUID primary keys which are database independent. Doesn’t matter if you can’t write a sequence to match it or if the engine doesn’t support it. Will deploy to any of the usual suspects equally well. Can also, as noted in the code, be overridden by providing your own key at object creation if you’re populating from legacy data. Woo woo.

Tune in next time for How to force NULL values into empty or undefined fields via DBIx::Class.