Switch cursor accessor to CAG's component_class type for autoloading
Justin Hunter [Mon, 28 Feb 2011 23:28:53 +0000 (15:28 -0800)]
Changes
lib/DBIx/Class.pm
lib/DBIx/Class/AccessorGroup.pm
lib/DBIx/Class/Storage.pm
t/04_c3_mro.t
t/39load_namespaces_stress.t [new file with mode: 0644]
t/cdbi/has_many_loads_foreign_class.t
t/lib/DBICTest/Cursor.pm [new file with mode: 0644]
t/resultset_class.t
t/storage/cursor.t [new file with mode: 0644]
xt/podcoverage.t

diff --git a/Changes b/Changes
index d18dea6..53da767 100644 (file)
--- a/Changes
+++ b/Changes
@@ -21,6 +21,8 @@ Revision history for DBIx::Class
           when deploying a schema via sql file
         - Fix reverse_relationship_info on prototypical result sources
           (sources not yet registered with a schema)
+        - Automatically require the requested cursor class before use
+          (RT#64795)
 
     * Misc
         - Only load Class::C3 and friends if necessary ($] < 5.010)
index e6cc6a7..86bc9b0 100644 (file)
@@ -19,7 +19,7 @@ use mro 'c3';
 use DBIx::Class::Optional::Dependencies;
 
 use vars qw($VERSION);
-use base qw/DBIx::Class::Componentised Class::Accessor::Grouped/;
+use base qw/DBIx::Class::Componentised DBIx::Class::AccessorGroup/;
 use DBIx::Class::StartupCheck;
 
 sub mk_classdata {
index 4d7e046..bd245e3 100644 (file)
@@ -5,6 +5,21 @@ use warnings;
 
 use base qw/Class::Accessor::Grouped/;
 
+our %successfully_loaded_components;
+
+sub get_component_class {
+  my $class = $_[0]->get_inherited($_[1]);
+  if (defined $class and ! $successfully_loaded_components{$class}) {
+    $_[0]->ensure_class_loaded($class);
+    $successfully_loaded_components{$class}++; # only increment if the load succeeded
+  }
+  $class;
+};
+
+sub set_component_class {
+  shift->set_inherited(@_);
+}
+
 1;
 
 =head1 NAME
index edfef85..dcc68bc 100644 (file)
@@ -13,7 +13,7 @@ use Try::Tiny;
 use namespace::clean;
 
 __PACKAGE__->mk_group_accessors('simple' => qw/debug schema/);
-__PACKAGE__->mk_group_accessors('inherited' => 'cursor_class');
+__PACKAGE__->mk_group_accessors('component_class' => 'cursor_class');
 
 __PACKAGE__->cursor_class('DBIx::Class::Cursor');
 
index 3224b5b..0c22bab 100644 (file)
@@ -51,6 +51,7 @@ is_deeply (
     DBIx::Class
     DBIx::Class::Componentised
     Class::C3::Componentised
+    DBIx::Class::AccessorGroup
     Class::Accessor::Grouped
   /],
   'Correctly ordered ISA of DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server'
diff --git a/t/39load_namespaces_stress.t b/t/39load_namespaces_stress.t
new file mode 100644 (file)
index 0000000..db178ee
--- /dev/null
@@ -0,0 +1,49 @@
+use strict;
+use warnings;
+use Test::More;
+use Time::HiRes qw/gettimeofday/;
+
+use lib qw(t/lib);
+use DBICTest; # do not remove even though it is not used
+
+our $src_count = 100;
+
+for (1 .. $src_count) {
+  eval <<EOM or die $@;
+
+  package DBICTest::NS::Stress::Schema::Result::T$_;
+  use base qw/DBIx::Class::Core/;
+  __PACKAGE__->table($_);
+  __PACKAGE__->add_columns (
+    id => { data_type => 'integer', is_auto_increment => 1 },
+    data => { data_type => 'varchar', size => 255 },
+  );
+  __PACKAGE__->set_primary_key('id');
+  __PACKAGE__->add_unique_constraint(['data']);
+
+EOM
+}
+
+{
+  package DBICTest::NS::Stress::Schema;
+
+  use base qw/DBIx::Class::Schema/;
+
+  sub _findallmod {
+    return $_[1] eq ( __PACKAGE__ . '::Result' )
+      ? ( map { __PACKAGE__ . "::Result::T$_" } 1 .. $::src_count )
+      : ()
+    ;
+  }
+}
+
+is (DBICTest::NS::Stress::Schema->sources, 0, 'Start with no sources');
+
+
+note gettimeofday . ":\tload_namespaces start";
+DBICTest::NS::Stress::Schema->load_namespaces;
+note gettimeofday . ":\tload_namespaces finished";
+
+is (DBICTest::NS::Stress::Schema->sources, $src_count, 'All sources attached');
+
+done_testing;
index e94a3ab..51cec5d 100644 (file)
@@ -1,6 +1,6 @@
 use strict;
 use Test::More;
-
+use Class::Inspector ();
 
 BEGIN {
   eval "use DBIx::Class::CDBICompat;";
diff --git a/t/lib/DBICTest/Cursor.pm b/t/lib/DBICTest/Cursor.pm
new file mode 100644 (file)
index 0000000..7f8873f
--- /dev/null
@@ -0,0 +1,7 @@
+package DBICTest::Cursor;
+
+use strict;
+use warnings;
+use base qw/DBIx::Class::Storage::DBI::Cursor/;
+
+1;
index 5aa7a92..607c1f2 100644 (file)
@@ -10,9 +10,12 @@ use DBICTest;
 
 is(DBICTest::Schema->source('Artist')->resultset_class, 'DBICTest::BaseResultSet', 'default resultset class');
 ok(!Class::Inspector->loaded('DBICNSTest::ResultSet::A'), 'custom resultset class not loaded');
+
 DBICTest::Schema->source('Artist')->resultset_class('DBICNSTest::ResultSet::A');
-ok(Class::Inspector->loaded('DBICNSTest::ResultSet::A'), 'custom resultset class loaded automatically');
+
+ok(!Class::Inspector->loaded('DBICNSTest::ResultSet::A'), 'custom resultset class not loaded on SET');
 is(DBICTest::Schema->source('Artist')->resultset_class, 'DBICNSTest::ResultSet::A', 'custom resultset class set');
+ok(Class::Inspector->loaded('DBICNSTest::ResultSet::A'), 'custom resultset class loaded on GET');
 
 my $schema = DBICTest->init_schema;
 my $resultset = $schema->resultset('Artist')->search;
diff --git a/t/storage/cursor.t b/t/storage/cursor.t
new file mode 100644 (file)
index 0000000..fb5f0cc
--- /dev/null
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+
+my $schema = DBICTest->init_schema(cursor_class => 'DBICTest::Cursor');
+
+lives_ok {
+  is($schema->resultset("Artist")->search(), 3, "Three artists returned");
+} 'Custom cursor autoloaded';
+
+done_testing;
index 022e320..caaeca4 100644 (file)
@@ -118,6 +118,7 @@ my $exceptions = {
     'DBIx::Class::Admin::*'                         => { skip => 1 },
     'DBIx::Class::ClassResolver::PassThrough'       => { skip => 1 },
     'DBIx::Class::Componentised'                    => { skip => 1 },
+    'DBIx::Class::AccessorGroup'                    => { skip => 1 },
     'DBIx::Class::Relationship::*'                  => { skip => 1 },
     'DBIx::Class::ResultSetProxy'                   => { skip => 1 },
     'DBIx::Class::ResultSourceProxy'                => { skip => 1 },