[Dbix-class] [PATCH] Enable Timestamp Conflation
Ronald E. Straight
quinnfazigu at gmail.com
Tue May 5 00:52:33 GMT 2009
Heya, folks. Here's a patch I discussed on IRC with mst. It allows for
the proper consideration of timestamp data types. I saw some discussion
recently about it, so hopefully it will pass the mustard {sic}.
Tests included, and all existing tests pass. I'm not altogether happy
with how I went about the testing, but it seemed the least invasive,
best surgical method. Comments and criticism welcome.
The code is in the oracle-tweaks branch. Next up: Oracle LOB support.
-------------- next part --------------
Index: t/73oracle.t
===================================================================
--- t/73oracle.t (revision 6116)
+++ t/73oracle.t (working copy)
@@ -64,7 +64,7 @@
$dbh->do("CREATE TABLE artist (artistid NUMBER(12), name VARCHAR(255), rank NUMBER(38), charfield VARCHAR2(10))");
$dbh->do("CREATE TABLE sequence_test (pkid1 NUMBER(12), pkid2 NUMBER(12), nonpkid NUMBER(12), name VARCHAR(255))");
$dbh->do("CREATE TABLE cd (cdid NUMBER(12), artist NUMBER(12), title VARCHAR(255), year VARCHAR(4))");
-$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12), position NUMBER(12), title VARCHAR(255), last_updated_on DATE)");
+$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12), position NUMBER(12), title VARCHAR(255), last_updated_on DATE, last_updated_at DATE)");
$dbh->do("ALTER TABLE artist ADD (CONSTRAINT artist_pk PRIMARY KEY (artistid))");
$dbh->do("ALTER TABLE sequence_test ADD (CONSTRAINT sequence_test_constraint PRIMARY KEY (pkid1, pkid2))");
Index: t/73oracle_inflate.t
===================================================================
--- t/73oracle_inflate.t (revision 6116)
+++ t/73oracle_inflate.t (working copy)
@@ -17,12 +17,13 @@
plan skip_all => 'needs DateTime and DateTime::Format::Oracle for testing';
}
else {
- plan tests => 4;
+ plan tests => 7;
}
}
# DateTime::Format::Oracle needs this set
$ENV{NLS_DATE_FORMAT} = 'DD-MON-YY';
+$ENV{NLS_TIMESTAMP_FORMAT} = 'YYYY-MM-DD HH24:MI:SSXFF';
my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
@@ -30,16 +31,20 @@
my $col_metadata = $schema->class('Track')->column_info('last_updated_on');
$schema->class('Track')->add_column( 'last_updated_on' => {
data_type => 'date' });
+$schema->class('Track')->add_column( 'last_updated_at' => {
+ data_type => 'timestamp' });
my $dbh = $schema->storage->dbh;
+#$dbh->do("alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SSXFF'");
+
eval {
$dbh->do("DROP TABLE track");
};
-$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12), position NUMBER(12), title VARCHAR(255), last_updated_on DATE)");
+$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12), position NUMBER(12), title VARCHAR(255), last_updated_on DATE, last_updated_at TIMESTAMP)");
# insert a row to play with
-my $new = $schema->resultset('Track')->create({ trackid => 1, cd => 1, position => 1, title => 'Track1', last_updated_on => '06-MAY-07' });
+my $new = $schema->resultset('Track')->create({ trackid => 1, cd => 1, position => 1, title => 'Track1', last_updated_on => '06-MAY-07', last_updated_at => '2009-05-03 21:17:18.5' });
is($new->trackid, 1, "insert sucessful");
my $track = $schema->resultset('Track')->find( 1 );
@@ -48,11 +53,18 @@
is( $track->last_updated_on->month, 5, "DateTime methods work on inflated column");
+#note '$track->last_updated_at => ', $track->last_updated_at;
+is( ref($track->last_updated_at), 'DateTime', "last_updated_at inflated ok");
+
+is( $track->last_updated_at->nanosecond, 500_000_000, "DateTime methods work with nanosecond precision");
+
my $dt = DateTime->now();
$track->last_updated_on($dt);
+$track->last_updated_at($dt);
$track->update;
is( $track->last_updated_on->month, $dt->month, "deflate ok");
+is( int $track->last_updated_at->nanosecond, int $dt->nanosecond, "deflate ok with nanosecond precision");
# clean up our mess
END {
Index: t/lib/sqlite.sql
===================================================================
--- t/lib/sqlite.sql (revision 6116)
+++ t/lib/sqlite.sql (working copy)
@@ -375,7 +375,8 @@
cd integer NOT NULL,
position integer NOT NULL,
title varchar(100) NOT NULL,
- last_updated_on datetime
+ last_updated_on datetime,
+ last_updated_at datetime
);
CREATE INDEX track_idx_cd_track ON track (cd);
Index: t/lib/DBICTest/Schema/Track.pm
===================================================================
--- t/lib/DBICTest/Schema/Track.pm (revision 6116)
+++ t/lib/DBICTest/Schema/Track.pm (working copy)
@@ -26,6 +26,10 @@
accessor => 'updated_date',
is_nullable => 1
},
+ last_updated_at => {
+ data_type => 'datetime',
+ is_nullable => 1
+ },
);
__PACKAGE__->set_primary_key('trackid');
Index: lib/DBIx/Class/InflateColumn/DateTime.pm
===================================================================
--- lib/DBIx/Class/InflateColumn/DateTime.pm (revision 6116)
+++ lib/DBIx/Class/InflateColumn/DateTime.pm (working copy)
@@ -94,7 +94,7 @@
my $type;
- for (qw/date datetime/) {
+ for (qw/date datetime timestamp/) {
my $key = "inflate_${_}";
next unless exists $info->{$key};
@@ -106,7 +106,6 @@
unless ($type) {
$type = lc($info->{data_type});
- $type = 'datetime' if ($type =~ /^timestamp/);
}
my $timezone;
@@ -128,7 +127,7 @@
my $undef_if_invalid = $info->{datetime_undef_if_invalid};
- if ($type eq 'datetime' || $type eq 'date') {
+ if ($type eq 'datetime' || $type eq 'date' || $type eq 'timestamp') {
my ($parse, $format) = ("parse_${type}", "format_${type}");
# This assignment must happen here, otherwise Devel::Cycle treats
@@ -157,7 +156,9 @@
{
inflate => sub {
my ($value, $obj) = @_;
- my $dt = eval { $obj->_datetime_parser->$parse($value); };
+ my $parser = $obj->_datetime_parser;
+ my $parser_method = $parser->can($parse) ? $parse : "parse_datetime";
+ my $dt = eval { $parser->$parser_method($value); };
die "Error while inflating ${value} for ${column} on ${self}: $@"
if $@ and not $undef_if_invalid;
$dt->set_time_zone($timezone) if $timezone;
@@ -166,6 +167,8 @@
},
deflate => sub {
my ($value, $obj) = @_;
+ my $parser = $obj->_datetime_parser;
+ my $parser_method = $parser->can($format) ? $format : "format_datetime";
if ($timezone) {
warn "You're using a floating timezone, please see the documentation of"
. " DBIx::Class::InflateColumn::DateTime for an explanation"
@@ -175,13 +178,14 @@
$value->set_time_zone($timezone);
$value->set_locale($locale) if $locale;
}
- $obj->_datetime_parser->$format($value);
+ $parser->$parser_method($value);
},
}
);
}
}
+
sub _datetime_parser {
my $self = shift;
if (my $parser = $self->__datetime_parser) {
More information about the DBIx-Class
mailing list