populate code added
Luke Saunders [Thu, 31 Jan 2008 16:46:48 +0000 (16:46 +0000)]
lib/DBIx/Class/Fixtures.pm
lib/DBIx/Class/Fixtures/Schema.pm [new file with mode: 0644]
lib/DBIx/Class/Fixtures/SchemaVersioned.pm [new file with mode: 0644]
t/var/configs/fetch.json [new file with mode: 0644]
t/var/configs/quantity.json [new file with mode: 0644]
t/var/configs/rules.json [new file with mode: 0644]

index 6fd5651..dd57bcf 100644 (file)
@@ -301,6 +301,142 @@ sub dump_object {
   }
 }
 
+sub _generate_schema {
+  my $self = shift;
+  my $params = shift || {};
+
+  require DBI;
+  $self->msg("\ncreating schema");
+  #   die 'must pass version param to generate_schema_from_ddl' unless $params->{version};
+
+  my $dbh;
+  unless ($dbh = DBI->connect(@{$params->{connection_details}})) {
+    return DBIx::Class::Exception->throw('connection details not valid');
+  }
+  my $connection_details = $params->{connection_details};
+
+  # clear existing db
+  $self->msg("- clearing DB of existing tables");
+  $dbh->do('SET foreign_key_checks=0');
+  my $sth = $dbh->prepare('SHOW TABLES');
+  $sth->execute;
+  my $rows = $sth->fetchall_arrayref;
+  $dbh->do('drop table ' . $_->[0]) for (@{$rows});
+
+  # import new ddl file to db
+  my $ddl_file = $params->{ddl};
+  $self->msg("- deploying schema using $ddl_file");
+  my $fh;
+  open $fh, "<$ddl_file" or die ("Can't open DDL file, $ddl_file ($!)");
+  my @data = split(/\n/, join('', <$fh>));
+  @data = grep(!/^--/, @data);
+  @data = split(/;/, join('', @data));
+  close($fh);
+  @data = grep { $_ && $_ !~ /^-- / } @data;
+  for (@data) {
+      eval { $dbh->do($_) or warn "SQL was:\n $_"};
+         if ($@) { die "SQL was:\n $_\n$@"; }
+  }
+  $dbh->do('SET foreign_key_checks=1');
+  $self->msg("- finished importing DDL into DB");
+
+  # load schema object from our new DB
+  $self->msg("- loading fresh DBIC object from DB");
+  my $schema = DBIx::Class::Fixtures::Schema->connect(@{$connection_details});
+
+  # manually set the version then set DB version to it (upgrade)
+#   $Takkle::SchemaPopulate::VERSION = $params->{version};
+#   $schema->upgrade(); # set version number  
+  return $schema;
+}
+
+sub populate {
+  my $self = shift;
+  my ($params) = @_;
+  unless (ref $params eq 'HASH') {
+    return DBIx::Class::Exception->throw('first arg to populate must be hash ref');
+  }
+
+  foreach my $param (qw/directory/) {
+    unless ($params->{$param}) {
+      return DBIx::Class::Exception->throw($param . ' param not specified');
+    }
+  }
+  my $fixture_dir = dir($params->{directory});
+  unless (-e $fixture_dir) {
+    return DBIx::Class::Exception->throw('fixture directory does not exist at ' . $fixture_dir);
+  }
+
+  my $ddl_file;
+  my $dbh;  
+  if ($params->{ddl} && $params->{connection_details}) {
+    my $ddl_file = file($params->{ddl});
+    unless (-e $ddl_file) {
+      return DBIx::Class::Exception->throw('DDL does not exist at ' . $ddl_file);
+    }
+    unless (ref $params->{connection_details} eq 'ARRAY') {
+      return DBIx::Class::Exception->throw('connection details must be an arrayref');
+    }
+  } elsif ($params->{schema}) {
+    return DBIx::Class::Exception->throw('passing a schema is not supported at the moment');
+  } else {
+    return DBIx::Class::Exception->throw('you must set the ddl and connection_details params');
+  }
+
+  my $schema = $self->_generate_schema({ ddl => $ddl_file, connection_details => $params->{connection_details} });
+  $self->msg("importing fixtures");
+
+  my $tmp_fixture_dir = dir($fixture_dir, "-~populate~-" . $<);
+
+  my $version_file = file($fixture_dir, '_dumper_version');
+  unless (-e $version_file) {
+#     return DBIx::Class::Exception->throw('no version file found');
+  }
+
+  if (-e $tmp_fixture_dir) {
+    $self->msg("- deleting existing temp directory $tmp_fixture_dir");
+    system("rm -rf $tmp_fixture_dir");
+  }
+  $self->msg("- creating temp dir");
+  system("cp -r $fixture_dir $tmp_fixture_dir");
+
+  $schema->storage->dbh->do('SET foreign_key_checks=0');
+  my $fixup_visitor;
+  my %callbacks;
+  if ($params->{datetime_relative_to}) {
+    $callbacks{'DateTime::Duration'} = sub {
+      $params->{datetime_relative_to}->clone->add_duration($_);
+    };
+  } else {
+    $callbacks{'DateTime::Duration'} = sub {
+      DateTime->today->add_duration($_)
+    };
+  }
+  $callbacks{object} ||= "visit_ref";  
+  $fixup_visitor = new Data::Visitor::Callback(%callbacks);
+
+  foreach my $source (sort $schema->sources) {
+    $self->msg("- adding " . $source);
+    my $rs = $schema->resultset($source);
+    my $source_dir = dir($tmp_fixture_dir, lc($rs->result_source->from));
+    next unless (-e $source_dir);
+    while (my $file = $source_dir->next) {
+      next unless ($file =~ /\.fix$/);
+      next if $file->is_dir;
+      my $contents = $file->slurp;
+      my $HASH1;
+      eval($contents);
+      $HASH1 = $fixup_visitor->visit($HASH1) if $fixup_visitor;
+      $rs->find_or_create($HASH1);
+    }
+  }
+
+  $self->msg("- fixtures imported");
+  $self->msg("- cleaning up");
+  $tmp_fixture_dir->rmtree;
+  $schema->storage->dbh->do('SET foreign_key_checks=1');
+}
+
 sub msg {
   my $self = shift;
   my $subject = shift || return;
diff --git a/lib/DBIx/Class/Fixtures/Schema.pm b/lib/DBIx/Class/Fixtures/Schema.pm
new file mode 100644 (file)
index 0000000..3d7ae67
--- /dev/null
@@ -0,0 +1,10 @@
+package DBIx::Class::Fixtures::Schema;
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Schema::Loader';
+
+__PACKAGE__->loader_options( );
+
+1;
diff --git a/lib/DBIx/Class/Fixtures/SchemaVersioned.pm b/lib/DBIx/Class/Fixtures/SchemaVersioned.pm
new file mode 100644 (file)
index 0000000..f05d110
--- /dev/null
@@ -0,0 +1,15 @@
+package DBIx::Class::Fixtures::SchemaVersioned;
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Schema::Loader';
+
+our $VERSION = 'set-when-loading';
+
+__PACKAGE__->load_components('Schema::Versioned');
+__PACKAGE__->loader_options(
+                            # debug                 => 1,
+                           );
+
+1;
diff --git a/t/var/configs/fetch.json b/t/var/configs/fetch.json
new file mode 100644 (file)
index 0000000..30d6685
--- /dev/null
@@ -0,0 +1,23 @@
+{
+        might_have: {
+            fetch: 0
+        },
+        has_many: {
+            fetch: 0
+        },
+        sets: [{
+            class: 'Artist',
+            ids: ['1'],
+            fetch: [{
+                rel: cds,
+                quantity: all
+            }]
+        }, {
+            class: 'Artist',
+            ids: ['2'],
+            fetch: [{
+                rel: cds,
+                cond: { year: {'>': 2002} }
+            }]
+        }]
+}
\ No newline at end of file
diff --git a/t/var/configs/quantity.json b/t/var/configs/quantity.json
new file mode 100644 (file)
index 0000000..d4f9ba4
--- /dev/null
@@ -0,0 +1,12 @@
+{
+        might_have: {
+            fetch: 0
+        },
+        has_many: {
+            fetch: 0
+        },
+        sets: [{
+            class: 'CD',
+            quantity: 3
+        }]
+}
\ No newline at end of file
diff --git a/t/var/configs/rules.json b/t/var/configs/rules.json
new file mode 100644 (file)
index 0000000..b02a286
--- /dev/null
@@ -0,0 +1,29 @@
+{
+        might_have: {
+            fetch: 0
+        },
+        has_many: {
+            fetch: 0
+        },
+        sets: [{
+            class: 'CD',
+            ids: ['5']
+        }, {
+            class: 'Artist',
+            ids: ['1'],
+            fetch: [{
+                rel: cds,
+                quantity: all
+            }]
+        }],
+        rules: {
+            'CD': {
+                cond: [{ 'tags.tag': 'Cheesy' }],
+                join: ['tags'],
+                fetch: [{
+                    rel: tracks,
+                    cond: { position: 2 }
+                }]
+            }                    
+        }
+}
\ No newline at end of file