better type info for Pg: sets sequence for serials, handles numerics without precision
Rafael Kitover [Sun, 21 Mar 2010 11:45:10 +0000 (07:45 -0400)]
Changes
lib/DBIx/Class/Schema/Loader/DBI.pm
lib/DBIx/Class/Schema/Loader/DBI/Pg.pm
t/12pg_common.t
t/lib/dbixcsl_common_tests.pm

diff --git a/Changes b/Changes
index b6e72c7..d004d3b 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
 Revision history for Perl extension DBIx::Class::Schema::Loader
 
+        - better type info for Pg: sets sequence for serials, handles numerics
+          without precision
         - better _tables_list for MSSQL
         - pick up views in SQLite too
         - better rel inflection using Lingua::EN::Inflect::Phrase
index a9d7161..0eef7aa 100644 (file)
@@ -284,10 +284,10 @@ sub _columns_info_for {
             my $sth = $dbh->column_info( undef, $self->db_schema, $table, '%' );
             while ( my $info = $sth->fetchrow_hashref() ){
                 my $column_info = {};
-                $column_info->{data_type}   = $info->{TYPE_NAME};
-                $column_info->{size}      = $info->{COLUMN_SIZE};
+                $column_info->{data_type}     = $info->{TYPE_NAME};
+                $column_info->{size}          = $info->{COLUMN_SIZE} if defined $info->{COLUMN_SIZE};
                 $column_info->{is_nullable}   = $info->{NULLABLE} ? 1 : 0;
-                $column_info->{default_value} = $info->{COLUMN_DEF};
+                $column_info->{default_value} = $info->{COLUMN_DEF} if defined $info->{COLUMN_DEF};
                 my $col_name = $info->{COLUMN_NAME};
                 $col_name =~ s/^\"(.*)\"$/$1/;
 
@@ -310,7 +310,7 @@ sub _columns_info_for {
     for my $i ( 0 .. $#columns ){
         my $column_info = {};
         $column_info->{data_type} = $sth->{TYPE}->[$i];
-        $column_info->{size} = $sth->{PRECISION}->[$i];
+        $column_info->{size} = $sth->{PRECISION}->[$i] if $sth->{PRECISION}->[$i];
         $column_info->{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
 
         if ($column_info->{data_type} =~ m/^(.*?)\((.*?)\)$/) {
index 6d26474..cee52e2 100644 (file)
@@ -186,28 +186,23 @@ EOF
 
             $result->{$col}{size} = $precision;
         }
-        elsif ($data_type =~ /^(?:numeric|decimal)\z/i) {
-            my $size = $result->{$col}{size};
+        elsif ($data_type =~ /^(?:numeric|decimal)\z/i && (my $size = $result->{$col}{size})) {
             $size =~ s/\s*//g;
 
             my ($scale, $precision) = split /,/, $size;
 
             $result->{$col}{size} = [ $precision, $scale ];
         }
-    }
-
-    return $result;
-}
 
-sub _extra_column_info {
-    my ($self, $table, $column, $info, $dbi_info) = @_;
-    my %extra_info;
-
-    if ($dbi_info->{COLUMN_DEF} && $dbi_info->{COLUMN_DEF} =~ /\bnextval\(/i) {
-        $extra_info{is_auto_increment} = 1;
+# process SERIAL columns
+        if (ref($result->{$col}{default_value}) eq 'SCALAR' && ${ $result->{$col}{default_value} } =~ /\bnextval\(['"](\w+)/i) {
+            $result->{$col}{is_auto_increment} = 1;
+            $result->{$col}{sequence}          = $1;
+            delete $result->{$col}{default_value};
+        }
     }
 
-    return \%extra_info;
+    return $result;
 }
 
 =head1 SEE ALSO
index fb31fb7..157decf 100644 (file)
@@ -16,51 +16,51 @@ my $tester = dbixcsl_common_tests->new(
     user        => $user,
     password    => $password,
     data_types  => {
-       'bigint'    => { size => undef, data_type => 'bigint' },
-       'int8'      => { size => undef, data_type => 'bigint' },
-       'bigserial' => { size => undef, data_type => 'bigint', is_auto_increment => 1 },
-       'serial8'   => { size => undef, data_type => 'bigint', is_auto_increment => 1 },
-       'bit'       => { size => undef, data_type => 'bit' },
-       'boolean'   => { size => undef, data_type => 'boolean' },
-       'bool'      => { size => undef, data_type => 'boolean' },
-       'box'       => { size => undef, data_type => 'box' },
-       'bytea'     => { size => undef, data_type => 'bytea' },
-       'cidr'      => { size => undef, data_type => 'cidr' },
-       'circle'    => { size => undef, data_type => 'circle' },
-       'date'      => { size => undef, data_type => 'date' },
-       'double precision' => { size => undef, data_type => 'double precision' },
-       'float8'      => { size => undef, data_type => 'double precision' },
-       'inet'        => { size => undef, data_type => 'inet' },
-       'integer'     => { size => undef, data_type => 'integer' },
-       'int'         => { size => undef, data_type => 'integer' },
-       'int4'        => { size => undef, data_type => 'integer' },
-       'interval'    => { size => undef, data_type => 'interval' },
+       'bigint'    => { data_type => 'bigint' },
+       'int8'      => { data_type => 'bigint' },
+       'bigserial' => { data_type => 'bigint', is_auto_increment => 1 },
+       'serial8'   => { data_type => 'bigint', is_auto_increment => 1 },
+       'bit'       => { data_type => 'bit' },
+       'boolean'   => { data_type => 'boolean' },
+       'bool'      => { data_type => 'boolean' },
+       'box'       => { data_type => 'box' },
+       'bytea'     => { data_type => 'bytea' },
+       'cidr'      => { data_type => 'cidr' },
+       'circle'    => { data_type => 'circle' },
+       'date'      => { data_type => 'date' },
+       'double precision' => { data_type => 'double precision' },
+       'float8'      => { data_type => 'double precision' },
+       'inet'        => { data_type => 'inet' },
+       'integer'     => { data_type => 'integer' },
+       'int'         => { data_type => 'integer' },
+       'int4'        => { data_type => 'integer' },
+       'interval'    => { data_type => 'interval' },
        'interval(2)' => { size => 2, data_type => 'interval' },
-       'line'        => { size => undef, data_type => 'line' },
-       'lseg'        => { size => undef, data_type => 'lseg' },
-       'macaddr'     => { size => undef, data_type => 'macaddr' },
-       'money'       => { size => undef, data_type => 'money' },
-       'path'        => { size => undef, data_type => 'path' },
-       'point'       => { size => undef, data_type => 'point' },
-       'polygon'     => { size => undef, data_type => 'polygon' },
-       'real'        => { size => undef, data_type => 'real' },
-       'float4'      => { size => undef, data_type => 'real' },
-       'smallint'    => { size => undef, data_type => 'smallint' },
-       'int2'        => { size => undef, data_type => 'smallint' },
-       'serial'      => { size => undef, data_type => 'integer', is_auto_increment => 1 },
-       'serial4'     => { size => undef, data_type => 'integer', is_auto_increment => 1 },
-       'text'        => { size => undef, data_type => 'text' },
-       'time'        => { size => undef, data_type => 'time without time zone' },
+       'line'        => { data_type => 'line' },
+       'lseg'        => { data_type => 'lseg' },
+       'macaddr'     => { data_type => 'macaddr' },
+       'money'       => { data_type => 'money' },
+       'path'        => { data_type => 'path' },
+       'point'       => { data_type => 'point' },
+       'polygon'     => { data_type => 'polygon' },
+       'real'        => { data_type => 'real' },
+       'float4'      => { data_type => 'real' },
+       'smallint'    => { data_type => 'smallint' },
+       'int2'        => { data_type => 'smallint' },
+       'serial'      => { data_type => 'integer', is_auto_increment => 1 },
+       'serial4'     => { data_type => 'integer', is_auto_increment => 1 },
+       'text'        => { data_type => 'text' },
+       'time'        => { data_type => 'time without time zone' },
        'time(2)'     => { size => 2, data_type => 'time without time zone' },
-       'time without time zone'         => { size => undef, data_type => 'time without time zone' },
+       'time without time zone'         => { data_type => 'time without time zone' },
        'time(2) without time zone'      => { size => 2, data_type => 'time without time zone' },
-       'time with time zone'            => { size => undef, data_type => 'time with time zone' },
+       'time with time zone'            => { data_type => 'time with time zone' },
        'time(2) with time zone'         => { size => 2, data_type => 'time with time zone' },
-       'timestamp'                      => { size => undef, data_type => 'timestamp without time zone' },
+       'timestamp'                      => { data_type => 'timestamp without time zone' },
        'timestamp(2)'                   => { size => 2, data_type => 'timestamp without time zone' },
-       'timestamp without time zone'    => { size => undef, data_type => 'timestamp without time zone' },
+       'timestamp without time zone'    => { data_type => 'timestamp without time zone' },
        'timestamp(2) without time zone' => { size => 2, data_type => 'timestamp without time zone' },
-       'timestamp with time zone'       => { size => undef, data_type => 'timestamp with time zone' },
+       'timestamp with time zone'       => { data_type => 'timestamp with time zone' },
        'timestamp(2) with time zone'    => { size => 2, data_type => 'timestamp with time zone' },
        'bit varying(2)'                 => { size => 2, data_type => 'bit varying' },
        'varbit(2)'                      => { size => 2, data_type => 'bit varying' },
@@ -70,9 +70,11 @@ my $tester = dbixcsl_common_tests->new(
        'char(2)'                        => { size => 2, data_type => 'character' },
        'numeric(6, 3)'                  => { size => [6,3], data_type => 'numeric' },
        'decimal(6, 3)'                  => { size => [6,3], data_type => 'numeric' },
-        'float(24)'                      => { size => undef, data_type => 'real' },
-        'float(53)'                      => { size => undef, data_type => 'double precision' },
-        'float'                          => { size => undef, data_type => 'double precision' },
+        'numeric'                        => { data_type => 'numeric' },
+        'decimal'                        => { data_type => 'numeric' },
+        'float(24)'                      => { data_type => 'real' },
+        'float(53)'                      => { data_type => 'double precision' },
+        'float'                          => { data_type => 'double precision' },
     },
     extra       => {
         create => [
index 8dff6ec..dd97705 100644 (file)
@@ -871,17 +871,25 @@ sub test_schema {
         my $rsrc = $conn->resultset($data_type_tests->{table_moniker})->result_source;
 
         while (my ($col_name, $expected_info) = each %$columns) {
-            while (my ($info_key, $info_val) = each %$expected_info) {
-                my $text_info_val = do {
-                    my $dd = Dumper;
-                    $dd->Indent(0);
-                    $dd->Values([$info_val]);
-                    $dd->Dump;
-                };
-
-                is_deeply $rsrc->column_info($col_name)->{$info_key}, $info_val,
-                    "column of type $col_name has $info_key => $text_info_val";
-            }
+            my %info = %{ $rsrc->column_info($col_name) };
+            delete @info{qw/is_nullable timezone locale sequence/};
+
+            my $text_col_def = do {
+                my $dd = Dumper;
+                $dd->Indent(0);
+                $dd->Values([\%info]);
+                $dd->Dump;
+            };
+
+            my $text_expected_info = do {
+                my $dd = Dumper;
+                $dd->Indent(0);
+                $dd->Values([$expected_info]);
+                $dd->Dump;
+            };
+
+            is_deeply \%info, $expected_info,
+                "test column $col_name has definition: $text_col_def expecting: $text_expected_info";
         }
     }
 
@@ -1559,7 +1567,7 @@ sub setup_data_type_tests {
 
         $cols->{$col_name} = $expected_info;
 
-        $test_count += scalar keys %$expected_info;
+        $test_count++;
     }
 
     $ddl =~ s/,\n\z/\n)/;
@@ -1579,3 +1587,4 @@ sub DESTROY {
 }
 
 1;
+# vim:et sts=4 sw=4 tw=0: