make dump/populate work with mixed-case table names
[dbsrgits/DBIx-Class-Fixtures.git] / lib / DBIx / Class / Fixtures.pm
index 2d244b6..e44827e 100644 (file)
@@ -26,15 +26,15 @@ __PACKAGE__->mk_group_accessors( 'simple' => qw/config_dir
 
 =head1 VERSION
 
-Version 1.001008
+Version 1.001013
 
 =cut
 
-our $VERSION = '1.001008';
+our $VERSION = '1.001013';
 
 =head1 NAME
 
-DBIx::Class::Fixtures
+DBIx::Class::Fixtures - Dump data and repopulate a database using rules
 
 =head1 SYNOPSIS
 
@@ -425,7 +425,8 @@ sub new {
               _inherited_attributes => [qw/datetime_relative might_have rules belongs_to/],
               debug => $params->{debug} || 0,
               ignore_sql_errors => $params->{ignore_sql_errors},
-              dumped_objects => {}
+              dumped_objects => {},
+              use_create => $params->{use_create} || 0
   };
 
   bless $self, $class;
@@ -433,6 +434,22 @@ sub new {
   return $self;
 }
 
+=head2 available_config_sets
+
+Returns a list of all the config sets found in the L</config_dir>.  These will
+be a list of the json based files containing dump rules.
+
+=cut
+
+my @config_sets;
+sub available_config_sets {
+  @config_sets = scalar(@config_sets) ? @config_sets : map {
+    $_->basename;
+  } grep { 
+    -f $_ && $_=~/json$/;
+  } dir((shift)->config_dir)->children;
+}
+
 =head2 dump
 
 =over 4
@@ -465,7 +482,12 @@ directory. For example:
  /home/me/app/fixtures/artist/3.fix
  /home/me/app/fixtures/producer/5.fix
 
-schema and directory are required attributes. also, one of config or all must be specified.
+schema and directory are required attributes. also, one of config or all must
+be specified.
+
+Lastly, the C<config> parameter can be a Perl HashRef instead of a file name.
+If this form is used your HashRef should conform to the structure rules defined
+for the JSON representations.
 
 =cut
 
@@ -483,18 +505,32 @@ sub dump {
     }
   }
 
+  if($params->{excludes} && !$params->{all}) {
+    return DBIx::Class::Exception->throw("'excludes' param only works when using the 'all' param");
+  }
+
   my $schema = $params->{schema};
   my $config;
   if ($params->{config}) {
-    #read config
-    my $config_file = $self->config_dir->file($params->{config});
-    $config = $self->load_config_file($config_file);
+    $config = ref $params->{config} eq 'HASH' ? 
+      $params->{config} : 
+      do {
+        #read config
+        my $config_file = $self->config_dir->file($params->{config});
+        $self->load_config_file($config_file);
+      };
   } elsif ($params->{all}) {
+    my %excludes = map {$_=>1} @{$params->{excludes}||[]};
     $config = { 
       might_have => { fetch => 0 },
       has_many => { fetch => 0 },
       belongs_to => { fetch => 0 },
-      sets => [map {{ class => $_, quantity => 'all' }} $schema->sources] 
+      sets => [
+        map {
+          { class => $_, quantity => 'all' };
+        } grep {
+          !$excludes{$_}
+        } $schema->sources],
     };
   } else {
     DBIx::Class::Exception->throw('must pass config or set all');
@@ -676,7 +712,7 @@ sub dump_object {
 
 
   # write dir and gen filename
-  my $source_dir = $params->{set_dir}->subdir(lc $src->from);
+  my $source_dir = $params->{set_dir}->subdir($src->from);
   $source_dir->mkpath(0, 0777);
 
   # strip dir separators from file name
@@ -903,6 +939,79 @@ sub _read_sql {
   return \@data;
 }
 
+=head2 dump_config_sets
+
+Works just like L</dump> but instead of specifying a single json config set
+located in L</config_dir> we dump each set named in the C<configs> parameter.
+
+The parameters are the same as for L</dump> except instead of a C<directory>
+parameter we have a C<directory_template> which is a coderef expected to return
+a scalar that is a root directory where we will do the actual dumping.  This
+coderef get three arguments: C<$self>, C<$params> and C<$set_name>.  For
+example:
+
+    $fixture->dump_all_config_sets({
+      schema => $schema,
+      configs => [qw/one.json other.json/],
+      directory_template => sub {
+        my ($fixture, $params, $set) = @_;
+        return File::Spec->catdir('var', 'fixtures', $params->{schema}->version, $set);
+      },
+    });
+
+=cut
+
+sub dump_config_sets {
+  my ($self, $params) = @_;
+  my $available_config_sets = delete $params->{configs};
+  my $directory_template = delete $params->{directory_template} ||
+    DBIx::Class::Exception->throw("'directory_template is required parameter");
+
+  for my $set (@$available_config_sets) {
+    my $localparams = $params;
+    $localparams->{directory} = $directory_template->($self, $localparams, $set);
+    $localparams->{config} = $set;
+    $self->dump($localparams);
+    $self->dumped_objects({}); ## Clear dumped for next go, if there is one!
+  }
+}
+
+=head2 dump_all_config_sets
+
+    my %local_params = %$params;
+    my $local_self = bless { %$self }, ref($self);
+    $local_params{directory} = $directory_template->($self, \%local_params, $set);
+    $local_params{config} = $set;
+    $self->dump(\%local_params);
+
+
+Works just like L</dump> but instead of specifying a single json config set
+located in L</config_dir> we dump each set in turn to the specified directory.
+
+The parameters are the same as for L</dump> except instead of a C<directory>
+parameter we have a C<directory_template> which is a coderef expected to return
+a scalar that is a root directory where we will do the actual dumping.  This
+coderef get three arguments: C<$self>, C<$params> and C<$set_name>.  For
+example:
+
+    $fixture->dump_all_config_sets({
+      schema => $schema,
+      directory_template => sub {
+        my ($fixture, $params, $set) = @_;
+        return File::Spec->catdir('var', 'fixtures', $params->{schema}->version, $set);
+      },
+    });
+
+=cut
+
+sub dump_all_config_sets {
+  my ($self, $params) = @_;
+  $self->dump_config_sets({
+    %$params,
+    configs=>[$self->available_config_sets],
+  });
+}
+
 =head2 populate
 
 =over 4
@@ -932,6 +1041,11 @@ sub _read_sql {
    # optional, set to 1 to run ddl but not populate 
    no_populate => 0,
 
+       # optional, set to 1 to run each fixture through ->create rather than have
+   # each $rs populated using $rs->populate. Useful if you have overridden new() logic
+       # that effects the value of column(s).
+       use_create => 0,
+
    # Dont try to clean the database, just populate over whats there. Requires
    # schema option. Use this if you want to handle removing old data yourself
    # no_deploy => 1
@@ -1049,7 +1163,7 @@ sub populate {
       foreach my $source (sort $schema->sources) {
         $self->msg("- adding " . $source);
         my $rs = $schema->resultset($source);
-        my $source_dir = $tmp_fixture_dir->subdir( lc $rs->result_source->from );
+        my $source_dir = $tmp_fixture_dir->subdir( $rs->result_source->from );
         next unless (-e $source_dir);
         my @rows;
         while (my $file = $source_dir->next) {
@@ -1059,7 +1173,11 @@ sub populate {
           my $HASH1;
           eval($contents);
           $HASH1 = $fixup_visitor->visit($HASH1) if $fixup_visitor;
-          push(@rows, $HASH1);
+          if ( $params->{use_create} ) {
+            $rs->create( $HASH1 );
+          } else {
+            push(@rows, $HASH1);
+          }
         }
         $rs->populate(\@rows) if scalar(@rows);
       }