more work on multi-db_schema
Rafael Kitover [Mon, 6 Jun 2011 10:04:31 +0000 (06:04 -0400)]
lib/DBIx/Class/Schema/Loader.pm
lib/DBIx/Class/Schema/Loader/Base.pm
lib/DBIx/Class/Schema/Loader/DBI.pm
lib/DBIx/Class/Schema/Loader/DBI/Pg.pm
lib/DBIx/Class/Schema/Loader/TableLike.pm
t/lib/dbixcsl_common_tests.pm

index f49a426..04a850c 100644 (file)
@@ -453,19 +453,7 @@ Can be imported into your dump script and called as a function as well:
 
 =head2 Multiple Database Schemas
 
-Currently the loader is limited to working within a single schema
-(using the underlying RDBMS's definition of "schema").  If you have a
-multi-schema database with inter-schema relationships (which is easy
-to do in PostgreSQL or DB2 for instance), you currently can only
-automatically load the tables of one schema, and relationships to
-tables in other schemas will be silently ignored.
-
-At some point in the future, an intelligent way around this might be
-devised, probably by allowing the C<db_schema> option to be an
-arrayref of schemas to load.
-
-In "normal" L<DBIx::Class::Schema> usage, manually-defined
-source classes and relationships have no problems crossing vendor schemas.
+See L<DBIx::Class::Schema::Loader::Base/db_schema>.
 
 =head1 ACKNOWLEDGEMENTS
 
index 622be52..11065f4 100644 (file)
@@ -304,8 +304,12 @@ decides to execute will be C<warn>-ed before execution.
 =head2 db_schema
 
 Set the name of the schema to load (schema in the sense that your database
-vendor means it).  Does not currently support loading more than one schema
-name.
+vendor means it).
+
+Can be set to an arrayref of schema names for multiple schemas, or the special
+value C<%> for all schemas.
+
+Multiple schemas have only been tested on PostgreSQL.
 
 =head2 constraint
 
@@ -848,6 +852,27 @@ sub new {
         }
     }
 
+    if (defined $self->db_schema) {
+        if (ref $self->db_schema eq 'ARRAY') {
+            if (@{ $self->db_schema } > 1) {
+                $self->{qualify_objects} = 1;
+            }
+            elsif (@{ $self->db_schema } == 0) {
+                $self->{db_schema} = undef;
+            }
+        }
+        elsif (not ref $self->db_schema) {
+            if ($self->db_schema eq '%') {
+                $self->{qualify_objects} = 1;
+            }
+
+            $self->{db_schema} = [ $self->db_schema ];
+        }
+        else {
+            croak 'db_schema must be an array or single value';
+        }
+    }
+
     $self;
 }
 
@@ -1873,14 +1898,12 @@ sub _is_result_class_method {
 sub _resolve_col_accessor_collisions {
     my ($self, $table, $col_info) = @_;
 
-    my $table_name = ref $table ? $$table : $table;
-
     while (my ($col, $info) = each %$col_info) {
         my $accessor = $info->{accessor} || $col;
 
         next if $accessor eq 'id'; # special case (very common column)
 
-        if ($self->_is_result_class_method($accessor, $table_name)) {
+        if ($self->_is_result_class_method($accessor, $table)) {
             my $mapped = 0;
 
             if (my $map = $self->col_collision_map) {
@@ -1894,7 +1917,7 @@ sub _resolve_col_accessor_collisions {
 
             if (not $mapped) {
                 warn <<"EOF";
-Column '$col' in table '$table_name' collides with an inherited method.
+Column '$col' in table '$table' collides with an inherited method.
 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
 EOF
                 $info->{accessor} = undef;
@@ -1983,8 +2006,8 @@ sub _setup_src_meta {
     }
 
     my $full_table_name = ($self->qualify_objects ?
-        ($self->_quote($self->db_schema) . '.') : '')
-        . (ref $table_name ? $$table_name : $table_name);
+        ($self->_quote($table->schema) . '.') : '')
+        . (ref $table_name eq 'SCALAR' ? $$table_name : $table_name);
 
     # be careful to not create refs Data::Dump can "optimize"
     $full_table_name = \do {"".$full_table_name} if ref $table_name;
index 964e923..f052bb7 100644 (file)
@@ -169,10 +169,10 @@ sub _table_as_sql {
 
     my $sql_maker = $self->schema->storage->sql_maker;
     my $name_sep  = $sql_maker->name_sep;
-    my $db_schema = $self->db_schema;
+    my $schema    = $table->schema;
 
-    if($db_schema) {
-        return $self->_quote($self->{db_schema})
+    if ($schema) {
+        return $self->_quote($schema)
             . $name_sep
             . $self->_quote($table);
     }
index 913e1d1..4bb5d23 100644 (file)
@@ -6,8 +6,8 @@ use base qw/
     DBIx::Class::Schema::Loader::DBI::Component::QuotedDefault
     DBIx::Class::Schema::Loader::DBI
 /;
-use Carp::Clan qw/^DBIx::Class/;
 use mro 'c3';
+use DBIx::Class::Schema::Loader::Table ();
 
 our $VERSION = '0.07010';
 
@@ -16,18 +16,9 @@ our $VERSION = '0.07010';
 DBIx::Class::Schema::Loader::DBI::Pg - DBIx::Class::Schema::Loader::DBI
 PostgreSQL Implementation.
 
-=head1 SYNOPSIS
-
-  package My::Schema;
-  use base qw/DBIx::Class::Schema::Loader/;
-
-  __PACKAGE__->loader_options( debug => 1 );
-
-  1;
-
 =head1 DESCRIPTION
 
-See L<DBIx::Class::Schema::Loader::Base>.
+See L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base>.
 
 =cut
 
@@ -36,7 +27,7 @@ sub _setup {
 
     $self->next::method(@_);
 
-    $self->{db_schema} ||= 'public';
+    $self->{db_schema} ||= ['public'];
 
     if (not defined $self->preserve_case) {
         $self->preserve_case(0);
@@ -51,18 +42,30 @@ sub _tables_list {
     my ($self, $opts) = @_;
 
     my $dbh = $self->schema->storage->dbh;
-    my @tables = $dbh->tables(undef, $self->db_schema, '%', '%');
 
-    my $schema_quoted = $tables[0] =~ /^"/;
+    my @tables;
 
-    if ($schema_quoted) {
-        s/^"[^"]+"\.// for @tables;
-    }
-    else {
-        s/^[^.]+\.// for @tables;
-    }
+    foreach my $schema (@{ $self->db_schema }) {
+        my @raw_tables = $dbh->tables(undef, $schema, '%', '%');
 
-    s/^"([^"]+)"\z/$1/ for @tables;
+        foreach my $table_name (@raw_tables) {
+            my $schema_quoted = $table_name =~ /^"/;
+
+            if ($schema_quoted) {
+                $table_name =~ s/^"([^"]+)"\.//;
+            }
+            else {
+                $table_name =~ s/^([^.]+)\.//;
+            }
+            my $table = DBIx::Class::Schema::Loader::Table->new(schema => $1);
+
+            $table_name =~ s/^"([^"]+)"\z/$1/;
+
+            $table->name($table_name);
+
+            push @tables, $table;
+        }
+    }
 
     return $self->_filter_tables(\@tables, $opts);
 }
@@ -103,7 +106,7 @@ sub _table_uniq_info {
           c.relname     = ?}
     );
 
-    $uniq_sth->execute($self->db_schema, $table);
+    $uniq_sth->execute($table->schema, $table);
     while(my $row = $uniq_sth->fetchrow_arrayref) {
         my ($tableid, $indexname, $col_nums) = @$row;
         $col_nums =~ s/^\s+//;
@@ -134,7 +137,7 @@ sub _table_comment {
             FROM pg_class 
             WHERE relname=? AND relnamespace=(
                 SELECT oid FROM pg_namespace WHERE nspname=?)
-        }, undef, $table, $self->db_schema
+        }, undef, $table, $table->schema
         );   
     return $table_comment
 }
@@ -147,7 +150,7 @@ sub _column_comment {
             FROM pg_class 
             WHERE relname=? AND relnamespace=(
                 SELECT oid FROM pg_namespace WHERE nspname=?)
-        }, undef, $table, $self->db_schema
+        }, undef, $table, $table->schema
         );   
     return $self->schema->storage->dbh->selectrow_array('SELECT col_description(?,?)', undef, $table_oid,
     $column_number );
@@ -251,7 +254,7 @@ SELECT typtype
 FROM pg_catalog.pg_type
 WHERE typname = ?
 EOF
-            if ($typetype eq 'e') {
+            if ($typetype && $typetype eq 'e') {
                 # The following will extract a list of allowed values for the
                 # enum.
                 my $typevalues = $self->schema->storage->dbh
index 366eb43..bdfbfe9 100644 (file)
@@ -27,7 +27,13 @@ __PACKAGE__->mk_group_accessors(simple => qw/
 /);
 
 use overload
-    '""' => 'name';
+    '""' => sub { $_[0]->name };
+
+sub new {
+    my $class = shift;
+
+    return bless { @_ }, $class;
+}
 
 =head1 SEE ALSO
 
index 0739692..9067be9 100644 (file)
@@ -574,12 +574,12 @@ sub test_schema {
         );
 
         is(
-            sprintf("%.3f", $class35->column_info('a_double')->{default_value}), '10.555',
+            sprintf("%.3f", $class35->column_info('a_double')->{default_value}||0), '10.555',
             'constant numeric default',
         );
 
         is(
-            sprintf("%.3f", $class35->column_info('a_negative_double')->{default_value}), -10.555,
+            sprintf("%.3f", $class35->column_info('a_negative_double')->{default_value}||0), -10.555,
             'constant negative numeric default',
         );