unregister dropped sources on rescan
Rafael Kitover [Mon, 26 Apr 2010 21:21:17 +0000 (17:21 -0400)]
Changes
TODO
lib/DBIx/Class/Schema/Loader/Base.pm
lib/DBIx/Class/Schema/Loader/DBI.pm
t/lib/dbixcsl_common_tests.pm

diff --git a/Changes b/Changes
index b21aada..c6454fb 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,6 @@
 Revision history for Perl extension DBIx::Class::Schema::Loader
 
+        - unregister dropped sources on rescan
         - added 'preserve_case' option with support for SQLite, mysql, MSSQL and
           Firebird/InterBase; removed the MSSQL 'case_sensitive_collation' and
           the Firebird/InterBase 'unquoted_ddl' options in favor of it.
diff --git a/TODO b/TODO
index a2ba73f..95b9bf5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,8 +8,6 @@ support pk/uk/fk info on views, possibly.  May or may not be a sane thing to try
 Fix up ResultSet Manager / Methods / etc stuff.  May require some work in the
 main DBIx::Class first.
 
-SQLite needs some heavy refactoring, the subroutines are becoming too complex to understand easily.
-
 Refactor RelBuilder so that it doesn't require a live mostly-built
 DBIx::Class::Schema, so that other modules (SQLT) can use it easier.  And then
 when/if we get there, break it out as a seperate distribution with a new name.
@@ -18,5 +16,3 @@ Relationship stuff:
    Re-scan relations/tables after initial relation setup to find ->many_to_many() relations to be set up?
    While scanning for many-to-many, scan for implied rels as well? (if foo->belongs_to('bar') and baz->belongs_to('bar'), does that impliy foo->might_have('baz') and the reverse?)
    ...
-
-unregister sources for dropped tables on rescan
index 997b7e0..d5e70a8 100644 (file)
@@ -177,12 +177,8 @@ In general, there is very little difference between v5 and v6 schemas.
 This mode is identical to C<v6> mode, except that monikerization of CamelCase
 table names is also done correctly.
 
-CamelCase column names in case-sensitive mode will also be handled correctly
-for relationship name inflection.
-
-Currently, only Sybase ASE, MSSQL with CS/BIN collation and Firebird without
-the L<unquoted_ddl|DBIx::Class::Schema::Loader::DBI::InterBase/unquoted_ddl>
-option are in case-sensitive mode.
+CamelCase column names in case-preserving mode will also be handled correctly
+for relationship name inflection. See L</preserve_case>.
 
 If you don't have any CamelCase table or column names, you can upgrade without
 breaking any of your code.
@@ -924,12 +920,21 @@ sub rescan {
 
     my @created;
     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
+
     foreach my $table (@current) {
         if(!exists $self->{_tables}->{$table}) {
             push(@created, $table);
         }
     }
 
+    my %current;
+    @current{@current} = ();
+    foreach my $table (keys %{ $self->{_tables} }) {
+        if (not exists $current{$table}) {
+            $self->_unregister_source_for_table($table);
+        }
+    }
+
     my $loaded = $self->_load_tables(@created);
 
     return map { $self->monikers->{$_} } @$loaded;
@@ -1801,6 +1806,22 @@ sub _uc {
     return $self->preserve_case ? $name : uc($name);
 }
 
+sub _unregister_source_for_table {
+    my ($self, $table) = @_;
+
+    eval {
+        local $@;
+        my $schema = $self->schema;
+        # in older DBIC it's a private method
+        my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
+        $schema->$unregister($self->_table2moniker($table));
+        delete $self->monikers->{$table};
+        delete $self->classes->{$table};
+        delete $self->_upgrading_classes->{$table};
+        delete $self->{_tables}{$table};
+    };
+}
+
 # remove the dump dir from @INC on destruction
 sub DESTROY {
     my $self = shift;
index 33a274e..7e9a7a7 100644 (file)
@@ -132,14 +132,7 @@ sub _filter_tables {
         }
         else {
             warn "Bad table or view '$table', ignoring: $@\n";
-            local $@;
-            eval {
-                my $schema = $self->schema;
-                # in older DBIC it's a private method
-                my $unregister = $schema->can('unregister_source')
-                    || $schema->can('_unregister_source');
-                $schema->$unregister($self->_table2moniker($table));
-            };
+            $self->_unregister_source_for_table($table);
         }
     }
 
index 6557e07..0ecbda0 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use Test::More;
+use Test::Exception;
 use DBIx::Class::Schema::Loader;
 use Class::Unload;
 use File::Path;
@@ -87,7 +88,7 @@ sub run_tests {
 
     my $extra_count = $self->{extra}{count} || 0;
 
-    plan tests => @connect_info * (176 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
+    plan tests => @connect_info * (178 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
 
     foreach my $info_idx (0..$#connect_info) {
         my $info = $connect_info[$info_idx];
@@ -861,7 +862,7 @@ sub test_schema {
     }
 
     # rescan and norewrite test
-    SKIP: {
+    {
         my @statements_rescan = (
             qq{
                 CREATE TABLE loader_test30 (
@@ -924,13 +925,28 @@ sub test_schema {
         my $rsobj30   = $conn->resultset('LoaderTest30');
         isa_ok($rsobj30, 'DBIx::Class::ResultSet');
 
-        skip 'no rels', 2 if $self->{skip_rels};
+        SKIP: {
+            skip 'no rels', 2 if $self->{skip_rels};
+
+            my $obj30 = $rsobj30->find(123);
+            isa_ok( $obj30->loader_test2, $class2);
+
+            ok($rsobj30->result_source->column_info('loader_test2')->{is_foreign_key},
+               'Foreign key detected');
+        }
+
+        $conn->storage->disconnect; # for Firebird
+        $conn->storage->dbh->do("DROP TABLE loader_test30");
 
-        my $obj30 = $rsobj30->find(123);
-        isa_ok( $obj30->loader_test2, $class2);
+        @new = do {
+            local $SIG{__WARN__} = sub {};
+            $conn->rescan;
+        };
+        is_deeply(\@new, [], 'no new tables on rescan');
 
-        ok($rsobj30->result_source->column_info('loader_test2')->{is_foreign_key},
-           'Foreign key detected');
+        throws_ok { $conn->resultset('LoaderTest30') }
+            qr/Can't find source/,
+            'source unregistered for dropped table after rescan';
     }
 
     $self->test_data_types($conn);