add missing newline for no-linenumber-change dzil
[dbsrgits/DBIx-Class-DeploymentHandler.git] / lib / DBIx / Class / DeploymentHandler / DeployMethod / SQL / Translator.pm
1 package DBIx::Class::DeploymentHandler::DeployMethod::SQL::Translator;
2
3 use Moose;
4
5 # ABSTRACT: Manage your SQL and Perl migrations in nicely laid out directories
6
7 use autodie;
8 use Carp qw( carp croak );
9 use DBIx::Class::DeploymentHandler::LogImporter qw(:log :dlog);
10 use Context::Preserve;
11
12 use Try::Tiny;
13
14 use SQL::Translator;
15 require SQL::Translator::Diff;
16
17 require DBIx::Class::Storage;   # loaded for type constraint
18 use DBIx::Class::DeploymentHandler::Types;
19
20 use Path::Class qw(file dir);
21
22 with 'DBIx::Class::DeploymentHandler::HandlesDeploy';
23
24 has ignore_ddl => (
25   isa      => 'Bool',
26   is       => 'ro',
27   default  => undef,
28 );
29
30 has force_overwrite => (
31   isa      => 'Bool',
32   is       => 'ro',
33   default  => undef,
34 );
35
36 has schema => (
37   is       => 'ro',
38   required => 1,
39 );
40
41 has storage => (
42   isa        => 'DBIx::Class::Storage',
43   is         => 'ro',
44   lazy_build => 1,
45 );
46
47 sub _build_storage {
48   my $self = shift;
49   my $s = $self->schema->storage;
50   $s->_determine_driver;
51   $s
52 }
53
54 has sql_translator_args => (
55   isa => 'HashRef',
56   is  => 'ro',
57   default => sub { {} },
58 );
59 has script_directory => (
60   isa      => 'Str',
61   is       => 'ro',
62   required => 1,
63   default  => 'sql',
64 );
65
66 has databases => (
67   coerce  => 1,
68   isa     => 'DBIx::Class::DeploymentHandler::Databases',
69   is      => 'ro',
70   default => sub { [qw( MySQL SQLite PostgreSQL )] },
71 );
72
73 has txn_wrap => (
74   is => 'ro',
75   isa => 'Bool',
76   default => 1,
77 );
78
79 has schema_version => (
80   is => 'ro',
81   isa => 'Str',
82   lazy_build => 1,
83 );
84
85 # this will probably never get called as the DBICDH
86 # will be passing down a schema_version normally, which
87 # is built the same way, but we leave this in place
88 sub _build_schema_version {
89   my $self = shift;
90   $self->schema->schema_version
91 }
92
93 sub __ddl_consume_with_prefix {
94   my ($self, $type, $versions, $prefix) = @_;
95   my $base_dir = $self->script_directory;
96
97   my $main    = dir( $base_dir, $type      );
98   my $common  =
99     dir( $base_dir, '_common', $prefix, join q(-), @{$versions} );
100
101   my $common_any  =
102     dir( $base_dir, '_common', $prefix, '_any' );
103
104   my $dir;
105   if (-d $main) {
106     $dir = dir($main, $prefix, join q(-), @{$versions})
107   } else {
108     if ($self->ignore_ddl) {
109       return []
110     } else {
111       croak "$main does not exist; please write/generate some SQL"
112     }
113   }
114   my $dir_any = dir($main, $prefix, '_any');
115
116   my %files;
117   try {
118      opendir my($dh), $dir;
119      %files =
120        map { $_ => "$dir/$_" }
121        grep { /\.(?:sql|pl|sql-\w+)$/ && -f "$dir/$_" }
122        readdir $dh;
123      closedir $dh;
124   } catch {
125     die $_ unless $self->ignore_ddl;
126   };
127   for my $dirname (grep { -d $_ } $common, $common_any, $dir_any) {
128     opendir my($dh), $dirname;
129     for my $filename (grep { /\.(?:sql|pl)$/ && -f file($dirname,$_) } readdir $dh) {
130       unless ($files{$filename}) {
131         $files{$filename} = file($dirname,$filename);
132       }
133     }
134     closedir $dh;
135   }
136
137   return [@files{sort keys %files}]
138 }
139
140 sub _ddl_initialize_consume_filenames {
141   my ($self, $type, $version) = @_;
142   $self->__ddl_consume_with_prefix($type, [ $version ], 'initialize')
143 }
144
145 sub _ddl_schema_consume_filenames {
146   my ($self, $type, $version) = @_;
147   $self->__ddl_consume_with_prefix($type, [ $version ], 'deploy')
148 }
149
150 sub _ddl_protoschema_deploy_consume_filenames {
151   my ($self, $version) = @_;
152   my $base_dir = $self->script_directory;
153
154   my $dir = dir( $base_dir, '_source', 'deploy', $version);
155   return [] unless -d $dir;
156
157   opendir my($dh), $dir;
158   my %files = map { $_ => "$dir/$_" } grep { /\.yml$/ && -f "$dir/$_" } readdir $dh;
159   closedir $dh;
160
161   return [@files{sort keys %files}]
162 }
163
164 sub _ddl_protoschema_upgrade_consume_filenames {
165   my ($self, $versions) = @_;
166   my $base_dir = $self->script_directory;
167
168   my $dir = dir( $base_dir, '_preprocess_schema', 'upgrade', join q(-), @{$versions});
169
170   return [] unless -d $dir;
171
172   opendir my($dh), $dir;
173   my %files = map { $_ => "$dir/$_" } grep { /\.pl$/ && -f "$dir/$_" } readdir $dh;
174   closedir $dh;
175
176   return [@files{sort keys %files}]
177 }
178
179 sub _ddl_protoschema_downgrade_consume_filenames {
180   my ($self, $versions) = @_;
181   my $base_dir = $self->script_directory;
182
183   my $dir = dir( $base_dir, '_preprocess_schema', 'downgrade', join q(-), @{$versions});
184
185   return [] unless -d $dir;
186
187   opendir my($dh), $dir;
188   my %files = map { $_ => "$dir/$_" } grep { /\.pl$/ && -f "$dir/$_" } readdir $dh;
189   closedir $dh;
190
191   return [@files{sort keys %files}]
192 }
193
194 sub _ddl_protoschema_produce_filename {
195   my ($self, $version) = @_;
196   my $dirname = dir( $self->script_directory, '_source', 'deploy',  $version );
197   $dirname->mkpath unless -d $dirname;
198
199   return "" . file( $dirname, '001-auto.yml' );
200 }
201
202 sub _ddl_schema_produce_filename {
203   my ($self, $type, $version) = @_;
204   my $dirname = dir( $self->script_directory, $type, 'deploy', $version );
205   $dirname->mkpath unless -d $dirname;
206
207   return "" . file( $dirname, '001-auto.sql' );
208 }
209
210 sub _ddl_schema_upgrade_consume_filenames {
211   my ($self, $type, $versions) = @_;
212   $self->__ddl_consume_with_prefix($type, $versions, 'upgrade')
213 }
214
215 sub _ddl_schema_downgrade_consume_filenames {
216   my ($self, $type, $versions) = @_;
217   $self->__ddl_consume_with_prefix($type, $versions, 'downgrade')
218 }
219
220 sub _ddl_schema_upgrade_produce_filename {
221   my ($self, $type, $versions) = @_;
222   my $dir = $self->script_directory;
223
224   my $dirname = dir( $dir, $type, 'upgrade', join q(-), @{$versions});
225   $dirname->mkpath unless -d $dirname;
226
227   return "" . file( $dirname, '001-auto.sql' );
228 }
229
230 sub _ddl_schema_downgrade_produce_filename {
231   my ($self, $type, $versions, $dir) = @_;
232   my $dirname = dir( $dir, $type, 'downgrade', join q(-), @{$versions} );
233   $dirname->mkpath unless -d $dirname;
234
235   return "" . file( $dirname, '001-auto.sql');
236 }
237
238 sub _run_sql_array {
239   my ($self, $sql) = @_;
240   my $storage = $self->storage;
241
242   $sql = [ _split_sql_chunk( @$sql ) ];
243
244   Dlog_trace { "Running SQL $_" } $sql;
245   foreach my $line (@{$sql}) {
246     $storage->_query_start($line);
247     # the whole reason we do this is so that we can see the line that was run
248     try {
249       $storage->dbh_do (sub { $_[1]->do($line) });
250     }
251     catch {
252       die "$_ (running line '$line')"
253     };
254     $storage->_query_end($line);
255   }
256   return join "\n", @$sql
257 }
258
259 # split a chunk o' SQL into statements
260 sub _split_sql_chunk {
261     my @sql = map { split /;\n/, $_ } @_;
262
263     for ( @sql ) {
264         # strip transactions
265         s/^(?:BEGIN|BEGIN TRANSACTION|COMMIT).*//mgi;
266
267         # trim whitespaces
268         s/^\s+//gm;
269         s/\s+$//gm;
270
271         # remove comments
272         s/^--.*//gm;
273
274         # remove blank lines
275         s/^\n//gm;
276
277         # put on single line
278         s/\n/ /g;
279     }
280
281     return grep $_, @sql;
282 }
283
284 sub _run_sql {
285   my ($self, $filename) = @_;
286   log_debug { "Running SQL from $filename" };
287   return $self->_run_sql_array($self->_read_sql_file($filename));
288 }
289
290 sub _load_sandbox {
291   my $_file = shift;
292   $_file = "$_file";
293
294   my $_package = $_file;
295   $_package =~ s/([^A-Za-z0-9_])/sprintf("_%2x", ord($1))/eg;
296
297   my $fn = eval sprintf <<'END_EVAL', $_package;
298 package DBICDH::Sandbox::%s;
299 {
300   our $app;
301   $app ||= require $_file;
302   if ( !$app && ( my $error = $@ || $! )) { die $error; }
303   $app;
304 }
305 END_EVAL
306
307   croak $@ if $@;
308
309   croak "$_file should define an anonymous sub that takes a schema but it didn't!"
310      unless ref $fn && ref $fn eq 'CODE';
311
312   return $fn;
313 }
314
315 sub _run_perl {
316   my ($self, $filename, $versions) = @_;
317   log_debug { "Running Perl from $filename" };
318
319   my $fn = _load_sandbox($filename);
320
321   Dlog_trace { "Running Perl $_" } $fn;
322
323   $fn->($self->schema, $versions)
324 }
325
326 sub txn_do {
327    my ( $self, $code ) = @_;
328    return $code->() unless $self->txn_wrap;
329
330    my $guard = $self->schema->txn_scope_guard;
331
332    return preserve_context { $code->() } after => sub { $guard->commit };
333 }
334
335 sub _run_sql_and_perl {
336   my ($self, $filenames, $sql_to_run, $versions) = @_;
337   my @files   = @{$filenames};
338   $self->txn_do(sub {
339      $self->_run_sql_array($sql_to_run) if $self->ignore_ddl;
340
341      my $sql = ($sql_to_run)?join ";\n", @$sql_to_run:'';
342      FILENAME:
343      for my $filename (map file($_), @files) {
344        if ($self->ignore_ddl && $filename->basename =~ /^[^-]*-auto.*\.sql$/) {
345          next FILENAME
346        } elsif ($filename =~ /\.sql$/) {
347           $sql .= $self->_run_sql($filename)
348        } elsif ( $filename =~ /\.pl$/ ) {
349           $self->_run_perl($filename, $versions)
350        } else {
351          croak "A file ($filename) got to deploy that wasn't sql or perl!";
352        }
353      }
354
355      return $sql;
356   });
357 }
358
359 sub deploy {
360   my $self = shift;
361   my $version = (shift @_ || {})->{version} || $self->schema_version;
362   log_info { "deploying version $version" };
363   my $sqlt_type = $self->storage->sqlt_type;
364   my $sql;
365   my $sqltargs = $self->sql_translator_args;
366   if ($self->ignore_ddl) {
367      $sql = $self->_sql_from_yaml($sqltargs,
368        '_ddl_protoschema_deploy_consume_filenames', $sqlt_type
369      );
370   }
371   return $self->_run_sql_and_perl($self->_ddl_schema_consume_filenames(
372     $sqlt_type,
373     $version,
374   ), $sql, [$version]);
375 }
376
377 sub initialize {
378   my $self         = shift;
379   my $args         = shift;
380   my $version      = $args->{version}      || $self->schema_version;
381   log_info { "initializing version $version" };
382   my $storage_type = $args->{storage_type} || $self->storage->sqlt_type;
383
384   my @files = @{$self->_ddl_initialize_consume_filenames(
385     $storage_type,
386     $version,
387   )};
388
389   for my $filename (@files) {
390     # We ignore sql for now (till I figure out what to do with it)
391     if ( $filename =~ /^(.+)\.pl$/ ) {
392       my $filedata = do { local( @ARGV, $/ ) = $filename; <> };
393
394       no warnings 'redefine';
395       my $fn = eval "$filedata";
396       use warnings;
397
398       if ($@) {
399         croak "$filename failed to compile: $@";
400       } elsif (ref $fn eq 'CODE') {
401         $fn->()
402       } else {
403         croak "$filename should define an anonymous sub but it didn't!";
404       }
405     } else {
406       croak "A file ($filename) got to initialize_scripts that wasn't sql or perl!";
407     }
408   }
409 }
410
411 sub _sqldiff_from_yaml {
412   my ($self, $from_version, $to_version, $db, $direction) = @_;
413   my $dir       = $self->script_directory;
414   my $sqltargs = {
415     add_drop_table => 1,
416     ignore_constraint_names => 1,
417     ignore_index_names => 1,
418     %{$self->sql_translator_args}
419   };
420
421   my $source_schema;
422   {
423     my $prefilename = $self->_ddl_protoschema_produce_filename($from_version, $dir);
424
425     # should probably be a croak
426     carp("No previous schema file found ($prefilename)")
427        unless -e $prefilename;
428
429     my $t = SQL::Translator->new({
430        %{$sqltargs},
431        debug => 0,
432        trace => 0,
433        parser => 'SQL::Translator::Parser::YAML',
434     });
435
436     my $out = $t->translate( $prefilename )
437       or croak($t->error);
438
439     $source_schema = $t->schema;
440
441     $source_schema->name( $prefilename )
442       unless  $source_schema->name;
443   }
444
445   my $dest_schema;
446   {
447     my $filename = $self->_ddl_protoschema_produce_filename($to_version, $dir);
448
449     # should probably be a croak
450     carp("No next schema file found ($filename)")
451        unless -e $filename;
452
453     my $t = SQL::Translator->new({
454        %{$sqltargs},
455        debug => 0,
456        trace => 0,
457        parser => 'SQL::Translator::Parser::YAML',
458     });
459
460     my $out = $t->translate( $filename )
461       or croak($t->error);
462
463     $dest_schema = $t->schema;
464
465     $dest_schema->name( $filename )
466       unless $dest_schema->name;
467   }
468
469   my $transform_files_method =  "_ddl_protoschema_${direction}_consume_filenames";
470   my $transforms = $self->_coderefs_per_files(
471     $self->$transform_files_method([$from_version, $to_version])
472   );
473   $_->($source_schema, $dest_schema) for @$transforms;
474
475   return [SQL::Translator::Diff::schema_diff(
476      $source_schema, $db,
477      $dest_schema,   $db,
478      $sqltargs
479   )];
480 }
481
482 sub _sql_from_yaml {
483   my ($self, $sqltargs, $from_file, $db) = @_;
484   my $schema    = $self->schema;
485   my $version   = $self->schema_version;
486
487   my @sql;
488
489   my $actual_file = $self->$from_file($version);
490   for my $yaml_filename (@{(
491      DlogS_trace { "generating SQL from Serialized SQL Files: $_" }
492         (ref $actual_file?$actual_file:[$actual_file])
493   )}) {
494      my $sqlt = SQL::Translator->new({
495        add_drop_table          => 0,
496        parser                  => 'SQL::Translator::Parser::YAML',
497        %{$sqltargs},
498        producer => $db,
499      });
500
501      push @sql, $sqlt->translate($yaml_filename);
502      if(!@sql) {
503        carp("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
504        return undef;
505      }
506   }
507   return \@sql;
508 }
509
510 sub _prepare_install {
511   my $self      = shift;
512   my $sqltargs  = { %{$self->sql_translator_args}, %{shift @_} };
513   my $from_file = shift;
514   my $to_file   = shift;
515   my $dir       = $self->script_directory;
516   my $databases = $self->databases;
517   my $version   = $self->schema_version;
518
519   foreach my $db (@$databases) {
520     my $sql = $self->_sql_from_yaml($sqltargs, $from_file, $db ) or next;
521
522     my $filename = $self->$to_file($db, $version, $dir);
523     if (-e $filename ) {
524       if ($self->force_overwrite) {
525          carp "Overwriting existing DDL file - $filename";
526          unlink $filename;
527       } else {
528          die "Cannot overwrite '$filename', either enable force_overwrite or delete it"
529       }
530     }
531     open my $file, q(>), $filename;
532     print {$file} join ";\n", @$sql, '';
533     close $file;
534   }
535 }
536
537 sub _resultsource_install_filename {
538   my ($self, $source_name) = @_;
539   return sub {
540     my ($self, $type, $version) = @_;
541     my $dirname = dir( $self->script_directory, $type, 'deploy', $version );
542     $dirname->mkpath unless -d $dirname;
543
544     return "" . file( $dirname, "001-auto-$source_name.sql" );
545   }
546 }
547
548 sub _resultsource_protoschema_filename {
549   my ($self, $source_name) = @_;
550   return sub {
551     my ($self, $version) = @_;
552     my $dirname = dir( $self->script_directory, '_source', 'deploy', $version );
553     $dirname->mkpath unless -d $dirname;
554
555     return "" . file( $dirname, "001-auto-$source_name.yml" );
556   }
557 }
558
559 sub install_resultsource {
560   my ($self, $args) = @_;
561   my $source          = $args->{result_source}
562     or die 'result_source must be passed to install_resultsource';
563   my $version         = $args->{version}
564     or die 'version must be passed to install_resultsource';
565   log_info { 'installing_resultsource ' . $source->source_name . ", version $version" };
566   my $rs_install_file =
567     $self->_resultsource_install_filename($source->source_name);
568
569   my $files = [
570      $self->$rs_install_file(
571       $self->storage->sqlt_type,
572       $version,
573     )
574   ];
575   $self->_run_sql_and_perl($files, '', [$version]);
576 }
577
578 sub prepare_resultsource_install {
579   my $self = shift;
580   my $source = (shift @_)->{result_source};
581   log_info { 'preparing install for resultsource ' . $source->source_name };
582
583   my $install_filename = $self->_resultsource_install_filename($source->source_name);
584   my $proto_filename = $self->_resultsource_protoschema_filename($source->source_name);
585   $self->prepare_protoschema({
586       parser_args => { sources => [$source->source_name], }
587   }, $proto_filename);
588   $self->_prepare_install({}, $proto_filename, $install_filename);
589 }
590
591 sub prepare_deploy {
592   log_info { 'preparing deploy' };
593   my $self = shift;
594   $self->prepare_protoschema({
595       # Exclude __VERSION so that it gets installed separately
596       parser_args => {
597          sources => [
598             sort { $a cmp $b }
599             grep { $_ ne '__VERSION' }
600             $self->schema->sources
601          ],
602       }
603   }, '_ddl_protoschema_produce_filename');
604   $self->_prepare_install({}, '_ddl_protoschema_produce_filename', '_ddl_schema_produce_filename');
605 }
606
607 sub prepare_upgrade {
608   my ($self, $args) = @_;
609   log_info {
610      "preparing upgrade from $args->{from_version} to $args->{to_version}"
611   };
612   $self->_prepare_changegrade(
613     $args->{from_version}, $args->{to_version}, $args->{version_set}, 'upgrade'
614   );
615 }
616
617 sub prepare_downgrade {
618   my ($self, $args) = @_;
619   log_info {
620      "preparing downgrade from $args->{from_version} to $args->{to_version}"
621   };
622   $self->_prepare_changegrade(
623     $args->{from_version}, $args->{to_version}, $args->{version_set}, 'downgrade'
624   );
625 }
626
627 sub _coderefs_per_files {
628   my ($self, $files) = @_;
629   no warnings 'redefine';
630   [map eval do { local( @ARGV, $/ ) = $_; <> }, @$files]
631 }
632
633 sub _prepare_changegrade {
634   my ($self, $from_version, $to_version, $version_set, $direction) = @_;
635   my $schema    = $self->schema;
636   my $databases = $self->databases;
637   my $dir       = $self->script_directory;
638
639   my $schema_version = $self->schema_version;
640   my $diff_file_method = "_ddl_schema_${direction}_produce_filename";
641   foreach my $db (@$databases) {
642     my $diff_file = $self->$diff_file_method($db, $version_set, $dir );
643     if(-e $diff_file) {
644       if ($self->force_overwrite) {
645          carp("Overwriting existing $direction-diff file - $diff_file");
646          unlink $diff_file;
647       } else {
648          die "Cannot overwrite '$diff_file', either enable force_overwrite or delete it"
649       }
650     }
651
652     open my $file, q(>), $diff_file;
653     print {$file} join ";\n", @{$self->_sqldiff_from_yaml($from_version, $to_version, $db, $direction)};
654     close $file;
655   }
656 }
657
658 sub _read_sql_file {
659   my ($self, $file)  = @_;
660   return unless $file;
661
662    local $/ = undef;  #sluuuuuurp
663
664   open my $fh, '<', $file;
665   return [ _split_sql_chunk( <$fh> ) ];
666 }
667
668 sub downgrade_single_step {
669   my $self = shift;
670   my $version_set = (shift @_)->{version_set};
671   Dlog_info { "downgrade_single_step'ing $_" } $version_set;
672
673   my $sqlt_type = $self->storage->sqlt_type;
674   my $sql_to_run;
675   if ($self->ignore_ddl) {
676      $sql_to_run = $self->_sqldiff_from_yaml(
677        $version_set->[0], $version_set->[1], $sqlt_type, 'downgrade',
678      );
679   }
680   my $sql = $self->_run_sql_and_perl($self->_ddl_schema_downgrade_consume_filenames(
681     $sqlt_type,
682     $version_set,
683   ), $sql_to_run, $version_set);
684
685   return ['', $sql];
686 }
687
688 sub upgrade_single_step {
689   my $self = shift;
690   my $version_set = (shift @_)->{version_set};
691   Dlog_info { "upgrade_single_step'ing $_" } $version_set;
692
693   my $sqlt_type = $self->storage->sqlt_type;
694   my $sql_to_run;
695   if ($self->ignore_ddl) {
696      $sql_to_run = $self->_sqldiff_from_yaml(
697        $version_set->[0], $version_set->[1], $sqlt_type, 'upgrade',
698      );
699   }
700   my $sql = $self->_run_sql_and_perl($self->_ddl_schema_upgrade_consume_filenames(
701     $sqlt_type,
702     $version_set,
703   ), $sql_to_run, $version_set);
704   return ['', $sql];
705 }
706
707 sub prepare_protoschema {
708   my $self      = shift;
709   my $sqltargs  = { %{$self->sql_translator_args}, %{shift @_} };
710   my $to_file   = shift;
711   my $filename
712     = $self->$to_file($self->schema_version);
713
714   # we do this because the code that uses this sets parser args,
715   # so we just need to merge in the package
716   my $sqlt = SQL::Translator->new({
717     parser                  => 'SQL::Translator::Parser::DBIx::Class',
718     producer                => 'SQL::Translator::Producer::YAML',
719     %{ $sqltargs },
720   });
721
722   my $yml = $sqlt->translate(data => $self->schema);
723
724   croak("Failed to translate to YAML: " . $sqlt->error)
725     unless $yml;
726
727   if (-e $filename ) {
728     if ($self->force_overwrite) {
729        carp "Overwriting existing DDL-YML file - $filename";
730        unlink $filename;
731     } else {
732        die "Cannot overwrite '$filename', either enable force_overwrite or delete it"
733     }
734   }
735
736   open my $file, q(>), $filename;
737   print {$file} $yml;
738   close $file;
739 }
740
741 __PACKAGE__->meta->make_immutable;
742
743 1;
744
745 # vim: ts=2 sw=2 expandtab
746
747 __END__
748
749 =head1 DESCRIPTION
750
751 This class is the meat of L<DBIx::Class::DeploymentHandler>.  It takes care
752 of generating serialized schemata  as well as sql files to move from one
753 version of a schema to the rest.  One of the hallmark features of this class
754 is that it allows for multiple sql files for deploy and upgrade, allowing
755 developers to fine tune deployment.  In addition it also allows for perl
756 files to be run at any stage of the process.
757
758 For basic usage see L<DBIx::Class::DeploymentHandler::HandlesDeploy>.  What's
759 documented here is extra fun stuff or private methods.
760
761 =head1 DIRECTORY LAYOUT
762
763 Arguably this is the best feature of L<DBIx::Class::DeploymentHandler>.
764 It's spiritually based upon L<DBIx::Migration::Directories>, but has a
765 lot of extensions and modifications, so even if you are familiar with it,
766 please read this.  I feel like the best way to describe the layout is with
767 the following example:
768
769  $sql_migration_dir
770  |- _source
771  |  |- deploy
772  |     |- 1
773  |     |  `- 001-auto.yml
774  |     |- 2
775  |     |  `- 001-auto.yml
776  |     `- 3
777  |        `- 001-auto.yml
778  |- SQLite
779  |  |- downgrade
780  |  |  `- 2-1
781  |  |     `- 001-auto.sql
782  |  |- deploy
783  |  |  `- 1
784  |  |     `- 001-auto.sql
785  |  `- upgrade
786  |     |- 1-2
787  |     |  `- 001-auto.sql
788  |     `- 2-3
789  |        `- 001-auto.sql
790  |- _common
791  |  |- downgrade
792  |  |  `- 2-1
793  |  |     `- 002-remove-customers.pl
794  |  `- upgrade
795  |     `- 1-2
796  |     |  `- 002-generate-customers.pl
797  |     `- _any
798  |        `- 999-bump-action.pl
799  `- MySQL
800     |- downgrade
801     |  `- 2-1
802     |     `- 001-auto.sql
803     |- initialize
804     |  `- 1
805     |     |- 001-create_database.pl
806     |     `- 002-create_users_and_permissions.pl
807     |- deploy
808     |  `- 1
809     |     `- 001-auto.sql
810     `- upgrade
811        `- 1-2
812           `- 001-auto.sql
813
814 So basically, the code
815
816  $dm->deploy(1)
817
818 on an C<SQLite> database that would simply run
819 C<$sql_migration_dir/SQLite/deploy/1/001-auto.sql>.  Next,
820
821  $dm->upgrade_single_step([1,2])
822
823 would run C<$sql_migration_dir/SQLite/upgrade/1-2/001-auto.sql> followed by
824 C<$sql_migration_dir/_common/upgrade/1-2/002-generate-customers.pl>, and
825 finally punctuated by
826 C<$sql_migration_dir/_common/upgrade/_any/999-bump-action.pl>.
827
828 C<.pl> files don't have to be in the C<_common> directory, but most of the time
829 they should be, because perl scripts are generally database independent.
830
831 Note that unlike most steps in the process, C<initialize> will not run SQL, as
832 there may not even be an database at initialize time.  It will run perl scripts
833 just like the other steps in the process, but nothing is passed to them.
834 Until people have used this more it will remain freeform, but a recommended use
835 of initialize is to have it prompt for username and password, and then call the
836 appropriate C<< CREATE DATABASE >> commands etc.
837
838 =head2 Directory Specification
839
840 The following subdirectories are recognized by this DeployMethod:
841
842 =over 2
843
844 =item C<_source> This directory can contain the following directories:
845
846 =over 2
847
848 =item C<deploy> This directory merely contains directories named after schema
849 versions, which in turn contain C<yaml> files that are serialized versions
850 of the schema at that version.  These files are not for editing by hand.
851
852 =back
853
854 =item C<_preprocess_schema> This directory can contain the following
855 directories:
856
857 =over 2
858
859 =item C<downgrade> This directory merely contains directories named after
860 migrations, which are of the form C<$from_version-$to_version>.  Inside of
861 these directories you may put Perl scripts which are to return a subref
862 that takes the arguments C<< $from_schema, $to_schema >>, which are
863 L<SQL::Translator::Schema> objects.
864
865 =item C<upgrade> This directory merely contains directories named after
866 migrations, which are of the form C<$from_version-$to_version>.  Inside of
867 these directories you may put Perl scripts which are to return a subref
868 that takes the arguments C<< $from_schema, $to_schema >>, which are
869 L<SQL::Translator::Schema> objects.
870
871 =back
872
873 =item C<$storage_type> This is a set of scripts that gets run depending on what
874 your storage type is.  If you are not sure what your storage type is, take a
875 look at the producers listed for L<SQL::Translator>.  Also note, C<_common>
876 is a special case.  C<_common> will get merged into whatever other files you
877 already have.  This directory can contain the following directories itself:
878
879 =over 2
880
881 =item C<initialize> Gets run before the C<deploy> is C<deploy>ed.  Has the
882 same structure as the C<deploy> subdirectory as well; that is, it has a
883 directory for each schema version.  Unlike C<deploy>, C<upgrade>, and C<downgrade>
884 though, it can only run C<.pl> files, and the coderef in the perl files get
885 no arguments passed to them.
886
887 =item C<deploy> Gets run when the schema is C<deploy>ed.  Structure is a
888 directory per schema version, and then files are merged with C<_common> and run
889 in filename order.  C<.sql> files are merely run, as expected.  C<.pl> files are
890 run according to L</PERL SCRIPTS>.
891
892 =item C<upgrade> Gets run when the schema is C<upgrade>d.  Structure is a directory
893 per upgrade step, (for example, C<1-2> for upgrading from version 1 to version
894 2,) and then files are merged with C<_common> and run in filename order.
895 C<.sql> files are merely run, as expected.  C<.pl> files are run according
896 to L</PERL SCRIPTS>.
897
898 =item C<downgrade> Gets run when the schema is C<downgrade>d.  Structure is a directory
899 per downgrade step, (for example, C<2-1> for downgrading from version 2 to version
900 1,) and then files are merged with C<_common> and run in filename order.
901 C<.sql> files are merely run, as expected.  C<.pl> files are run according
902 to L</PERL SCRIPTS>.
903
904
905 =back
906
907 =back
908
909 Note that there can be an C<_any> in the place of any of the versions (like
910 C<1-2> or C<1>), which means those scripts will be run B<every> time.  So if
911 you have an C<_any> in C<_common/upgrade>, that script will get run for every
912 upgrade.
913
914 =head1 PERL SCRIPTS
915
916 A perl script for this tool is very simple.  It merely needs to contain an
917 anonymous sub that takes a L<DBIx::Class::Schema> and the version set as it's
918 arguments.
919
920 A very basic perl script might look like:
921
922  #!perl
923
924  use strict;
925  use warnings;
926
927  use DBIx::Class::DeploymentHandler::DeployMethod::SQL::Translator::ScriptHelpers
928     'schema_from_schema_loader';
929
930  schema_from_schema_loader({ naming => 'v4' }, sub {
931    my $schema = shift;
932
933    # [1] for deploy, [1,2] for upgrade or downgrade, probably used with _any
934    my $versions = shift;
935
936    $schema->resultset('Users')->create({
937      name => 'root',
938      password => 'root',
939    })
940  })
941
942 Note that the above uses
943 L<DBIx::Class::DeploymentHanlder::DeployMethod::SQL::Translator::ScriptHelpers/schema_from_schema_loader>.
944 Using a raw coderef is strongly discouraged as it is likely to break as you
945 modify your schema.
946
947 =attr ignore_ddl
948
949 This attribute will, when set to true (default is false), cause the DM to use
950 L<SQL::Translator> to use the C<_source>'s serialized SQL::Translator::Schema
951 instead of any pregenerated SQL.  If you have a development server this is
952 probably the best plan of action as you will not be putting as many generated
953 files in your version control.  Goes well with with C<databases> of C<[]>.
954
955 =attr force_overwrite
956
957 When this attribute is true generated files will be overwritten when the
958 methods which create such files are run again.  The default is false, in which
959 case the program will die with a message saying which file needs to be deleted.
960
961 =attr schema
962
963 The L<DBIx::Class::Schema> (B<required>) that is used to talk to the database
964 and generate the DDL.
965
966 =attr storage
967
968 The L<DBIx::Class::Storage> that is I<actually> used to talk to the database
969 and generate the DDL.  This is automatically created with L</_build_storage>.
970
971 =attr sql_translator_args
972
973 The arguments that get passed to L<SQL::Translator> when it's used.
974
975 =attr script_directory
976
977 The directory (default C<'sql'>) that scripts are stored in
978
979 =attr databases
980
981 The types of databases (default C<< [qw( MySQL SQLite PostgreSQL )] >>) to
982 generate files for
983
984 =attr txn_wrap
985
986 Set to true (which is the default) to wrap all upgrades and deploys in a single
987 transaction.
988
989 =attr schema_version
990
991 The version the schema on your harddrive is at.  Defaults to
992 C<< $self->schema->schema_version >>.
993
994 =head1 SEE ALSO
995
996 This class is an implementation of
997 L<DBIx::Class::DeploymentHandler::HandlesDeploy>.  Pretty much all the
998 documentation is there.