convert from the bottom up people/jnap/moo_replication
John Napiorkowski [Sat, 13 Nov 2010 01:14:41 +0000 (20:14 -0500)]
lib/DBIx/Class/Optional/Dependencies.pm
lib/DBIx/Class/Storage/DBI/Replicated.pm
lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm
lib/DBIx/Class/Storage/DBI/Replicated/Balancer/First.pm
lib/DBIx/Class/Storage/DBI/Replicated/Balancer/Random.pm
lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm
lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm
lib/DBIx/Class/Storage/DBI/Replicated/Types.pm
lib/DBIx/Class/Storage/DBI/Replicated/WithDSN.pm
t/storage/replicated.t

index 082ce79..1e4e9ba 100644 (file)
@@ -21,7 +21,6 @@ my $moose_basic = {
 };
 
 my $replicated = {
-  %$moose_basic,
 };
 
 my $admin_basic = {
@@ -82,13 +81,9 @@ my $reqs = {
   },
 
   test_replicated => {
-    req => {
-      %$replicated,
-      'Test::Moose'               => '0',
-    },
+    req => $replicated,
   },
 
-
   admin => {
     req => {
       %$admin_basic,
index 7857f08..8c9fd99 100644 (file)
@@ -1,5 +1,5 @@
 package DBIx::Class::Storage::DBI::Replicated;
-
 BEGIN {
   use Carp::Clan qw/^DBIx::Class/;
   use DBIx::Class;
@@ -7,19 +7,17 @@ BEGIN {
     unless DBIx::Class::Optional::Dependencies->req_ok_for ('replicated');
 }
 
-use Moose;
+use Moo;
+use Role::Tiny ();
 use DBIx::Class::Storage::DBI;
-use DBIx::Class::Storage::DBI::Replicated::Pool;
-use DBIx::Class::Storage::DBI::Replicated::Balancer;
-use DBIx::Class::Storage::DBI::Replicated::Types qw/BalancerClassNamePart DBICSchema DBICStorageDBI/;
-use MooseX::Types::Moose qw/ClassName HashRef Object/;
-use Scalar::Util 'reftype';
-use Hash::Merge;
-use List::Util qw/min max reduce/;
+use Scalar::Util qw(reftype blessed);
+use List::Util qw(min max reduce);
 use Try::Tiny;
-use namespace::clean;
-
-use namespace::clean -except => 'meta';
+use Sub::Name 'subname';
+use Class::Inspector;
+use DBIx::Class::Storage::DBI::Replicated::Types
+  qw(DBICSchema DBICStorageDBI ClassName HashRef Object 
+  DoesDBICStorageReplicatedBalancer DBICStorageDBIReplicatedPool Defined);
 
 =head1 NAME
 
@@ -117,10 +115,10 @@ The underlying L<DBIx::Class::Schema> object this storage is attaching
 =cut
 
 has 'schema' => (
-    is=>'rw',
-    isa=>DBICSchema,
-    weak_ref=>1,
-    required=>1,
+  is=>'rw',
+  isa=>DBICSchema,
+  weak_ref=>1,
+  required=>1,
 );
 
 =head2 pool_type
@@ -133,7 +131,7 @@ to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
 has 'pool_type' => (
   is=>'rw',
   isa=>ClassName,
-  default=>'DBIx::Class::Storage::DBI::Replicated::Pool',
+  default=> sub { 'DBIx::Class::Storage::DBI::Replicated::Pool'},
   handles=>{
     'create_pool' => 'new',
   },
@@ -148,7 +146,7 @@ See L<DBIx::Class::Storage::DBI::Replicated::Pool> for available arguments.
 
 has 'pool_args' => (
   is=>'rw',
-  isa=>HashRef,
+  isa =>HashRef,
   lazy=>1,
   default=>sub { {} },
 );
@@ -163,15 +161,19 @@ choose how to spread the query load across each replicant in the pool.
 
 has 'balancer_type' => (
   is=>'rw',
-  isa=>BalancerClassNamePart,
-  coerce=>1,
-  required=>1,
-  default=> 'DBIx::Class::Storage::DBI::Replicated::Balancer::First',
-  handles=>{
-    'create_balancer' => 'new',
-  },
+  isa=>Defined,
+  default=>sub { 'DBIx::Class::Storage::DBI::Replicated::Balancer::First' },
 );
 
+sub create_balancer {
+    my ($self, @args) = @_;
+    my $type = $self->balancer_type;
+    $type = 'DBIx::Class::Storage::DBI::Replicated::Balancer'.$type
+      if ($type=~m/^::/);
+    $self->schema->ensure_class_loaded($type);
+    return $type->new(@args);
+}
+
 =head2 balancer_args
 
 Contains a hashref of initialized information to pass to the Balancer object.
@@ -181,10 +183,9 @@ See L<DBIx::Class::Storage::DBI::Replicated::Balancer> for available arguments.
 
 has 'balancer_args' => (
   is=>'rw',
-  isa=>HashRef,
+  isa =>HashRef,
   lazy=>1,
-  required=>1,
-  default=>sub { {} },
+  default=>sub { +{} },
 );
 
 =head2 pool
@@ -196,12 +197,13 @@ container class for one or more replicated databases.
 
 has 'pool' => (
   is=>'ro',
-  isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
-  lazy_build=>1,
+  isa =>DBICStorageDBIReplicatedPool,
+  lazy=>1,
+  builder=>'_build_pool',
+  clearer=>'clear_pool',
   handles=>[qw/
     connect_replicants
     replicants
-    has_replicants
   /],
 );
 
@@ -214,8 +216,9 @@ is a class that takes a pool (L<DBIx::Class::Storage::DBI::Replicated::Pool>)
 
 has 'balancer' => (
   is=>'rw',
-  isa=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
-  lazy_build=>1,
+  isa => DoesDBICStorageReplicatedBalancer,
+  lazy=>1,
+  builder=>'_build_balancer',
   handles=>[qw/auto_validate_every/],
 );
 
@@ -231,8 +234,9 @@ pool of databases that is allowed to handle write traffic.
 
 has 'master' => (
   is=> 'ro',
-  isa=>DBICStorageDBI,
-  lazy_build=>1,
+  isa => DBICStorageDBI,
+  lazy=>1,
+  builder=>'_build_master',
 );
 
 =head1 ATTRIBUTES IMPLEMENTING THE DBIx::Storage::DBI INTERFACE
@@ -249,7 +253,8 @@ Defines an object that implements the read side of L<BIx::Class::Storage::DBI>.
 has 'read_handler' => (
   is=>'rw',
   isa=>Object,
-  lazy_build=>1,
+  lazy=>1,
+  builder=>'_build_read_handler',
   handles=>[qw/
     select
     select_single
@@ -271,7 +276,8 @@ run on a replicant.
 has 'write_handler' => (
   is=>'ro',
   isa=>Object,
-  lazy_build=>1,
+  lazy=>1,
+  builder=>'_build_write_handler',
   handles=>[qw/
     on_connect_do
     on_disconnect_do
@@ -303,7 +309,6 @@ has 'write_handler' => (
     with_deferred_fk_checks
     dbh_do
     reload_row
-    with_deferred_fk_checks
     _prep_for_execute
 
     backup
@@ -365,7 +370,9 @@ has 'write_handler' => (
 
 my @unimplemented = qw(
   _arm_global_destructor
+  _preserve_foreign_dbh
   _verify_pid
+  _verify_tid
 
   get_use_dbms_capability
   set_use_dbms_capability
@@ -377,27 +384,32 @@ my @unimplemented = qw(
 
   _inner_join_to_node
   _group_over_selection
-  _prefetch_autovalues
   _extract_order_criteria
-  _max_column_bytesize
   _is_lob_type
+  _max_column_bytesize
+  _prefetch_autovalues
 );
 
 # the capability framework
-# not sure if CMOP->initialize does evil things to DBIC::S::DBI, fix if a problem
 push @unimplemented, ( grep
   { $_ =~ /^ _ (?: use | supports | determine_supports ) _ /x }
-  ( Class::MOP::Class->initialize('DBIx::Class::Storage::DBI')->get_all_method_names )
+  @{Class::Inspector->methods('DBIx::Class::Storage::DBI')||[]}
 );
 
 for my $method (@unimplemented) {
-  __PACKAGE__->meta->add_method($method, sub {
-    croak "$method must not be called on ".(blessed shift).' objects';
-  });
+  { 
+    no strict qw/refs/;
+    *{__PACKAGE__ ."::$method"} = subname $method => sub {
+      croak "$method must not be called on ".(blessed shift).' objects';
+    };
+  }
 }
 
-has _master_connect_info_opts =>
-  (is => 'rw', isa => HashRef, default => sub { {} });
+has _master_connect_info_opts => (
+  is => 'rw',
+  isa =>HashRef ,
+  default => sub { +{} },
+);
 
 =head2 around: connect_info
 
@@ -456,9 +468,10 @@ around connect_info => sub {
   # Make sure master is blessed into the correct class and apply role to it.
   my $master = $self->master;
   $master->_determine_driver;
-  Moose::Meta::Class->initialize(ref $master);
 
-  DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($master);
+  ## Moose::Meta::Class->initialize(ref $master);
+  Role::Tiny->apply_roles_to_object($master, 'DBIx::Class::Storage::DBI::Replicated::WithDSN');
+  ## DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($master);
 
   # link pool back to master
   $self->pool->master($master);
@@ -470,7 +483,7 @@ around connect_info => sub {
 
 This class defines the following methods.
 
-=head2 BUILDARGS
+=head2 new
 
 L<DBIx::Class::Schema> when instantiating its storage passed itself as the
 first argument.  So we need to massage the arguments a bit so that all the
@@ -478,15 +491,15 @@ bits get put into the correct places.
 
 =cut
 
-sub BUILDARGS {
-  my ($class, $schema, $storage_type_args, @args) = @_;
-
-  return {
-    schema=>$schema,
+around 'new', sub {
+  my ($orig, $class, $schema, $storage_type_args, @args) = @_;
+  return $orig->(
+    $class,
+    schema => $schema,
     %$storage_type_args,
-    @args
-  }
-}
+    @args,
+  );
+};
 
 =head2 _build_master
 
@@ -497,7 +510,7 @@ Lazy builder for the L</master> attribute.
 sub _build_master {
   my $self = shift @_;
   my $master = DBIx::Class::Storage::DBI->new($self->schema);
-  $master
+  return $master;
 }
 
 =head2 _build_pool
@@ -1096,7 +1109,7 @@ using the Schema clone method.
 
 =head1 AUTHOR
 
-  John Napiorkowski <john.napiorkowski@takkle.com>
+  John Napiorkowski <jjnapiork@cpan.org>
 
 Based on code originated by:
 
@@ -1109,6 +1122,4 @@ You may distribute this code under the same terms as Perl itself.
 
 =cut
 
-__PACKAGE__->meta->make_immutable;
-
 1;
index 279ad51..6055107 100644 (file)
@@ -1,11 +1,11 @@
 package DBIx::Class::Storage::DBI::Replicated::Balancer;
 
-use Moose::Role;
+use Moo::Role;
+use Scalar::Util ();
+use DBIx::Class::Storage::DBI::Replicated::Types
+  qw(PositiveInteger DBICStorageDBI DBICStorageDBIReplicatedPool);
+
 requires 'next_storage';
-use MooseX::Types::Moose qw/Int/;
-use DBIx::Class::Storage::DBI::Replicated::Pool;
-use DBIx::Class::Storage::DBI::Replicated::Types qw/DBICStorageDBI/;
-use namespace::clean -except => 'meta';
 
 =head1 NAME
 
@@ -35,8 +35,9 @@ validating every query.
 
 has 'auto_validate_every' => (
   is=>'rw',
-  isa=>Int,
+  isa=>PositiveInteger,
   predicate=>'has_auto_validate_every',
+
 );
 
 =head2 master
@@ -62,7 +63,7 @@ balance.
 
 has 'pool' => (
   is=>'ro',
-  isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
+  isa=>DBICStorageDBIReplicatedPool,
   required=>1,
 );
 
@@ -82,7 +83,8 @@ via its balancer object.
 has 'current_replicant' => (
   is=> 'rw',
   isa=>DBICStorageDBI,
-  lazy_build=>1,
+  lazy=>1,
+  builder=>'_build_current_replicant',
   handles=>[qw/
     select
     select_single
@@ -101,7 +103,7 @@ Lazy builder for the L</current_replicant_storage> attribute.
 =cut
 
 sub _build_current_replicant {
-  my $self = shift @_;
+  my $self = shift;
   $self->next_storage;
 }
 
@@ -123,7 +125,7 @@ Advice on next storage to add the autovalidation.  We have this broken out so
 that it's easier to break out the auto validation into a role.
 
 This also returns the master in the case that none of the replicants are active
-or just just forgot to create them :)
+or just just for?blgot to create them :)
 
 =cut
 
@@ -161,7 +163,7 @@ Rolls the Storage to whatever is next in the queue, as defined by the Balancer.
 =cut
 
 sub increment_storage {
-  my $self = shift @_;
+  my $self = shift;
   my $next_replicant = $self->next_storage;
   $self->current_replicant($next_replicant);
 }
@@ -219,7 +221,7 @@ the load evenly (hopefully) across existing capacity.
 =cut
 
 before 'columns_info_for' => sub {
-  my $self = shift @_;
+  my $self = shift;
   $self->increment_storage;
 };
 
@@ -231,7 +233,7 @@ Given an identifier, find the most correct storage object to handle the query.
 
 sub _get_forced_pool {
   my ($self, $forced_pool) = @_;
-  if(blessed $forced_pool) {
+  if(Scalar::Util::blessed($forced_pool)) {
     return $forced_pool;
   } elsif($forced_pool eq 'master') {
     return $self->master;
index 806a05f..5ef4410 100644 (file)
@@ -1,8 +1,7 @@
 package DBIx::Class::Storage::DBI::Replicated::Balancer::First;
 
-use Moose;
+use Moo;
 with 'DBIx::Class::Storage::DBI::Replicated::Balancer';
-use namespace::clean -except => 'meta';
 
 =head1 NAME
 
@@ -41,7 +40,7 @@ sub next_storage {
 
 =head1 AUTHOR
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+John Napiorkowski <jjnapiork@cpan.org>
 
 =head1 LICENSE
 
@@ -49,6 +48,4 @@ You may distribute this code under the same terms as Perl itself.
 
 =cut
 
-__PACKAGE__->meta->make_immutable;
-
 1;
index 1fc7b94..72fa0b3 100644 (file)
@@ -1,9 +1,8 @@
 package DBIx::Class::Storage::DBI::Replicated::Balancer::Random;
 
-use Moose;
+use Moo;
+use DBIx::Class::Storage::DBI::Replicated::Types qw(PositiveNumber);
 with 'DBIx::Class::Storage::DBI::Replicated::Balancer';
-use DBIx::Class::Storage::DBI::Replicated::Types 'Weight';
-use namespace::clean -except => 'meta';
 
 =head1 NAME
 
@@ -20,10 +19,6 @@ Given a pool (L<DBIx::Class::Storage::DBI::Replicated::Pool>) of replicated
 database's (L<DBIx::Class::Storage::DBI::Replicated::Replicant>), defines a
 method by which query load can be spread out across each replicant in the pool.
 
-This Balancer uses L<List::Util> keyword 'shuffle' to randomly pick an active
-replicant from the associated pool.  This may or may not be random enough for
-you, patches welcome.
-
 =head1 ATTRIBUTES
 
 This class defines the following attributes.
@@ -43,7 +38,11 @@ any single replicant, if for example you have a very powerful master.
 
 =cut
 
-has master_read_weight => (is => 'rw', isa => Weight, default => sub { 0 });
+has master_read_weight => (
+  is => 'rw',
+  isa => PositiveNumber(err => sub {"weight must be a positive number, not $_[0]"}),
+  default => sub { 0 },
+);
 
 =head1 METHODS
 
@@ -58,8 +57,7 @@ be requested several times in a row.
 =cut
 
 sub next_storage {
-  my $self = shift @_;
-
+  my $self = shift;
   my @replicants = $self->pool->active_replicants;
 
   if (not @replicants) {
@@ -67,20 +65,19 @@ sub next_storage {
     return;
   }
 
-  my $master     = $self->master;
-
+  my $master = $self->master;
   my $rnd = $self->_random_number(@replicants + $self->master_read_weight);
 
   return $rnd >= @replicants ? $master : $replicants[int $rnd];
 }
 
 sub _random_number {
-  rand($_[1])
+  rand($_[1]);
 }
 
 =head1 AUTHOR
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+John Napiorkowski <jjnapiork@cpan.org>
 
 =head1 LICENSE
 
@@ -88,6 +85,4 @@ You may distribute this code under the same terms as Perl itself.
 
 =cut
 
-__PACKAGE__->meta->make_immutable;
-
 1;
index 7ce7de9..aaaa823 100644 (file)
@@ -1,16 +1,14 @@
 package DBIx::Class::Storage::DBI::Replicated::Pool;
 
-use Moose;
-use DBIx::Class::Storage::DBI::Replicated::Replicant;
-use List::Util 'sum';
-use Scalar::Util 'reftype';
+use Moo;
+use Role::Tiny ();
+use List::Util ();
+use Scalar::Util qw(reftype);
 use DBI ();
 use Carp::Clan qw/^DBIx::Class/;
-use MooseX::Types::Moose qw/Num Int ClassName HashRef/;
-use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
 use Try::Tiny;
-
-use namespace::clean -except => 'meta';
+use DBIx::Class::Storage::DBI::Replicated::Types
+  qw(PositiveInteger Number DBICStorageDBI ClassName HashRef);
 
 =head1 NAME
 
@@ -44,10 +42,9 @@ return a number of seconds that the replicating database is lagging.
 
 has 'maximum_lag' => (
   is=>'rw',
-  isa=>Num,
-  required=>1,
+  isa=>Number,
   lazy=>1,
-  default=>0,
+  default=>sub {0},
 );
 
 =head2 last_validated
@@ -60,11 +57,9 @@ built-in.
 
 has 'last_validated' => (
   is=>'rw',
-  isa=>Int,
-  reader=>'last_validated',
-  writer=>'_last_validated',
+  isa=>PositiveInteger,
   lazy=>1,
-  default=>0,
+  default=>sub {0},
 );
 
 =head2 replicant_type ($classname)
@@ -78,8 +73,7 @@ just leave this alone.
 has 'replicant_type' => (
   is=>'ro',
   isa=>ClassName,
-  required=>1,
-  default=>'DBIx::Class::Storage::DBI',
+  default=> sub{'DBIx::Class::Storage::DBI'},
   handles=>{
     'create_replicant' => 'new',
   },  
@@ -87,7 +81,7 @@ has 'replicant_type' => (
 
 =head2 replicants
 
-A hashref of replicant, with the key being the dsn and the value returning the
+A hashref of replicants, with the key being the dsn and the value returning the
 actual replicant storage.  For example, if the $dsn element is something like:
 
   "dbi:SQLite:dbname=dbfile"
@@ -96,71 +90,38 @@ You could access the specific replicant via:
 
   $schema->storage->replicants->{'dbname=dbfile'}
 
-This attributes also supports the following helper methods:
-
-=over 4
-
-=item set_replicant($key=>$storage)
-
-Pushes a replicant onto the HashRef under $key
-
-=item get_replicant($key)
-
-Retrieves the named replicant
-
-=item has_replicants
-
-Returns true if the Pool defines replicants.
-
-=item num_replicants
-
-The number of replicants in the pool
-
-=item delete_replicant ($key)
-
-Removes the replicant under $key from the pool
-
-=back
-
 =cut
 
 has 'replicants' => (
-  is=>'rw',
-  traits => ['Hash'],
-  isa=>HashRef['Object'],
-  default=>sub {{}},
-  handles  => {
-    'set_replicant' => 'set',
-    'get_replicant' => 'get',
-    'has_replicants' => 'is_empty',
-    'num_replicants' => 'count',
-    'delete_replicant' => 'delete',
-    'all_replicant_storages' => 'values',
-  },
+  is => 'rw',
+  isa => HashRef,
+  default => sub { +{} },
 );
 
-around has_replicants => sub {
-    my ($orig, $self) = @_;
-    return !$self->$orig;
-};
-
 has next_unknown_replicant_id => (
   is => 'rw',
-  traits => ['Counter'],
-  isa => Int,
-  default => 1,
-  handles => {
-    'inc_unknown_replicant_id' => 'inc',
-  },
+  isa=>PositiveInteger
+  default => sub { 1 },
 );
 
+sub inc_unknown_replicant_id {
+    my $self = shift;
+    my $next = $self->next_unknown_replicant_id + 1;
+    $self->next_unknown_replicant_id($next);
+    return $next;
+}
+
 =head2 master
 
 Reference to the master Storage.
 
 =cut
 
-has master => (is => 'rw', isa => DBICStorageDBI, weak_ref => 1);
+has master => (
+  is => 'rw',
+  isa =>DBICStorageDBI,
+  weak_ref => 1,
+);
 
 =head1 METHODS
 
@@ -190,8 +151,8 @@ sub connect_replicants {
 
     my $dsn;
     my $replicant = do {
-# yes this is evil, but it only usually happens once (for coderefs)
-# this will fail if the coderef does not actually DBI::connect
+      ## yes this is evil, but it only usually happens once (for coderefs)
+      ## this will fail if the coderef does not actually DBI::connect
       no warnings 'redefine';
       my $connect = \&DBI::connect;
       local *DBI::connect = sub {
@@ -219,8 +180,17 @@ sub connect_replicants {
       ($key) = ($dsn =~ m/^dbi\:.+\:(.+)$/i);
     }
 
-    $replicant->id($key);
-    $self->set_replicant($key => $replicant);  
+    if($key) {
+      $replicant->id($key);
+    } else {
+      $replicant->debugobj->print("Could not create an ID for the replicant!");
+    }
+
+    ## Add the new replicant to the list
+    $self->replicants({
+        $key => $replicant,
+        %{$self->replicants},
+    });  
 
     push @newly_created, $replicant;
   }
@@ -240,7 +210,7 @@ sub connect_replicant {
   my $replicant = $self->create_replicant($schema);
   $replicant->connect_info($connect_info);
 
-## It is undesirable for catalyst to connect at ->conect_replicants time, as
+## It is undesirable for catalyst to connect at ->connect_replicants time, as
 ## connections should only happen on the first request that uses the database.
 ## So we try to set the driver without connecting, however this doesn't always
 ## work, as a driver may need to connect to determine the DB version, and this
@@ -253,9 +223,7 @@ sub connect_replicant {
     $replicant->_determine_driver
   });
 
-  Moose::Meta::Class->initialize(ref $replicant);
-
-  DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);
+  Role::Tiny->apply_roles_to_object($replicant, 'DBIx::Class::Storage::DBI::Replicated::Replicant');
 
   # link back to master
   $replicant->master($self->master);
@@ -324,7 +292,7 @@ is actually connected, try not to hit this 10 times a second.
 
 sub connected_replicants {
   my $self = shift @_;
-  return sum( map {
+  return List::Util::sum( map {
     $_->connected ? 1:0
   } $self->all_replicants );
 }
@@ -408,12 +376,12 @@ sub validate_replicants {
     }
   }
   ## Mark that we completed this validation.  
-  $self->_last_validated(time);  
+  $self->last_validated(time);  
 }
 
 =head1 AUTHOR
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+John Napiorkowski <jjnapiork@cpan.org>
 
 =head1 LICENSE
 
@@ -421,6 +389,4 @@ You may distribute this code under the same terms as Perl itself.
 
 =cut
 
-__PACKAGE__->meta->make_immutable;
-
 1;
index a541e7d..b18675c 100644 (file)
@@ -1,12 +1,11 @@
 package DBIx::Class::Storage::DBI::Replicated::Replicant;
 
-use Moose::Role;
+use Moo::Role;
+use DBIx::Class::Storage::DBI::Replicated::Types
+  qw(Boolean DBICStorageDBI Defined);
+
 requires qw/_query_start/;
 with 'DBIx::Class::Storage::DBI::Replicated::WithDSN';
-use MooseX::Types::Moose qw/Bool Str/;
-use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
-
-use namespace::clean -except => 'meta';
 
 =head1 NAME
 
@@ -47,14 +46,14 @@ storage driver for more information.
 
 has 'active' => (
   is=>'rw',
-  isa=>Bool,
+  isa=>Boolean,
   lazy=>1,
   required=>1,
-  default=>1,
+  default=> sub {1},
 );
 
-has dsn => (is => 'rw', isa => Str);
-has id  => (is => 'rw', isa => Str);
+has dsn => (is => 'rw', isa => Defined(err=>sub{"'dsn' must be defined"}));
+has id  => (is => 'rw', isa => Defined(err=>sub{"'id' must be defined"}));
 
 =head2 master
 
@@ -62,7 +61,11 @@ Reference to the master Storage.
 
 =cut
 
-has master => (is => 'rw', isa => DBICStorageDBI, weak_ref => 1);
+has master => (
+  is => 'rw',
+  isa =>DBICStorageDBI,
+  weak_ref => 1,
+);
 
 =head1 METHODS
 
@@ -75,9 +78,7 @@ Override the debugobj method to redirect this method call back to the master.
 =cut
 
 sub debugobj {
-  my $self = shift;
-
-  return $self->master->debugobj;
+  (shift)->master->debugobj;
 }
 
 =head1 ALSO SEE
@@ -87,7 +88,7 @@ L<DBIx::Class::Storage::DBI::Replicated>
 
 =head1 AUTHOR
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+John Napiorkowski <jjnapiork@cpan.org>
 
 =head1 LICENSE
 
index 4e75aa2..c2b38da 100644 (file)
 package # hide from PAUSE
   DBIx::Class::Storage::DBI::Replicated::Types;
 
-# DBIx::Class::Storage::DBI::Replicated::Types - Types used internally by
-# L<DBIx::Class::Storage::DBI::Replicated>
+use strict;
+use warnings;
+use Carp qw(confess);
 
-use MooseX::Types
-  -declare => [qw/BalancerClassNamePart Weight DBICSchema DBICStorageDBI/];
-use MooseX::Types::Moose qw/ClassName Str Num/;
+use Scalar::Util qw(blessed looks_like_number reftype);
 
-class_type 'DBIx::Class::Storage::DBI';
-class_type 'DBIx::Class::Schema';
+sub import {
+  my ($package, @methods) = @_;
+  my $caller = caller;
+  for my $method (@methods) {
+    { no strict;
+      *{"${caller}::${method}"} = sub {
+        my %args = @_;
+        sub { my $value = shift; &{$method}($value, %args) }
+      };
+    }
+  }
+}
 
-subtype DBICSchema, as 'DBIx::Class::Schema';
-subtype DBICStorageDBI, as 'DBIx::Class::Storage::DBI';
+sub error {
+  my ($default, $value, %args) = @_;
+  if(my $err = $args{err}) {
+    confess $err->($value);
+  } else {
+    confess $default;
+  }
+}
 
-subtype BalancerClassNamePart,
-  as ClassName;
+sub Defined {
+  error("Value $_[0] must be Defined", @_)
+    unless defined($_[0]);
+}
 
-coerce BalancerClassNamePart,
-  from Str,
-  via {
-    my $type = $_;
-    if($type=~m/^::/) {
-      $type = 'DBIx::Class::Storage::DBI::Replicated::Balancer'.$type;
-    }
-    Class::MOP::load_class($type);
-    $type;
-  };
-
-subtype Weight,
-  as Num,
-  where { $_ >= 0 },
-  message { 'weight must be a decimal greater than 0' };
-
-# AUTHOR
-#
-#  John Napiorkowski <john.napiorkowski@takkle.com>
-#
-# LICENSE
-#
-#  You may distribute this code under the same terms as Perl itself.
+sub UnDefined {
+  error("Value $_[0] must be UnDefined", @_)
+    unless !defined($_[0]);
+}
+
+sub Boolean {
+  error("$_[0] is not a valid Boolean", @_)
+    unless(!defined($_[0]) || $_[0] eq "" || "$_[0]" eq '1' || "$_[0]" eq '0');
+}
+
+sub Number {
+  error("weight must be a Number greater than or equal to 0, not $_[0]", @_)
+    unless(Defined(@_) && looks_like_number($_[0]));
+}
+
+sub Integer {
+  error("$_[0] must be an Integer", @_)
+    unless(Number(@_) && (int($_[0]) == $_[0]));
+}
+
+sub HashRef {
+  error("$_[0] must be a HashRef", @_)
+    unless(Defined(@_) && (reftype($_[0]) eq 'HASH'));
+}
+
+sub PositiveNumber {
+  error("value must be a Number greater than or equal to 0, not $_[0]", @_)
+    unless(Number(@_) && ($_[0] >= 0));
+}
+
+sub PositiveInteger {
+  error("Value must be a Number greater than or equal to 0, not $_[0]", @_)
+    unless(Integer(@_) && ($_[0] >= 0));
+}
+
+sub ClassName {
+  error("$_[0] is not a loaded Class", @_)
+    unless(Defined(@_) && ($_[0]->can('can')));
+}
+
+sub Object {
+  error("Value is not an Object", @_)
+    unless(Defined(@_) && blessed($_[0]));
+}
+
+sub DBICStorageDBI {
+  error("Need an Object of type DBIx::Class::Storage::DBI, not ".ref($_[0]), @_)
+    unless(Object(@_) && ($_[0]->isa('DBIx::Class::Storage::DBI')));
+}
+
+sub DBICStorageDBIReplicatedPool {
+  error("Need an Object of type DBIx::Class::Storage::DBI::Replicated::Pool, not ".ref($_[0]), @_)
+    unless(Object(@_) && ($_[0]->isa('DBIx::Class::Storage::DBI::Replicated::Pool')));
+}
+
+sub DBICSchema {
+  error("Need an Object of type DBIx::Class::Schema, not ".ref($_[0]), @_)
+    unless(Object(@_) && ($_[0]->isa('DBIx::Class::Schema')));
+}
+
+sub DoesDBICStorageReplicatedBalancer {
+  error("$_[0] does not do DBIx::Class::Storage::DBI::Replicated::Balancer", @_)
+    unless(Object(@_) && $_[0]->does('DBIx::Class::Storage::DBI::Replicated::Balancer') );
+}
 
 1;
+
index f26eb3c..b389ce2 100644 (file)
@@ -1,12 +1,10 @@
 package DBIx::Class::Storage::DBI::Replicated::WithDSN;
 
-use Moose::Role;
-use Scalar::Util 'reftype';
+use Try::Tiny qw(try);
+use Scalar::Util ();
+use Role::Tiny;
 requires qw/_query_start/;
 
-use Try::Tiny;
-use namespace::clean -except => 'meta';
-
 =head1 NAME
 
 DBIx::Class::Storage::DBI::Replicated::WithDSN - A DBI Storage Role with DSN
@@ -39,7 +37,7 @@ around '_query_start' => sub {
   my $storage_type = $self->can('active') ? 'REPLICANT' : 'MASTER';
 
   my $query = do {
-    if ((reftype($dsn)||'') ne 'CODE') {
+    if ((Scalar::Util::reftype($dsn)||'') ne 'CODE') {
       "$op [DSN_$storage_type=$dsn]$rest";
     }
     elsif (my $id = try { $self->id }) {
@@ -59,7 +57,7 @@ L<DBIx::Class::Storage::DBI>
 
 =head1 AUTHOR
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+John Napiorkowski <jjnapiork@cpan.org>
 
 =head1 LICENSE
 
index 3f813aa..7e903be 100644 (file)
@@ -4,20 +4,17 @@ use warnings;
 use Test::More;
 
 BEGIN {
-    require DBIx::Class;
-    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_replicated')
-      unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_replicated');
+  require DBIx::Class;
+  plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_replicated')
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_replicated');
 }
 
-use Test::Moose;
 use Test::Exception;
 use List::Util 'first';
 use Scalar::Util 'reftype';
 use File::Spec;
 use IO::Handle;
-use Moose();
-use MooseX::Types();
-note "Using Moose version $Moose::VERSION and MooseX::Types version $MooseX::Types::VERSION";
+use Class::Inspector;
 
 use lib qw(t/lib);
 use DBICTest;
@@ -29,15 +26,13 @@ use_ok 'DBIx::Class::Storage::DBI::Replicated::Balancer';
 use_ok 'DBIx::Class::Storage::DBI::Replicated::Replicant';
 use_ok 'DBIx::Class::Storage::DBI::Replicated';
 
-
 =head1 HOW TO USE
 
     This is a test of the replicated storage system.  This will work in one of
     two ways, either it was try to fake replication with a couple of SQLite DBs
     and creative use of copy, or if you define a couple of %ENV vars correctly
     will try to test those.  If you do that, it will assume the setup is properly
-    replicating.  Your results may vary, but I have demonstrated this to work with
-    mysql native replication.
+    replicating.  
 
 =cut
 
@@ -66,6 +61,7 @@ TESTSCHEMACLASSES: {
         my $self = $class->SUPER::new(@_);
 
         $self->schema( $self->init_schema($schema_method) );
+
         return $self;
     }
 
@@ -107,8 +103,8 @@ TESTSCHEMACLASSES: {
         storage_type=> '::DBI::Replicated',
         balancer_type=>'::Random',
         balancer_args=> {
-            auto_validate_every=>100,
-            master_read_weight => 1
+          auto_validate_every=>100,
+          master_read_weight => 1
         },
         pool_args=>{
             maximum_lag=>1,
@@ -126,22 +122,18 @@ TESTSCHEMACLASSES: {
     ## --------------------------------------------------------------------- ##
     ## Add a connect_info option to test option merging.
     ## --------------------------------------------------------------------- ##
+
     {
     package DBIx::Class::Storage::DBI::Replicated;
 
-    use Moose;
-
-    __PACKAGE__->meta->make_mutable;
-
+    use Moo;
     around connect_info => sub {
       my ($next, $self, $info) = @_;
       $info->[3]{master_option} = 1;
       $self->$next($info);
     };
 
-    __PACKAGE__->meta->make_immutable;
-
-    no Moose;
+    no Moo;
     }
 
     ## --------------------------------------------------------------------- ##
@@ -262,6 +254,7 @@ my $replicated;
 
 for my $method (qw/by_connect_info by_storage_type/) {
   undef $replicated;
+
   ok $replicated = $replicated_class->new($method)
       => "Created a replication object $method";
 
@@ -276,67 +269,45 @@ for my $method (qw/by_connect_info by_storage_type/) {
       => 'configured balancer_type';
 }
 
-### check that all Storage::DBI methods are handled by ::Replicated
+## Check that all Storage::DBI methods are handled by ::Replicated
 {
-  my @storage_dbi_methods = Class::MOP::Class
-    ->initialize('DBIx::Class::Storage::DBI')->get_all_method_names;
-
-  my @replicated_methods  = DBIx::Class::Storage::DBI::Replicated->meta
-    ->get_all_method_names;
+  ## Get a bunch of methods to check
+  my @storage_dbi_methods = @{Class::Inspector->methods('DBIx::Class::Storage::DBI')||[]};
 
-# remove constants and OTHER_CRAP
+  ## remove constants and OTHER_CRAP
   @storage_dbi_methods = grep !/^[A-Z_]+\z/, @storage_dbi_methods;
 
-# remove CAG accessors
+  ## remove CAG accessors
   @storage_dbi_methods = grep !/_accessor\z/, @storage_dbi_methods;
 
-# remove DBIx::Class (the root parent, with CAG and stuff) methods
-  my @root_methods = Class::MOP::Class->initialize('DBIx::Class')
-    ->get_all_method_names;
-  my %count;
-  $count{$_}++ for (@storage_dbi_methods, @root_methods);
+  ## we need to exclude this stuff as well
+  my %root_methods = map { $_ => 1 } @{Class::Inspector->methods('DBIx::Class')};
 
-  @storage_dbi_methods = grep $count{$_} != 2, @storage_dbi_methods;
+  @storage_dbi_methods = grep { !$root_methods{$_} } @storage_dbi_methods;
 
-# make hashes
-  my %storage_dbi_methods;
-  @storage_dbi_methods{@storage_dbi_methods} = ();
-  my %replicated_methods;
-  @replicated_methods{@replicated_methods} = ();
-
-# remove ::Replicated-specific methods
-  for my $method (@replicated_methods) {
-    delete $replicated_methods{$method}
-      unless exists $storage_dbi_methods{$method};
+  ## anything missing?
+  my @missing_methods;
+  for my $method (@storage_dbi_methods) {
+    push @missing_methods, $method
+      unless $replicated->schema->storage->can($method);
   }
-  @replicated_methods = keys %replicated_methods;
-
-# check that what's left is implemented
-  %count = ();
-  $count{$_}++ for (@storage_dbi_methods, @replicated_methods);
 
-  if ((grep $count{$_} == 2, @storage_dbi_methods) == @storage_dbi_methods) {
+  if(scalar(@missing_methods)) {
+    my $missing = join (',', @missing_methods);
+    fail "the following DBIx::Class::Storage::DBI methods are unimplemented: $missing";
+  } else {
     pass 'all DBIx::Class::Storage::DBI methods implemented';
-  }
-  else {
-    my @unimplemented = grep $count{$_} == 1, @storage_dbi_methods;
-
-    fail 'the following DBIx::Class::Storage::DBI methods are unimplemented: '
-      . "@unimplemented";
-  }
+  }  
 }
 
-ok $replicated->schema->storage->meta
-    => 'has a meta object';
-
 isa_ok $replicated->schema->storage->master
     => 'DBIx::Class::Storage::DBI';
 
 isa_ok $replicated->schema->storage->pool
     => 'DBIx::Class::Storage::DBI::Replicated::Pool';
 
-does_ok $replicated->schema->storage->balancer
-    => 'DBIx::Class::Storage::DBI::Replicated::Balancer';
+ok  $replicated->schema->storage->balancer->does('DBIx::Class::Storage::DBI::Replicated::Balancer'),
+  'does Balancer';
 
 ok my @replicant_connects = $replicated->generate_replicant_connect_info
     => 'got replication connect information';
@@ -372,9 +343,8 @@ my @all_storage_opts =
   grep { (reftype($_)||'') eq 'HASH' }
     map @{ $_->_connect_info }, @all_storages;
 
-is ((grep $_->{master_option}, @all_storage_opts),
-    3
-    => 'connect_info was merged from master to replicants');
+  is ((grep $_->{master_option}, @all_storage_opts), 3,
+    'connect_info was merged from master to replicants');
 
 my @replicant_names = keys %{ $replicated->schema->storage->replicants };
 
@@ -390,23 +360,26 @@ isa_ok $replicated->schema->storage->balancer->current_replicant
 
 $replicated->schema->storage->debugobj->silence(0);
 
-ok $replicated->schema->storage->pool->has_replicants
+ok scalar(keys(%{$replicated->schema->storage->pool->replicants}))
     => 'does have replicants';
 
-is $replicated->schema->storage->pool->num_replicants => 2
+is scalar(keys(%{$replicated->schema->storage->pool->replicants})), 2
     => 'has two replicants';
 
-does_ok $replicated_storages[0]
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
 
-does_ok $replicated_storages[1]
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+ok $replicated_storages[0]->does('DBIx::Class::Storage::DBI::Replicated::Replicant'),
+  'does Replicant';
+
+ok $replicated_storages[1]->does('DBIx::Class::Storage::DBI::Replicated::Replicant'),
+  'does Replicant';
 
-does_ok $replicated->schema->storage->replicants->{$replicant_names[0]}
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+ok $replicated->schema->storage->replicants->{$replicant_names[0]}
+    ->does('DBIx::Class::Storage::DBI::Replicated::Replicant'),
+    'Does Replicant';
 
-does_ok $replicated->schema->storage->replicants->{$replicant_names[1]}
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+ok $replicated->schema->storage->replicants->{$replicant_names[1]}
+    ->does('DBIx::Class::Storage::DBI::Replicated::Replicant'),
+    'Does Replicant';
 
 ## Add some info to the database