Make ignore_ddl test fail
[dbsrgits/DBIx-Class-DeploymentHandler.git] / lib / DBIx / Class / DeploymentHandler / DeployMethod / SQL / Translator.pm
CommitLineData
45d0d9d5 1package DBIx::Class::DeploymentHandler::DeployMethod::SQL::Translator;
334bced5 2use Moose;
9af9d0b2 3
9a3a62f1 4# ABSTRACT: Manage your SQL and Perl migrations in nicely laid out directories
5
9af9d0b2 6use autodie;
7use Carp qw( carp croak );
8465e767 8use DBIx::Class::DeploymentHandler::Logger;
9use Log::Contextual qw(:log :dlog), -default_logger =>
10 DBIx::Class::DeploymentHandler::Logger->new({
11 env_prefix => 'DBICDH'
12 });
9af9d0b2 13
2e68a8e1 14use Method::Signatures::Simple;
7f50d101 15use Try::Tiny;
9af9d0b2 16
d23c7c77 17use SQL::Translator;
18require SQL::Translator::Diff;
9af9d0b2 19
d23c7c77 20require DBIx::Class::Storage; # loaded for type constraint
41863428 21use DBIx::Class::DeploymentHandler::Types;
22
9af9d0b2 23use File::Path 'mkpath';
24use File::Spec::Functions;
2e68a8e1 25
7521a845 26with 'DBIx::Class::DeploymentHandler::HandlesDeploy';
3c1b5ee8 27
93460690 28has ignore_ddl => (
29 isa => 'Bool',
30 is => 'ro',
31 default => undef,
32);
33
d54b8d69 34has schema => (
35 isa => 'DBIx::Class::Schema',
36 is => 'ro',
37 required => 1,
d54b8d69 38);
39
334bced5 40has storage => (
41 isa => 'DBIx::Class::Storage',
42 is => 'ro',
43 lazy_build => 1,
44);
45
2eaf903b 46method _build_storage {
47 my $s = $self->schema->storage;
48 $s->_determine_driver;
49 $s
50}
51
02a7b8ac 52has sql_translator_args => (
334bced5 53 isa => 'HashRef',
54 is => 'ro',
55 default => sub { {} },
56);
91adde75 57has script_directory => (
334bced5 58 isa => 'Str',
59 is => 'ro',
60 required => 1,
61 default => 'sql',
62);
63
334bced5 64has databases => (
65 coerce => 1,
66 isa => 'DBIx::Class::DeploymentHandler::Databases',
67 is => 'ro',
68 default => sub { [qw( MySQL SQLite PostgreSQL )] },
69);
70
a7d53deb 71has txn_wrap => (
72 is => 'ro',
73 isa => 'Bool',
74 default => 1,
75);
76
73caa630 77has schema_version => (
78 is => 'ro',
e86c0c07 79 isa => 'Str',
73caa630 80 lazy_build => 1,
81);
82
6df6dcb9 83# this will probably never get called as the DBICDH
84# will be passing down a schema_version normally, which
85# is built the same way, but we leave this in place
73caa630 86method _build_schema_version { $self->schema->schema_version }
87
76d311e7 88method __ddl_consume_with_prefix($type, $versions, $prefix) {
91adde75 89 my $base_dir = $self->script_directory;
262166c1 90
76d08d08 91 my $main = catfile( $base_dir, $type );
92 my $generic = catfile( $base_dir, '_generic' );
93 my $common =
94 catfile( $base_dir, '_common', $prefix, join q(-), @{$versions} );
262166c1 95
96 my $dir;
97 if (-d $main) {
76d08d08 98 $dir = catfile($main, $prefix, join q(-), @{$versions})
262166c1 99 } elsif (-d $generic) {
9af9d0b2 100 $dir = catfile($generic, $prefix, join q(-), @{$versions});
262166c1 101 } else {
9af9d0b2 102 croak "neither $main or $generic exist; please write/generate some SQL";
262166c1 103 }
104
105 opendir my($dh), $dir;
f36afe83 106 my %files = map { $_ => "$dir/$_" } grep { /\.(?:sql|pl|sql-\w+)$/ && -f "$dir/$_" } readdir $dh;
262166c1 107 closedir $dh;
108
109 if (-d $common) {
110 opendir my($dh), $common;
41219a5d 111 for my $filename (grep { /\.(?:sql|pl)$/ && -f catfile($common,$_) } readdir $dh) {
262166c1 112 unless ($files{$filename}) {
9af9d0b2 113 $files{$filename} = catfile($common,$filename);
262166c1 114 }
115 }
116 closedir $dh;
117 }
118
119 return [@files{sort keys %files}]
120}
3c1b5ee8 121
fc4b7602 122method _ddl_preinstall_consume_filenames($type, $version) {
123 $self->__ddl_consume_with_prefix($type, [ $version ], 'preinstall')
124}
125
76d311e7 126method _ddl_schema_consume_filenames($type, $version) {
127 $self->__ddl_consume_with_prefix($type, [ $version ], 'schema')
3c1b5ee8 128}
129
7e08eddd 130method _ddl_protoschema_produce_filename($version) {
131 my $dirname = catfile( $self->script_directory, '_protoschema', $version );
132 mkpath($dirname) unless -d $dirname;
133
134 return catfile( $dirname, '001-auto.yml' );
135}
136
76d311e7 137method _ddl_schema_produce_filename($type, $version) {
91adde75 138 my $dirname = catfile( $self->script_directory, $type, 'schema', $version );
76d08d08 139 mkpath($dirname) unless -d $dirname;
d54b8d69 140
09bc35e3 141 return catfile( $dirname, '001-auto.sql' );
d54b8d69 142}
143
76d311e7 144method _ddl_schema_up_consume_filenames($type, $versions) {
145 $self->__ddl_consume_with_prefix($type, $versions, 'up')
3c1b5ee8 146}
147
76d311e7 148method _ddl_schema_down_consume_filenames($type, $versions) {
149 $self->__ddl_consume_with_prefix($type, $versions, 'down')
a41a04e5 150}
151
76d311e7 152method _ddl_schema_up_produce_filename($type, $versions) {
91adde75 153 my $dir = $self->script_directory;
76d311e7 154
76d08d08 155 my $dirname = catfile( $dir, $type, 'up', join q(-), @{$versions});
156 mkpath($dirname) unless -d $dirname;
a41a04e5 157
e62add58 158 return catfile( $dirname, '001-auto.sql' );
a41a04e5 159}
160
76d311e7 161method _ddl_schema_down_produce_filename($type, $versions, $dir) {
76d08d08 162 my $dirname = catfile( $dir, $type, 'down', join q(-), @{$versions} );
163 mkpath($dirname) unless -d $dirname;
24f4524b 164
09bc35e3 165 return catfile( $dirname, '001-auto.sql');
24f4524b 166}
167
f36afe83 168method _run_sql_array($sql) {
41219a5d 169 my $storage = $self->storage;
5d7b27cf 170
1f0d0633 171 $sql = [grep {
172 $_ && # remove blank lines
173 !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/ # strip txn's
174 } map {
175 s/^\s+//; s/\s+$//; # trim whitespace
176 join '', grep { !/^--/ } split /\n/ # remove comments
177 } @$sql];
178
f4075791 179 Dlog_trace { "Running SQL $_" } $sql;
f36afe83 180 foreach my $line (@{$sql}) {
5d7b27cf 181 $storage->_query_start($line);
10a62c3d 182 # the whole reason we do this is so that we can see the line that was run
5d7b27cf 183 try {
5d7b27cf 184 $storage->dbh_do (sub { $_[1]->do($line) });
185 }
186 catch {
10a62c3d 187 die "$_ (running line '$line')"
5d7b27cf 188 }
189 $storage->_query_end($line);
190 }
4d09f712 191 return join "\n", @$sql
f36afe83 192}
193
194method _run_sql($filename) {
f4075791 195 log_debug { "Running SQL from $filename" };
f36afe83 196 return $self->_run_sql_array($self->_read_sql_file($filename));
5d7b27cf 197}
2e68a8e1 198
5d7b27cf 199method _run_perl($filename) {
f4075791 200 log_debug { "Running Perl from $filename" };
5d7b27cf 201 my $filedata = do { local( @ARGV, $/ ) = $filename; <> };
c8a2f7bd 202
5d7b27cf 203 no warnings 'redefine';
204 my $fn = eval "$filedata";
205 use warnings;
f4075791 206 Dlog_trace { "Running Perl $_" } $fn;
5d7b27cf 207
208 if ($@) {
209 carp "$filename failed to compile: $@";
210 } elsif (ref $fn eq 'CODE') {
211 $fn->($self->schema)
212 } else {
213 carp "$filename should define an anonymouse sub that takes a schema but it didn't!";
214 }
215}
5d7b27cf 216
217method _run_sql_and_perl($filenames) {
5d7b27cf 218 my @files = @{$filenames};
219 my $guard = $self->schema->txn_scope_guard if $self->txn_wrap;
220
221 my $sql = '';
41219a5d 222 for my $filename (@files) {
223 if ($filename =~ /\.sql$/) {
5d7b27cf 224 $sql .= $self->_run_sql($filename)
398b1385 225 } elsif ( $filename =~ /\.pl$/ ) {
5d7b27cf 226 $self->_run_perl($filename)
41219a5d 227 } else {
fc4b7602 228 croak "A file ($filename) got to deploy that wasn't sql or perl!";
2e68a8e1 229 }
2e68a8e1 230 }
a7d53deb 231
232 $guard->commit if $self->txn_wrap;
41219a5d 233
234 return $sql;
235}
236
93460690 237method _deploy($version) {
238 if (!$self->ignore_ddl) {
239 return $self->_run_sql_and_perl($self->_ddl_schema_consume_filenames(
240 $self->storage->sqlt_type,
241 $version,
242 ));
243 } else {
244 my $sqlt = SQL::Translator->new({
245 add_drop_table => 1,
246 parser => 'SQL::Translator::Parser::YAML',
247 producer => $self->storage->sqlt_type;
248 %{$sqltargs},
249 });
250
251 my $yaml_filename = $self->$from_file($version);
252
253 my @sql = $sqlt->translate($yaml_filename);
254 croak("Failed to translate to $db, skipping. (" . $sqlt->error . ")")
255 unless $sql;
256 }
257}
258
41219a5d 259sub deploy {
260 my $self = shift;
be140a5f 261 my $version = (shift @_ || {})->{version} || $self->schema_version;
f4075791 262 log_info { "deploying version $version" };
93460690 263 $self->_deploy($version);
2e68a8e1 264}
265
80ff6f6d 266sub preinstall {
9faec51a 267 my $self = shift;
268 my $args = shift;
269 my $version = $args->{version} || $self->schema_version;
f4075791 270 log_info { "preinstalling version $version" };
9faec51a 271 my $storage_type = $args->{storage_type} || $self->storage->sqlt_type;
fc4b7602 272
273 my @files = @{$self->_ddl_preinstall_consume_filenames(
9faec51a 274 $storage_type,
fc4b7602 275 $version,
276 )};
277
278 for my $filename (@files) {
279 # We ignore sql for now (till I figure out what to do with it)
280 if ( $filename =~ /^(.+)\.pl$/ ) {
fc4b7602 281 my $filedata = do { local( @ARGV, $/ ) = $filename; <> };
fc4b7602 282
9faec51a 283 no warnings 'redefine';
5b5defbc 284 my $fn = eval "$filedata";
fc4b7602 285 use warnings;
5b5defbc 286
9faec51a 287 if ($@) {
3fa64c79 288 carp "$filename failed to compile: $@";
9faec51a 289 } elsif (ref $fn eq 'CODE') {
fc4b7602 290 $fn->()
291 } else {
5b5defbc 292 carp "$filename should define an anonymous sub but it didn't!";
fc4b7602 293 }
294 } else {
295 croak "A file ($filename) got to preinstall_scripts that wasn't sql or perl!";
296 }
297 }
298}
299
c8a2f7bd 300sub _prepare_install {
73caa630 301 my $self = shift;
02a7b8ac 302 my $sqltargs = { %{$self->sql_translator_args}, %{shift @_} };
e62add58 303 my $from_file = shift;
c8a2f7bd 304 my $to_file = shift;
2e68a8e1 305 my $schema = $self->schema;
306 my $databases = $self->databases;
91adde75 307 my $dir = $self->script_directory;
73caa630 308 my $version = $self->schema_version;
d54b8d69 309
93460690 310 return if $self->ignore_ddl;
311
9600776d 312 my $sqlt = SQL::Translator->new({
d54b8d69 313 add_drop_table => 1,
7e08eddd 314 parser => 'SQL::Translator::Parser::YAML',
3aaf766f 315 %{$sqltargs}
9600776d 316 });
2e68a8e1 317
e62add58 318 my $yaml_filename = $self->$from_file($version);
2e68a8e1 319
320 foreach my $db (@$databases) {
321 $sqlt->reset;
2e68a8e1 322 $sqlt->producer($db);
323
c8a2f7bd 324 my $filename = $self->$to_file($db, $version, $dir);
9600776d 325 if (-e $filename ) {
2e68a8e1 326 carp "Overwriting existing DDL file - $filename";
327 unlink $filename;
328 }
329
7e08eddd 330 my $sql = $sqlt->translate($yaml_filename);
331 if(!$sql) {
2e68a8e1 332 carp("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
333 next;
334 }
387b11d2 335 open my $file, q(>), $filename;
7e08eddd 336 print {$file} $sql;
2e68a8e1 337 close $file;
338 }
339}
340
c8a2f7bd 341sub _resultsource_install_filename {
342 my ($self, $source_name) = @_;
343 return sub {
344 my ($self, $type, $version) = @_;
91adde75 345 my $dirname = catfile( $self->script_directory, $type, 'schema', $version );
c8a2f7bd 346 mkpath($dirname) unless -d $dirname;
347
09bc35e3 348 return catfile( $dirname, "001-auto-$source_name.sql" );
c8a2f7bd 349 }
350}
351
e62add58 352sub _resultsource_protoschema_filename {
353 my ($self, $source_name) = @_;
354 return sub {
355 my ($self, $version) = @_;
356 my $dirname = catfile( $self->script_directory, '_protoschema', $version );
357 mkpath($dirname) unless -d $dirname;
358
359 return catfile( $dirname, "001-auto-$source_name.yml" );
360 }
361}
362
c8a2f7bd 363sub install_resultsource {
be140a5f 364 my ($self, $args) = @_;
365 my $source = $args->{result_source};
366 my $version = $args->{version};
f4075791 367 log_info { 'installing_resultsource ' . $source->source_name . ", version $version" };
c8a2f7bd 368 my $rs_install_file =
369 $self->_resultsource_install_filename($source->source_name);
370
371 my $files = [
372 $self->$rs_install_file(
373 $self->storage->sqlt_type,
374 $version,
375 )
376 ];
377 $self->_run_sql_and_perl($files);
378}
379
380sub prepare_resultsource_install {
381 my $self = shift;
be140a5f 382 my $source = (shift @_)->{result_source};
f4075791 383 log_info { 'preparing install for resultsource ' . $source->source_name };
c8a2f7bd 384
e62add58 385 my $install_filename = $self->_resultsource_install_filename($source->source_name);
386 my $proto_filename = $self->_resultsource_protoschema_filename($source->source_name);
6cae2f56 387 $self->prepare_protoschema({
c8a2f7bd 388 parser_args => { sources => [$source->source_name], }
e62add58 389 }, $proto_filename);
390 $self->_prepare_install({}, $proto_filename, $install_filename);
c8a2f7bd 391}
392
91557c90 393sub prepare_deploy {
f4075791 394 log_info { 'preparing deploy' };
c8a2f7bd 395 my $self = shift;
6cae2f56 396 $self->prepare_protoschema({}, '_ddl_protoschema_produce_filename');
e62add58 397 $self->_prepare_install({}, '_ddl_protoschema_produce_filename', '_ddl_schema_produce_filename');
c8a2f7bd 398}
399
a41a04e5 400sub prepare_upgrade {
be140a5f 401 my ($self, $args) = @_;
0df68524 402 log_info {
f4075791 403 "preparing upgrade from $args->{from_version} to $args->{to_version}"
0df68524 404 };
be140a5f 405 $self->_prepare_changegrade(
406 $args->{from_version}, $args->{to_version}, $args->{version_set}, 'up'
407 );
76d311e7 408}
409
410sub prepare_downgrade {
be140a5f 411 my ($self, $args) = @_;
0df68524 412 log_info {
f4075791 413 "preparing downgrade from $args->{from_version} to $args->{to_version}"
0df68524 414 };
be140a5f 415 $self->_prepare_changegrade(
416 $args->{from_version}, $args->{to_version}, $args->{version_set}, 'down'
417 );
76d311e7 418}
419
420method _prepare_changegrade($from_version, $to_version, $version_set, $direction) {
2e68a8e1 421 my $schema = $self->schema;
422 my $databases = $self->databases;
91adde75 423 my $dir = $self->script_directory;
02a7b8ac 424 my $sqltargs = $self->sql_translator_args;
2e68a8e1 425
93460690 426 return if $self->ignore_ddl;
427
73caa630 428 my $schema_version = $self->schema_version;
2e68a8e1 429
430 $sqltargs = {
431 add_drop_table => 1,
432 ignore_constraint_names => 1,
433 ignore_index_names => 1,
434 %{$sqltargs}
435 };
436
e62add58 437 my $diff_file_method = "_ddl_schema_${direction}_produce_filename";
438 my $source_schema;
439 {
440 my $prefilename = $self->_ddl_protoschema_produce_filename($from_version, $dir);
2e68a8e1 441
e62add58 442 # should probably be a croak
443 carp("No previous schema file found ($prefilename)")
444 unless -e $prefilename;
2e68a8e1 445
e62add58 446 my $t = SQL::Translator->new({
447 %{$sqltargs},
448 debug => 0,
449 trace => 0,
450 parser => 'SQL::Translator::Parser::YAML',
451 });
2e68a8e1 452
e62add58 453 my $out = $t->translate( $prefilename )
454 or croak($t->error);
2e68a8e1 455
e62add58 456 $source_schema = $t->schema;
2e68a8e1 457
e62add58 458 $source_schema->name( $prefilename )
459 unless $source_schema->name;
460 }
2e68a8e1 461
e62add58 462 my $dest_schema;
463 {
464 my $filename = $self->_ddl_protoschema_produce_filename($to_version, $dir);
2e68a8e1 465
e62add58 466 # should probably be a croak
467 carp("No next schema file found ($filename)")
468 unless -e $filename;
2e68a8e1 469
e62add58 470 my $t = SQL::Translator->new({
471 %{$sqltargs},
472 debug => 0,
473 trace => 0,
474 parser => 'SQL::Translator::Parser::YAML',
475 });
2e68a8e1 476
e62add58 477 my $out = $t->translate( $filename )
478 or croak($t->error);
2e68a8e1 479
e62add58 480 $dest_schema = $t->schema;
2e68a8e1 481
e62add58 482 $dest_schema->name( $filename )
483 unless $dest_schema->name;
484 }
485 foreach my $db (@$databases) {
486 my $diff_file = $self->$diff_file_method($db, $version_set, $dir );
487 if(-e $diff_file) {
488 carp("Overwriting existing $direction-diff file - $diff_file");
489 unlink $diff_file;
2e68a8e1 490 }
491
09bc35e3 492 my $diff = SQL::Translator::Diff::schema_diff(
493 $source_schema, $db,
494 $dest_schema, $db,
495 $sqltargs
496 );
387b11d2 497 open my $file, q(>), $diff_file;
09bc35e3 498 print {$file} $diff;
2e68a8e1 499 close $file;
500 }
501}
502
334bced5 503method _read_sql_file($file) {
504 return unless $file;
505
aabd4237 506 open my $fh, '<', $file;
0d19af1d 507 my @data = split /;\n/, join '', <$fh>;
334bced5 508 close $fh;
509
09bc35e3 510 @data = grep {
511 $_ && # remove blank lines
512 !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/ # strip txn's
513 } map {
514 s/^\s+//; s/\s+$//; # trim whitespace
515 join '', grep { !/^--/ } split /\n/ # remove comments
516 } @data;
334bced5 517
09bc35e3 518 return \@data;
1f0d0633 519}
520
7d2a6974 521sub downgrade_single_step {
76d311e7 522 my $self = shift;
be140a5f 523 my $version_set = (shift @_)->{version_set};
f4075791 524 Dlog_info { "downgrade_single_step'ing $_" } $version_set;
41219a5d 525
526 my $sql = $self->_run_sql_and_perl($self->_ddl_schema_down_consume_filenames(
76d311e7 527 $self->storage->sqlt_type,
627581cd 528 $version_set,
41219a5d 529 ));
3249629f 530
41219a5d 531 return ['', $sql];
76d311e7 532}
533
7d2a6974 534sub upgrade_single_step {
7521a845 535 my $self = shift;
be140a5f 536 my $version_set = (shift @_)->{version_set};
f4075791 537 Dlog_info { "upgrade_single_step'ing $_" } $version_set;
41219a5d 538
539 my $sql = $self->_run_sql_and_perl($self->_ddl_schema_up_consume_filenames(
334bced5 540 $self->storage->sqlt_type,
627581cd 541 $version_set,
41219a5d 542 ));
543 return ['', $sql];
334bced5 544}
545
6cae2f56 546sub prepare_protoschema {
7e08eddd 547 my $self = shift;
e62add58 548 my $sqltargs = { %{$self->sql_translator_args}, %{shift @_} };
549 my $to_file = shift;
7e08eddd 550 my $filename
e62add58 551 = $self->$to_file($self->schema_version);
7e08eddd 552
e62add58 553 # we do this because the code that uses this sets parser args,
554 # so we just need to merge in the package
555 $sqltargs->{parser_args}{package} = $self->schema;
7e08eddd 556 my $sqlt = SQL::Translator->new({
557 parser => 'SQL::Translator::Parser::DBIx::Class',
558 producer => 'SQL::Translator::Producer::YAML',
e62add58 559 %{ $sqltargs },
7e08eddd 560 });
561
562 my $yml = $sqlt->translate;
563
564 croak("Failed to translate to YAML: " . $sqlt->error)
565 unless $yml;
566
567 if (-e $filename ) {
568 carp "Overwriting existing DDL-YML file - $filename";
569 unlink $filename;
570 }
571
572 open my $file, q(>), $filename;
573 print {$file} $yml;
574 close $file;
575}
576
aabd4237 577__PACKAGE__->meta->make_immutable;
578
2e68a8e1 5791;
e051bb00 580
e52174e3 581# vim: ts=2 sw=2 expandtab
582
e051bb00 583__END__
584
bcc72297 585=head1 DESCRIPTION
586
e62add58 587This class is the meat of L<DBIx::Class::DeploymentHandler>. It takes care
588of generating serialized schemata as well as sql files to move from one
589version of a schema to the rest. One of the hallmark features of this class
590is that it allows for multiple sql files for deploy and upgrade, allowing
591developers to fine tune deployment. In addition it also allows for perl
592files to be run at any stage of the process.
bcc72297 593
594For basic usage see L<DBIx::Class::DeploymentHandler::HandlesDeploy>. What's
595documented here is extra fun stuff or private methods.
596
597=head1 DIRECTORY LAYOUT
598
92c34cab 599Arguably this is the best feature of L<DBIx::Class::DeploymentHandler>. It's
600heavily based upon L<DBIx::Migration::Directories>, but has some extensions and
601modifications, so even if you are familiar with it, please read this. I feel
602like the best way to describe the layout is with the following example:
603
604 $sql_migration_dir
605 |- SQLite
606 | |- down
4f85efc6 607 | | `- 2-1
e62add58 608 | | `- 001-auto.sql
92c34cab 609 | |- schema
610 | | `- 1
e62add58 611 | | `- 001-auto.sql
92c34cab 612 | `- up
613 | |- 1-2
e62add58 614 | | `- 001-auto.sql
92c34cab 615 | `- 2-3
e62add58 616 | `- 001-auto.sql
92c34cab 617 |- _common
618 | |- down
4f85efc6 619 | | `- 2-1
92c34cab 620 | | `- 002-remove-customers.pl
621 | `- up
622 | `- 1-2
623 | `- 002-generate-customers.pl
624 |- _generic
625 | |- down
4f85efc6 626 | | `- 2-1
e62add58 627 | | `- 001-auto.sql
92c34cab 628 | |- schema
629 | | `- 1
e62add58 630 | | `- 001-auto.sql
92c34cab 631 | `- up
632 | `- 1-2
e62add58 633 | |- 001-auto.sql
92c34cab 634 | `- 002-create-stored-procedures.sql
635 `- MySQL
636 |- down
4f85efc6 637 | `- 2-1
e62add58 638 | `- 001-auto.sql
80ff6f6d 639 |- preinstall
640 | `- 1
641 | |- 001-create_database.pl
642 | `- 002-create_users_and_permissions.pl
92c34cab 643 |- schema
644 | `- 1
e62add58 645 | `- 001-auto.sql
92c34cab 646 `- up
647 `- 1-2
e62add58 648 `- 001-auto.sql
92c34cab 649
650So basically, the code
651
652 $dm->deploy(1)
653
654on an C<SQLite> database that would simply run
e62add58 655C<$sql_migration_dir/SQLite/schema/1/001-auto.sql>. Next,
92c34cab 656
657 $dm->upgrade_single_step([1,2])
658
e62add58 659would run C<$sql_migration_dir/SQLite/up/1-2/001-auto.sql> followed by
92c34cab 660C<$sql_migration_dir/_common/up/1-2/002-generate-customers.pl>.
661
0824f31f 662C<.pl> files don't have to be in the C<_common> directory, but most of the time
663they should be, because perl scripts are generally be database independent.
92c34cab 664
665C<_generic> exists for when you for some reason are sure that your SQL is
666generic enough to run on all databases. Good luck with that one.
667
80ff6f6d 668Note that unlike most steps in the process, C<preinstall> will not run SQL, as
669there may not even be an database at preinstall time. It will run perl scripts
670just like the other steps in the process, but nothing is passed to them.
671Until people have used this more it will remain freeform, but a recommended use
672of preinstall is to have it prompt for username and password, and then call the
673appropriate C<< CREATE DATABASE >> commands etc.
674
92c34cab 675=head1 PERL SCRIPTS
676
7d0b0f2b 677A perl script for this tool is very simple. It merely needs to contain an
678anonymous sub that takes a L<DBIx::Class::Schema> as it's only argument.
92c34cab 679A very basic perl script might look like:
680
681 #!perl
682
683 use strict;
684 use warnings;
685
7d0b0f2b 686 sub {
92c34cab 687 my $schema = shift;
688
689 $schema->resultset('Users')->create({
690 name => 'root',
691 password => 'root',
692 })
693 }
bcc72297 694
eb28403b 695=attr schema
a65184c8 696
bcc72297 697The L<DBIx::Class::Schema> (B<required>) that is used to talk to the database
698and generate the DDL.
699
eb28403b 700=attr storage
a65184c8 701
bcc72297 702The L<DBIx::Class::Storage> that is I<actually> used to talk to the database
703and generate the DDL. This is automatically created with L</_build_storage>.
704
02a7b8ac 705=attr sql_translator_args
cfc9edf9 706
02a7b8ac 707The arguments that get passed to L<SQL::Translator> when it's used.
a65184c8 708
91adde75 709=attr script_directory
cfc9edf9 710
91adde75 711The directory (default C<'sql'>) that scripts are stored in
cfc9edf9 712
eb28403b 713=attr databases
cfc9edf9 714
715The types of databases (default C<< [qw( MySQL SQLite PostgreSQL )] >>) to
716generate files for
717
eb28403b 718=attr txn_wrap
719
bcc72297 720Set to true (which is the default) to wrap all upgrades and deploys in a single
721transaction.
722
73caa630 723=attr schema_version
724
725The version the schema on your harddrive is at. Defaults to
726C<< $self->schema->schema_version >>.
727
db223aff 728=begin comment
729
730=head2 __ddl_consume_with_prefix
a65184c8 731
bcc72297 732 $dm->__ddl_consume_with_prefix( 'SQLite', [qw( 1.00 1.01 )], 'up' )
733
734This is the meat of the multi-file upgrade/deploy stuff. It returns a list of
735files in the order that they should be run for a generic "type" of upgrade.
736You should not be calling this in user code.
737
db223aff 738=head2 _ddl_schema_consume_filenames
a65184c8 739
bcc72297 740 $dm->__ddl_schema_consume_filenames( 'SQLite', [qw( 1.00 )] )
741
742Just a curried L</__ddl_consume_with_prefix>. Get's a list of files for an
743initial deploy.
744
db223aff 745=head2 _ddl_schema_produce_filename
a65184c8 746
bcc72297 747 $dm->__ddl_schema_produce_filename( 'SQLite', [qw( 1.00 )] )
748
749Returns a single file in which an initial schema will be stored.
750
db223aff 751=head2 _ddl_schema_up_consume_filenames
a65184c8 752
bcc72297 753 $dm->_ddl_schema_up_consume_filenames( 'SQLite', [qw( 1.00 )] )
754
755Just a curried L</__ddl_consume_with_prefix>. Get's a list of files for an
756upgrade.
757
db223aff 758=head2 _ddl_schema_down_consume_filenames
a65184c8 759
bcc72297 760 $dm->_ddl_schema_down_consume_filenames( 'SQLite', [qw( 1.00 )] )
761
762Just a curried L</__ddl_consume_with_prefix>. Get's a list of files for a
763downgrade.
764
db223aff 765=head2 _ddl_schema_up_produce_filenames
a65184c8 766
bcc72297 767 $dm->_ddl_schema_up_produce_filename( 'SQLite', [qw( 1.00 1.01 )] )
768
769Returns a single file in which the sql to upgrade from one schema to another
770will be stored.
771
db223aff 772=head2 _ddl_schema_down_produce_filename
bcc72297 773
774 $dm->_ddl_schema_down_produce_filename( 'SQLite', [qw( 1.00 1.01 )] )
775
776Returns a single file in which the sql to downgrade from one schema to another
777will be stored.
a65184c8 778
db223aff 779=head2 _resultsource_install_filename
a65184c8 780
bcc72297 781 my $filename_fn = $dm->_resultsource_install_filename('User');
782 $dm->$filename_fn('SQLite', '1.00')
783
784Returns a function which in turn returns a single filename used to install a
785single resultsource. Weird interface is convenient for me. Deal with it.
786
db223aff 787=head2 _run_sql_and_perl
eb28403b 788
bcc72297 789 $dm->_run_sql_and_perl([qw( list of filenames )])
a65184c8 790
bcc72297 791Simply put, this runs the list of files passed to it. If the file ends in
792C<.sql> it runs it as sql and if it ends in C<.pl> it runs it as a perl file.
a65184c8 793
bcc72297 794Depending on L</txn_wrap> all of the files run will be wrapped in a single
795transaction.
eb28403b 796
db223aff 797=head2 _prepare_install
a65184c8 798
bcc72297 799 $dm->_prepare_install({ add_drop_table => 0 }, sub { 'file_to_create' })
a65184c8 800
bcc72297 801Generates the sql file for installing the database. First arg is simply
802L<SQL::Translator> args and the second is a coderef that returns the filename
803to store the sql in.
a65184c8 804
db223aff 805=head2 _prepare_changegrade
bcc72297 806
807 $dm->_prepare_changegrade('1.00', '1.01', [qw( 1.00 1.01)], 'up')
a65184c8 808
bcc72297 809Generates the sql file for migrating from one schema version to another. First
810arg is the version to start from, second is the version to go to, third is the
811L<version set|DBIx::Class::DeploymentHandler/VERSION SET>, and last is the
812direction of the changegrade, be it 'up' or 'down'.
a65184c8 813
db223aff 814=head2 _read_sql_file
a65184c8 815
bcc72297 816 $dm->_read_sql_file('foo.sql')
a65184c8 817
bcc72297 818Reads a sql file and returns lines in an C<ArrayRef>. Strips out comments,
819transactions, and blank lines.
eb28403b 820
db223aff 821=end comment