DBIC note to self…

. 255 words; about 2 minutes.
Category: Perl.

[This post was rescued from an SQL dump of my ancient Movable Type blog. There may be conversion errors and broken links.]

Update 2010-03-10: The bug this works around has been fixed as of DBIx-Class-0.08120 (released 2010-02-24), so it is no longer necessary to use this hack unless you are stuck with an old DBIx::Class.

There's an interesting interaction between PostgreSQL, DBIx::Class::Schema::Loader and DBIx::Class:InflateColumn::DateTime.

When you define a column to be of type TIMESTAMP, it actually becomes a TIMESTAMP WITHOUT TIME ZONE. DBIx::Class::Schema::Loader just copies this into the DBIC data_type field without translation, and so when DBIx::Class::InflateColumn::DateTime comes along, it doesn't realise it's a time value and doesn't bother to add the inflater.

This awful kludge hooks register_column and changes the data_type field to "timestamp", thus making it all work as expected.

package DBIx::Class::InflateColumn::PgDateTimeTZKludge;
use Moose;
extends qw/DBIx::Class/;

# This DBIC component is added to the DBIC loader_options *just after*
# InflateColumn::DateTime - it's chained so it's actually run *first* - and
# it will change "timestamp without time zone" columns to "timestamp" so
# that InflateColumn realises they are timestamp types and adds its
# inflater/deflater.

sub register_column {
  my ($self, $column, $info, @rest) = @_;
  $self->next::method($column, $info, @rest);
  return unless defined($info->{data_type});

  my $type = lc $info->{data_type};
  if($type eq 'timestamp without time zone') {
    $info->{data_type} = 'timestamp';
  } # elsif etc
}