Get rid of _generic support
[dbsrgits/DBIx-Class-DeploymentHandler.git] / lib / DBIx / Class / DeploymentHandler / DeployMethod / SQL / Translator.pm
index fc0aa48..24222ef 100644 (file)
@@ -89,23 +89,27 @@ method __ddl_consume_with_prefix($type, $versions, $prefix) {
   my $base_dir = $self->script_directory;
 
   my $main    = catfile( $base_dir, $type      );
-  my $generic = catfile( $base_dir, '_generic' );
   my $common  =
     catfile( $base_dir, '_common', $prefix, join q(-), @{$versions} );
 
   my $dir;
   if (-d $main) {
     $dir = catfile($main, $prefix, join q(-), @{$versions})
-  } elsif (-d $generic) {
-    $dir = catfile($generic, $prefix, join q(-), @{$versions});
   } else {
-    croak "neither $main or $generic exist; please write/generate some SQL";
+    croak "$main does not exist; please write/generate some SQL";
   }
 
-  opendir my($dh), $dir;
-  my %files = map { $_ => "$dir/$_" } grep { /\.(?:sql|pl|sql-\w+)$/ && -f "$dir/$_" } readdir $dh;
-  closedir $dh;
-
+  my %files;
+  try {
+     opendir my($dh), $dir;
+     %files =
+       map { $_ => "$dir/$_" }
+       grep { /\.(?:sql|pl|sql-\w+)$/ && -f "$dir/$_" }
+       readdir $dh;
+     closedir $dh;
+  } catch {
+    die $_ unless $self->ignore_ddl;
+  };
   if (-d $common) {
     opendir my($dh), $common;
     for my $filename (grep { /\.(?:sql|pl)$/ && -f catfile($common,$_) } readdir $dh) {
@@ -127,8 +131,36 @@ method _ddl_schema_consume_filenames($type, $version) {
   $self->__ddl_consume_with_prefix($type, [ $version ], 'schema')
 }
 
+method _ddl_protoschema_up_consume_filenames($versions) {
+  my $base_dir = $self->script_directory;
+
+  my $dir = catfile( $base_dir, '_protoschema', 'up', join q(-), @{$versions});
+
+  return [] unless -d $dir;
+
+  opendir my($dh), $dir;
+  my %files = map { $_ => "$dir/$_" } grep { /\.pl$/ && -f "$dir/$_" } readdir $dh;
+  closedir $dh;
+
+  return [@files{sort keys %files}]
+}
+
+method _ddl_protoschema_down_consume_filenames($versions) {
+  my $base_dir = $self->script_directory;
+
+  my $dir = catfile( $base_dir, '_protoschema', 'down', join q(-), @{$versions});
+
+  return [] unless -d $dir;
+
+  opendir my($dh), $dir;
+  my %files = map { $_ => "$dir/$_" } grep { /\.pl$/ && -f "$dir/$_" } readdir $dh;
+  closedir $dh;
+
+  return [@files{sort keys %files}]
+}
+
 method _ddl_protoschema_produce_filename($version) {
-  my $dirname = catfile( $self->script_directory, '_protoschema', $version );
+  my $dirname = catfile( $self->script_directory, '_protoschema', 'schema',  $version );
   mkpath($dirname) unless -d $dirname;
 
   return catfile( $dirname, '001-auto.yml' );
@@ -214,13 +246,18 @@ method _run_perl($filename) {
   }
 }
 
-method _run_sql_and_perl($filenames) {
+method _run_sql_and_perl($filenames, $sql_to_run) {
   my @files   = @{$filenames};
   my $guard   = $self->schema->txn_scope_guard if $self->txn_wrap;
 
-  my $sql = '';
+  $self->_run_sql_array($sql_to_run) if $self->ignore_ddl;
+
+  my $sql = ($sql_to_run)?join ";\n", @$sql_to_run:'';
+  FILENAME:
   for my $filename (@files) {
-    if ($filename =~ /\.sql$/) {
+    if ($self->ignore_ddl && $filename =~ /^[^_]*-auto.*\.sql$/) {
+      next FILENAME
+    } elsif ($filename =~ /\.sql$/) {
        $sql .= $self->_run_sql($filename)
     } elsif ( $filename =~ /\.pl$/ ) {
        $self->_run_perl($filename)
@@ -234,18 +271,21 @@ method _run_sql_and_perl($filenames) {
   return $sql;
 }
 
-method _deploy($version) {
-  return $self->_run_sql_and_perl($self->_ddl_schema_consume_filenames(
-    $self->storage->sqlt_type,
-    $version,
-  ));
-}
-
 sub deploy {
   my $self = shift;
   my $version = (shift @_ || {})->{version} || $self->schema_version;
   log_info { "deploying version $version" };
-  $self->_deploy($version);
+  my $sqlt_type = $self->storage->sqlt_type;
+  my $sql;
+  if ($self->ignore_ddl) {
+     $sql = $self->_sql_from_yaml({},
+       '_ddl_protoschema_produce_filename', $sqlt_type
+     );
+  }
+  return $self->_run_sql_and_perl($self->_ddl_schema_consume_filenames(
+    $sqlt_type,
+    $version,
+  ), $sql);
 }
 
 sub preinstall {
@@ -282,7 +322,7 @@ sub preinstall {
   }
 }
 
-method _sqldiff_from_yaml($from_version, $to_version, $db) {
+method _sqldiff_from_yaml($from_version, $to_version, $db, $direction) {
   my $dir       = $self->script_directory;
   my $sqltargs = {
     add_drop_table => 1,
@@ -338,6 +378,13 @@ method _sqldiff_from_yaml($from_version, $to_version, $db) {
     $dest_schema->name( $filename )
       unless $dest_schema->name;
   }
+
+  my $transform_files_method =  "_ddl_protoschema_${direction}_consume_filenames";
+  my $transforms = $self->_coderefs_per_files(
+    $self->$transform_files_method([$from_version, $to_version])
+  );
+  $_->($source_schema, $dest_schema) for @$transforms;
+
   return [SQL::Translator::Diff::schema_diff(
      $source_schema, $db,
      $dest_schema,   $db,
@@ -350,7 +397,7 @@ method _sql_from_yaml($sqltargs, $from_file, $db) {
   my $version   = $self->schema_version;
 
   my $sqlt = SQL::Translator->new({
-    add_drop_table          => 1,
+    add_drop_table          => 0,
     parser                  => 'SQL::Translator::Parser::YAML',
     %{$sqltargs},
     producer => $db,
@@ -468,13 +515,16 @@ sub prepare_downgrade {
   );
 }
 
+method _coderefs_per_files($files) {
+  no warnings 'redefine';
+  [map eval do { local( @ARGV, $/ ) = $_; <> }, @$files]
+}
+
 method _prepare_changegrade($from_version, $to_version, $version_set, $direction) {
   my $schema    = $self->schema;
   my $databases = $self->databases;
   my $dir       = $self->script_directory;
 
-  return if $self->ignore_ddl;
-
   my $schema_version = $self->schema_version;
   my $diff_file_method = "_ddl_schema_${direction}_produce_filename";
   foreach my $db (@$databases) {
@@ -485,7 +535,7 @@ method _prepare_changegrade($from_version, $to_version, $version_set, $direction
     }
 
     open my $file, q(>), $diff_file;
-    print {$file} join ";\n", @{$self->_sqldiff_from_yaml($from_version, $to_version, $db)};
+    print {$file} join ";\n", @{$self->_sqldiff_from_yaml($from_version, $to_version, $db, $direction)};
     close $file;
   }
 }
@@ -513,10 +563,17 @@ sub downgrade_single_step {
   my $version_set = (shift @_)->{version_set};
   Dlog_info { "downgrade_single_step'ing $_" } $version_set;
 
+  my $sqlt_type = $self->storage->sqlt_type;
+  my $sql_to_run;
+  if ($self->ignore_ddl) {
+     $sql_to_run = $self->_sqldiff_from_yaml(
+       $version_set->[0], $version_set->[1], $sqlt_type, 'down',
+     );
+  }
   my $sql = $self->_run_sql_and_perl($self->_ddl_schema_down_consume_filenames(
-    $self->storage->sqlt_type,
+    $sqlt_type,
     $version_set,
-  ));
+  ), $sql_to_run);
 
   return ['', $sql];
 }
@@ -526,10 +583,17 @@ sub upgrade_single_step {
   my $version_set = (shift @_)->{version_set};
   Dlog_info { "upgrade_single_step'ing $_" } $version_set;
 
+  my $sqlt_type = $self->storage->sqlt_type;
+  my $sql_to_run;
+  if ($self->ignore_ddl) {
+     $sql_to_run = $self->_sqldiff_from_yaml(
+       $version_set->[0], $version_set->[1], $sqlt_type, 'up',
+     );
+  }
   my $sql = $self->_run_sql_and_perl($self->_ddl_schema_up_consume_filenames(
-    $self->storage->sqlt_type,
+    $sqlt_type,
     $version_set,
-  ));
+  ), $sql_to_run);
   return ['', $sql];
 }
 
@@ -592,6 +656,14 @@ modifications, so even if you are familiar with it, please read this.  I feel
 like the best way to describe the layout is with the following example:
 
  $sql_migration_dir
+ |- _protoschema
+ |  |- schema
+ |     |- 1
+ |     |  `- 001-auto.yml
+ |     |- 2
+ |     |  `- 001-auto.yml
+ |     `- 3
+ |        `- 001-auto.yml
  |- SQLite
  |  |- down
  |  |  `- 2-1
@@ -611,17 +683,6 @@ like the best way to describe the layout is with the following example:
  |  `- up
  |     `- 1-2
  |        `- 002-generate-customers.pl
- |- _generic
- |  |- down
- |  |  `- 2-1
- |  |     `- 001-auto.sql
- |  |- schema
- |  |  `- 1
- |  |     `- 001-auto.sql
- |  `- up
- |     `- 1-2
- |        |- 001-auto.sql
- |        `- 002-create-stored-procedures.sql
  `- MySQL
     |- down
     |  `- 2-1
@@ -652,9 +713,6 @@ C<$sql_migration_dir/_common/up/1-2/002-generate-customers.pl>.
 C<.pl> files don't have to be in the C<_common> directory, but most of the time
 they should be, because perl scripts are generally be database independent.
 
-C<_generic> exists for when you for some reason are sure that your SQL is
-generic enough to run on all databases.  Good luck with that one.
-
 Note that unlike most steps in the process, C<preinstall> will not run SQL, as
 there may not even be an database at preinstall time.  It will run perl scripts
 just like the other steps in the process, but nothing is passed to them.
@@ -662,6 +720,70 @@ Until people have used this more it will remain freeform, but a recommended use
 of preinstall is to have it prompt for username and password, and then call the
 appropriate C<< CREATE DATABASE >> commands etc.
 
+=head2 Directory Specification
+
+The following subdirectories are recognized by this DeployMethod:
+
+=over 2
+
+=item C<_protoschema> This directory can contain the following directories:
+
+=over 2
+
+=item C<down> This directory merely contains directories named after
+migrations, which are of the form C<$from_version-$to_version>.  Inside of
+these directories you may put Perl scripts which are to return a subref
+that takes the arguments C<< $from_schema, $to_schema >>, which are
+L<SQL::Translator::Schema> objects.
+
+=item C<up> This directory merely contains directories named after
+migrations, which are of the form C<$from_version-$to_version>.  Inside of
+these directories you may put Perl scripts which are to return a subref
+that takes the arguments C<< $from_schema, $to_schema >>, which are
+L<SQL::Translator::Schema> objects.
+
+=item C<schema> This directory merely contains directories named after schema
+versions, which in turn contain C<yaml> files that are serialized versions
+of the schema at that version.  These files are not for editing by hand.
+
+=back
+
+=item C<$storage_type> This is a set of scripts that gets run depending on what
+your storage type is.  If you are not sure what your storage type is, take a
+look at the producers listed for L<SQL::Translator>.  Also note, C<_common>
+is a special case.  C<_common> will get merged into whatever other files you
+already have.  This directory can containt the following directories itself:
+
+=over 2
+
+=item C<preinstall> Gets run before the C<schema> is C<deploy>ed.  Has the
+same structure as the C<schema> subdirectory as well; that is, it has a
+directory for each schema version.  Unlike C<schema>, C<up>, and C<down>
+though, it can only run C<.pl> files, and the coderef in the perl files get
+no arguments passed to them.
+
+=item C<schema> Gets run when the schema is C<deploy>ed.  Structure is a
+directory per schema version, and then files are merged with C<_common> and run
+in filename order.  C<.sql> files are merely run, as expected.  C<.pl> files are
+run according to L</PERL SCRIPTS>.
+
+=item C<up> Gets run when the schema is C<upgrade>d.  Structure is a directory
+per upgrade step, (for example, C<1-2> for upgrading from version 1 to version
+2,) and then files are merged with C<_common> and run in filename order.
+C<.sql> files are merely run, as expected.  C<.pl> files are run according
+to L</PERL SCRIPTS>.
+
+=item C<down> Gets run when the schema is C<downgrade>d.  Structure is a directory
+per downgrade step, (for example, C<2-1> for downgrading from version 2 to version
+1,) and then files are merged with C<_common> and run in filename order.
+C<.sql> files are merely run, as expected.  C<.pl> files are run according
+to L</PERL SCRIPTS>.
+
+
+=back
+
+=back
+
 =head1 PERL SCRIPTS
 
 A perl script for this tool is very simple.  It merely needs to contain an