check for "CURRENT_TIMESTAMP" only for "TIMESTAMP" columns in MySQL
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
CommitLineData
996be9ee 1package DBIx::Class::Schema::Loader::Base;
2
3use strict;
4use warnings;
65e705c3 5use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
996be9ee 6use Class::C3;
fa994d3c 7use Carp::Clan qw/^DBIx::Class/;
996be9ee 8use DBIx::Class::Schema::Loader::RelBuilder;
9use Data::Dump qw/ dump /;
10use POSIX qw//;
dd03ee1a 11use File::Spec qw//;
419a2eeb 12use Cwd qw//;
7cab3ab7 13use Digest::MD5 qw//;
22270947 14use Lingua::EN::Inflect::Number qw//;
af31090c 15use File::Temp qw//;
16use Class::Unload;
996be9ee 17require DBIx::Class;
18
04e60ed2 19our $VERSION = '0.04999_14';
32f784fc 20
3d95f9ff 21__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 22 schema
23 schema_class
24
25 exclude
26 constraint
27 additional_classes
28 additional_base_classes
29 left_base_classes
30 components
31 resultset_components
59cfa251 32 skip_relationships
0ca61324 33 skip_load_external
996be9ee 34 moniker_map
35 inflect_singular
36 inflect_plural
37 debug
38 dump_directory
d65cda9e 39 dump_overwrite
28b4691d 40 really_erase_my_files
f44ecc2f 41 resultset_namespace
42 default_resultset_class
9c9c2f2b 43 schema_base_class
44 result_base_class
639a1367 45 overwrite_modifications
996be9ee 46
c8c27020 47 relationship_attrs
48
996be9ee 49 db_schema
50 _tables
51 classes
f53dcdf0 52 _upgrading_classes
996be9ee 53 monikers
106a976a 54 dynamic
a8d229ff 55 naming
65e705c3 56/);
57
996be9ee 58
3d95f9ff 59__PACKAGE__->mk_group_accessors('simple', qw/
01012543 60 version_to_dump
1c95b304 61 schema_version_to_dump
f53dcdf0 62 _upgrading_from
f22644d7 63 _upgrading_from_load_classes
a4b94090 64 _downgrading_to_load_classes
540a8149 65 _rewriting_result_namespace
f22644d7 66 use_namespaces
540a8149 67 result_namespace
01012543 68/);
69
996be9ee 70=head1 NAME
71
72DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
73
74=head1 SYNOPSIS
75
76See L<DBIx::Class::Schema::Loader>
77
78=head1 DESCRIPTION
79
80This is the base class for the storage-specific C<DBIx::Class::Schema::*>
81classes, and implements the common functionality between them.
82
83=head1 CONSTRUCTOR OPTIONS
84
85These constructor options are the base options for
29ddb54c 86L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 87
59cfa251 88=head2 skip_relationships
996be9ee 89
59cfa251 90Skip setting up relationships. The default is to attempt the loading
91of relationships.
996be9ee 92
0ca61324 93=head2 skip_load_external
94
95Skip loading of other classes in @INC. The default is to merge all other classes
96with the same name found in @INC into the schema file we are creating.
97
9a95164d 98=head2 naming
99
100Static schemas (ones dumped to disk) will, by default, use the new-style 0.05XXX
101relationship names and singularized Results, unless you're overwriting an
102existing dump made by a 0.04XXX version of L<DBIx::Class::Schema::Loader>, in
103which case the backward compatible RelBuilder will be activated, and
104singularization will be turned off.
105
106Specifying
107
108 naming => 'v5'
109
110will disable the backward-compatible RelBuilder and use
111the new-style relationship names along with singularized Results, even when
112overwriting a dump made with an earlier version.
113
114The option also takes a hashref:
115
a8d229ff 116 naming => { relationships => 'v5', monikers => 'v4' }
117
118The keys are:
119
120=over 4
121
122=item relationships
123
124How to name relationship accessors.
125
126=item monikers
127
128How to name Result classes.
129
130=back
9a95164d 131
132The values can be:
133
134=over 4
135
136=item current
137
138Latest default style, whatever that happens to be.
139
140=item v5
141
142Version 0.05XXX style.
143
144=item v4
145
146Version 0.04XXX style.
147
148=back
149
150Dynamic schemas will always default to the 0.04XXX relationship names and won't
151singularize Results for backward compatibility, to activate the new RelBuilder
152and singularization put this in your C<Schema.pm> file:
153
154 __PACKAGE__->naming('current');
155
156Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
157next major version upgrade:
158
159 __PACKAGE__->naming('v5');
160
c8c27020 161=head2 relationship_attrs
162
163Hashref of attributes to pass to each generated relationship, listed
164by type. Also supports relationship type 'all', containing options to
165pass to all generated relationships. Attributes set for more specific
166relationship types override those set in 'all'.
167
168For example:
169
170 relationship_attrs => {
171 all => { cascade_delete => 0 },
172 has_many => { cascade_delete => 1 },
173 },
174
175will set the C<cascade_delete> option to 0 for all generated relationships,
176except for C<has_many>, which will have cascade_delete as 1.
177
178NOTE: this option is not supported if v4 backward-compatible naming is
179set either globally (naming => 'v4') or just for relationships.
180
996be9ee 181=head2 debug
182
183If set to true, each constructive L<DBIx::Class> statement the loader
184decides to execute will be C<warn>-ed before execution.
185
d65cda9e 186=head2 db_schema
187
188Set the name of the schema to load (schema in the sense that your database
189vendor means it). Does not currently support loading more than one schema
190name.
191
996be9ee 192=head2 constraint
193
194Only load tables matching regex. Best specified as a qr// regex.
195
196=head2 exclude
197
198Exclude tables matching regex. Best specified as a qr// regex.
199
200=head2 moniker_map
201
8f9d7ce5 202Overrides the default table name to moniker translation. Can be either
203a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 204function taking a single scalar table name argument and returning
205a scalar moniker. If the hash entry does not exist, or the function
206returns a false value, the code falls back to default behavior
207for that table name.
208
9cc8e7e1 209The default behavior is to singularize the table name, and: C<join '', map
210ucfirst, split /[\W_]+/, lc $table>, which is to say: lowercase everything,
211split up the table name into chunks anywhere a non-alpha-numeric character
212occurs, change the case of first letter of each chunk to upper case, and put
213the chunks back together. Examples:
996be9ee 214
215 Table Name | Moniker Name
216 ---------------------------
217 luser | Luser
218 luser_group | LuserGroup
48b8d687 219 luser-opts | LuserOpt
996be9ee 220
221=head2 inflect_plural
222
223Just like L</moniker_map> above (can be hash/code-ref, falls back to default
224if hash key does not exist or coderef returns false), but acts as a map
225for pluralizing relationship names. The default behavior is to utilize
226L<Lingua::EN::Inflect::Number/to_PL>.
227
228=head2 inflect_singular
229
230As L</inflect_plural> above, but for singularizing relationship names.
231Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
232
9c9c2f2b 233=head2 schema_base_class
234
235Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
236
237=head2 result_base_class
238
2229729e 239Base class for your table classes (aka result classes). Defaults to
240'DBIx::Class::Core'.
9c9c2f2b 241
996be9ee 242=head2 additional_base_classes
243
244List of additional base classes all of your table classes will use.
245
246=head2 left_base_classes
247
248List of additional base classes all of your table classes will use
249that need to be leftmost.
250
251=head2 additional_classes
252
253List of additional classes which all of your table classes will use.
254
255=head2 components
256
257List of additional components to be loaded into all of your table
258classes. A good example would be C<ResultSetManager>.
259
260=head2 resultset_components
261
8f9d7ce5 262List of additional ResultSet components to be loaded into your table
996be9ee 263classes. A good example would be C<AlwaysRS>. Component
264C<ResultSetManager> will be automatically added to the above
265C<components> list if this option is set.
266
f44ecc2f 267=head2 use_namespaces
268
f22644d7 269This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
270a C<0>.
271
f44ecc2f 272Generate result class names suitable for
273L<DBIx::Class::Schema/load_namespaces> and call that instead of
274L<DBIx::Class::Schema/load_classes>. When using this option you can also
275specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
276C<resultset_namespace>, C<default_resultset_class>), and they will be added
277to the call (and the generated result class names adjusted appropriately).
278
996be9ee 279=head2 dump_directory
280
281This option is designed to be a tool to help you transition from this
282loader to a manually-defined schema when you decide it's time to do so.
283
284The value of this option is a perl libdir pathname. Within
285that directory this module will create a baseline manual
286L<DBIx::Class::Schema> module set, based on what it creates at runtime
287in memory.
288
289The created schema class will have the same classname as the one on
290which you are setting this option (and the ResultSource classes will be
7cab3ab7 291based on this name as well).
996be9ee 292
8f9d7ce5 293Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 294is meant for one-time manual usage.
295
296See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
297recommended way to access this functionality.
298
d65cda9e 299=head2 dump_overwrite
300
28b4691d 301Deprecated. See L</really_erase_my_files> below, which does *not* mean
302the same thing as the old C<dump_overwrite> setting from previous releases.
303
304=head2 really_erase_my_files
305
7cab3ab7 306Default false. If true, Loader will unconditionally delete any existing
307files before creating the new ones from scratch when dumping a schema to disk.
308
309The default behavior is instead to only replace the top portion of the
310file, up to and including the final stanza which contains
311C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
312leaving any customizations you placed after that as they were.
313
28b4691d 314When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 315but the aforementioned final stanza is not found, or the checksum
316contained there does not match the generated contents, Loader will
317croak and not touch the file.
d65cda9e 318
28b4691d 319You should really be using version control on your schema classes (and all
320of the rest of your code for that matter). Don't blame me if a bug in this
321code wipes something out when it shouldn't have, you've been warned.
322
639a1367 323=head2 overwrite_modifications
324
325Default false. If false, when updating existing files, Loader will
326refuse to modify any Loader-generated code that has been modified
327since its last run (as determined by the checksum Loader put in its
328comment lines).
329
330If true, Loader will discard any manual modifications that have been
331made to Loader-generated code.
332
333Again, you should be using version control on your schema classes. Be
334careful with this option.
335
996be9ee 336=head1 METHODS
337
338None of these methods are intended for direct invocation by regular
339users of L<DBIx::Class::Schema::Loader>. Anything you can find here
340can also be found via standard L<DBIx::Class::Schema> methods somehow.
341
342=cut
343
66afce69 344use constant CURRENT_V => 'v5';
345
996be9ee 346# ensure that a peice of object data is a valid arrayref, creating
347# an empty one or encapsulating whatever's there.
348sub _ensure_arrayref {
349 my $self = shift;
350
351 foreach (@_) {
352 $self->{$_} ||= [];
353 $self->{$_} = [ $self->{$_} ]
354 unless ref $self->{$_} eq 'ARRAY';
355 }
356}
357
358=head2 new
359
360Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
361by L<DBIx::Class::Schema::Loader>.
362
363=cut
364
365sub new {
366 my ( $class, %args ) = @_;
367
368 my $self = { %args };
369
370 bless $self => $class;
371
996be9ee 372 $self->_ensure_arrayref(qw/additional_classes
373 additional_base_classes
374 left_base_classes
375 components
376 resultset_components
377 /);
378
379 push(@{$self->{components}}, 'ResultSetManager')
380 if @{$self->{resultset_components}};
381
382 $self->{monikers} = {};
383 $self->{classes} = {};
f53dcdf0 384 $self->{_upgrading_classes} = {};
996be9ee 385
996be9ee 386 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
387 $self->{schema} ||= $self->{schema_class};
388
28b4691d 389 croak "dump_overwrite is deprecated. Please read the"
390 . " DBIx::Class::Schema::Loader::Base documentation"
391 if $self->{dump_overwrite};
392
af31090c 393 $self->{dynamic} = ! $self->{dump_directory};
79193756 394 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 395 TMPDIR => 1,
396 CLEANUP => 1,
397 );
398
79193756 399 $self->{dump_directory} ||= $self->{temp_directory};
400
01012543 401 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 402 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 403
66afce69 404 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 405 my $naming_ver = $self->naming;
a8d229ff 406 $self->{naming} = {
407 relationships => $naming_ver,
408 monikers => $naming_ver,
409 };
410 }
411
66afce69 412 if ($self->naming) {
413 for (values %{ $self->naming }) {
414 $_ = CURRENT_V if $_ eq 'current';
415 }
416 }
417 $self->{naming} ||= {};
418
7824616e 419 $self->_check_back_compat;
9c465d2c 420
f22644d7 421 $self->use_namespaces(1) unless defined $self->use_namespaces;
422
7824616e 423 $self;
424}
af31090c 425
7824616e 426sub _check_back_compat {
427 my ($self) = @_;
e8ad6491 428
a8d229ff 429# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 430 if ($self->dynamic) {
fb3bb595 431# just in case, though no one is likely to dump a dynamic schema
1c95b304 432 $self->schema_version_to_dump('0.04006');
a8d229ff 433
66afce69 434 if (not %{ $self->naming }) {
435 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
436
437Dynamic schema detected, will run in 0.04006 mode.
438
439Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
440to disable this warning.
a0e0a56a 441
805dbe0a 442Also consider setting 'use_namespaces => 1' if/when upgrading.
443
a0e0a56a 444See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
445details.
66afce69 446EOF
447 }
f53dcdf0 448 else {
449 $self->_upgrading_from('v4');
450 }
66afce69 451
a8d229ff 452 $self->naming->{relationships} ||= 'v4';
453 $self->naming->{monikers} ||= 'v4';
454
805dbe0a 455 if ($self->use_namespaces) {
456 $self->_upgrading_from_load_classes(1);
457 }
458 else {
459 $self->use_namespaces(0);
460 }
f22644d7 461
01012543 462 return;
463 }
464
465# otherwise check if we need backcompat mode for a static schema
7824616e 466 my $filename = $self->_get_dump_filename($self->schema_class);
467 return unless -e $filename;
468
469 open(my $fh, '<', $filename)
470 or croak "Cannot open '$filename' for reading: $!";
471
540a8149 472 my $load_classes = 0;
473 my $result_namespace = '';
f22644d7 474
7824616e 475 while (<$fh>) {
f22644d7 476 if (/^__PACKAGE__->load_classes;/) {
477 $load_classes = 1;
540a8149 478 } elsif (/result_namespace => '([^']+)'/) {
479 $result_namespace = $1;
805dbe0a 480 } elsif (my ($real_ver) =
481 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
482
483 if ($load_classes && (not defined $self->use_namespaces)) {
484 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
485
a1a91c42 486'load_classes;' static schema detected, turning off 'use_namespaces'.
805dbe0a 487
488Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
489variable to disable this warning.
490
491See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
492details.
493EOF
494 $self->use_namespaces(0);
495 }
496 elsif ($load_classes && $self->use_namespaces) {
805dbe0a 497 $self->_upgrading_from_load_classes(1);
498 }
540a8149 499 elsif ((not $load_classes) && defined $self->use_namespaces
500 && (not $self->use_namespaces)) {
a4b94090 501 $self->_downgrading_to_load_classes(
502 $result_namespace || 'Result'
503 );
504 }
540a8149 505 elsif ((not defined $self->use_namespaces)
506 || $self->use_namespaces) {
507 if (not $self->result_namespace) {
508 $self->result_namespace($result_namespace || 'Result');
509 }
510 elsif ($result_namespace ne $self->result_namespace) {
511 $self->_rewriting_result_namespace(
512 $result_namespace || 'Result'
513 );
514 }
515 }
a8d229ff 516
a8d229ff 517 # XXX when we go past .0 this will need fixing
518 my ($v) = $real_ver =~ /([1-9])/;
519 $v = "v$v";
520
b24cb177 521 last if $v eq CURRENT_V || $real_ver =~ /^0\.\d\d999/;
a0e0a56a 522
523 if (not %{ $self->naming }) {
524 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
525
526Version $real_ver static schema detected, turning on backcompat mode.
527
528Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
529to disable this warning.
530
531See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
532details.
533EOF
534 }
f53dcdf0 535 else {
536 $self->_upgrading_from($v);
68d49e50 537 last;
f53dcdf0 538 }
a0e0a56a 539
a8d229ff 540 $self->naming->{relationships} ||= $v;
541 $self->naming->{monikers} ||= $v;
542
a0e0a56a 543 $self->schema_version_to_dump($real_ver);
544
7824616e 545 last;
546 }
547 }
548 close $fh;
996be9ee 549}
550
419a2eeb 551sub _find_file_in_inc {
552 my ($self, $file) = @_;
553
554 foreach my $prefix (@INC) {
af31090c 555 my $fullpath = File::Spec->catfile($prefix, $file);
556 return $fullpath if -f $fullpath
557 and Cwd::abs_path($fullpath) ne
00fb1678 558 (Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '');
419a2eeb 559 }
560
561 return;
562}
563
fb3bb595 564sub _class_path {
f96ef30f 565 my ($self, $class) = @_;
566
567 my $class_path = $class;
568 $class_path =~ s{::}{/}g;
569 $class_path .= '.pm';
570
fb3bb595 571 return $class_path;
572}
573
574sub _find_class_in_inc {
575 my ($self, $class) = @_;
576
577 return $self->_find_file_in_inc($self->_class_path($class));
578}
579
a4b94090 580sub _rewriting {
581 my $self = shift;
582
583 return $self->_upgrading_from
584 || $self->_upgrading_from_load_classes
540a8149 585 || $self->_downgrading_to_load_classes
586 || $self->_rewriting_result_namespace
587 ;
a4b94090 588}
589
b24cb177 590sub _rewrite_old_classnames {
591 my ($self, $code) = @_;
592
a4b94090 593 return $code unless $self->_rewriting;
b24cb177 594
595 my %old_classes = reverse %{ $self->_upgrading_classes };
596
597 my $re = join '|', keys %old_classes;
598 $re = qr/\b($re)\b/;
599
68d49e50 600 $code =~ s/$re/$old_classes{$1} || $1/eg;
b24cb177 601
602 return $code;
603}
604
fb3bb595 605sub _load_external {
606 my ($self, $class) = @_;
607
0ca61324 608 return if $self->{skip_load_external};
609
ffc705f3 610 # so that we don't load our own classes, under any circumstances
611 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
612
fb3bb595 613 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 614
ffc705f3 615 my $old_class = $self->_upgrading_classes->{$class}
a4b94090 616 if $self->_rewriting;
ffc705f3 617
618 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
619 if $old_class && $old_class ne $class;
620
621 return unless $real_inc_path || $old_real_inc_path;
622
623 if ($real_inc_path) {
624 # If we make it to here, we loaded an external definition
625 warn qq/# Loaded external class definition for '$class'\n/
626 if $self->debug;
627
628 open(my $fh, '<', $real_inc_path)
629 or croak "Failed to open '$real_inc_path' for reading: $!";
b24cb177 630 my $code = do { local $/; <$fh> };
ffc705f3 631 close($fh)
632 or croak "Failed to close $real_inc_path: $!";
b24cb177 633 $code = $self->_rewrite_old_classnames($code);
ffc705f3 634
635 if ($self->dynamic) { # load the class too
636 # kill redefined warnings
502b65d4 637 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 638 local $SIG{__WARN__} = sub {
502b65d4 639 $warn_handler->(@_)
640 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 641 };
b24cb177 642 eval $code;
ffc705f3 643 die $@ if $@;
644 }
b24cb177 645
646 $self->_ext_stmt($class,
647 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
648 .qq|# They are now part of the custom portion of this file\n|
649 .qq|# for you to hand-edit. If you do not either delete\n|
650 .qq|# this section or remove that file from \@INC, this section\n|
651 .qq|# will be repeated redundantly when you re-create this\n|
e770e9ce 652 .qq|# file again via Loader! See skip_load_external to disable\n|
653 .qq|# this feature.\n|
b24cb177 654 );
655 chomp $code;
656 $self->_ext_stmt($class, $code);
657 $self->_ext_stmt($class,
658 qq|# End of lines loaded from '$real_inc_path' |
659 );
996be9ee 660 }
106a976a 661
ffc705f3 662 if ($old_real_inc_path) {
663 open(my $fh, '<', $old_real_inc_path)
664 or croak "Failed to open '$old_real_inc_path' for reading: $!";
665 $self->_ext_stmt($class, <<"EOF");
666
30a4c064 667# These lines were loaded from '$old_real_inc_path',
668# based on the Result class name that would have been created by an 0.04006
669# version of the Loader. For a static schema, this happens only once during
e770e9ce 670# upgrade. See skip_load_external to disable this feature.
ffc705f3 671EOF
b24cb177 672
673 my $code = do {
674 local ($/, @ARGV) = (undef, $old_real_inc_path); <>
675 };
676 $code = $self->_rewrite_old_classnames($code);
677
ffc705f3 678 if ($self->dynamic) {
679 warn <<"EOF";
680
681Detected external content in '$old_real_inc_path', a class name that would have
682been used by an 0.04006 version of the Loader.
683
684* PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
685new name of the Result.
686EOF
687 # kill redefined warnings
502b65d4 688 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 689 local $SIG{__WARN__} = sub {
502b65d4 690 $warn_handler->(@_)
691 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 692 };
ffc705f3 693 eval $code;
694 die $@ if $@;
695 }
696
b24cb177 697 chomp $code;
698 $self->_ext_stmt($class, $code);
ffc705f3 699 $self->_ext_stmt($class,
700 qq|# End of lines loaded from '$old_real_inc_path' |
701 );
9e8033c1 702 }
996be9ee 703}
704
705=head2 load
706
707Does the actual schema-construction work.
708
709=cut
710
711sub load {
712 my $self = shift;
713
b97c2c1e 714 $self->_load_tables($self->_tables_list);
715}
716
717=head2 rescan
718
a60b5b8d 719Arguments: schema
720
b97c2c1e 721Rescan the database for newly added tables. Does
a60b5b8d 722not process drops or changes. Returns a list of
723the newly added table monikers.
724
725The schema argument should be the schema class
726or object to be affected. It should probably
727be derived from the original schema_class used
728during L</load>.
b97c2c1e 729
730=cut
731
732sub rescan {
a60b5b8d 733 my ($self, $schema) = @_;
734
735 $self->{schema} = $schema;
7824616e 736 $self->_relbuilder->{schema} = $schema;
b97c2c1e 737
738 my @created;
739 my @current = $self->_tables_list;
740 foreach my $table ($self->_tables_list) {
741 if(!exists $self->{_tables}->{$table}) {
742 push(@created, $table);
743 }
744 }
745
c39e3507 746 my $loaded = $self->_load_tables(@created);
a60b5b8d 747
c39e3507 748 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 749}
750
7824616e 751sub _relbuilder {
66afce69 752 no warnings 'uninitialized';
7824616e 753 my ($self) = @_;
3fed44ca 754
755 return if $self->{skip_relationships};
756
a8d229ff 757 if ($self->naming->{relationships} eq 'v4') {
758 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
759 return $self->{relbuilder} ||=
760 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
761 $self->schema, $self->inflect_plural, $self->inflect_singular
762 );
763 }
764
c8c27020 765 $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
766 $self->schema,
767 $self->inflect_plural,
768 $self->inflect_singular,
769 $self->relationship_attrs,
7824616e 770 );
771}
772
b97c2c1e 773sub _load_tables {
774 my ($self, @tables) = @_;
775
f96ef30f 776 # First, use _tables_list with constraint and exclude
777 # to get a list of tables to operate on
778
779 my $constraint = $self->constraint;
780 my $exclude = $self->exclude;
f96ef30f 781
b97c2c1e 782 @tables = grep { /$constraint/ } @tables if $constraint;
783 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 784
b97c2c1e 785 # Save the new tables to the tables list
a60b5b8d 786 foreach (@tables) {
787 $self->{_tables}->{$_} = 1;
788 }
f96ef30f 789
af31090c 790 $self->_make_src_class($_) for @tables;
f96ef30f 791 $self->_setup_src_meta($_) for @tables;
792
e8ad6491 793 if(!$self->skip_relationships) {
181cc907 794 # The relationship loader needs a working schema
af31090c 795 $self->{quiet} = 1;
79193756 796 local $self->{dump_directory} = $self->{temp_directory};
106a976a 797 $self->_reload_classes(\@tables);
e8ad6491 798 $self->_load_relationships($_) for @tables;
af31090c 799 $self->{quiet} = 0;
79193756 800
801 # Remove that temp dir from INC so it doesn't get reloaded
ffc705f3 802 @INC = grep $_ ne $self->dump_directory, @INC;
e8ad6491 803 }
804
f96ef30f 805 $self->_load_external($_)
75451704 806 for map { $self->classes->{$_} } @tables;
f96ef30f 807
106a976a 808 # Reload without unloading first to preserve any symbols from external
809 # packages.
810 $self->_reload_classes(\@tables, 0);
996be9ee 811
5223f24a 812 # Drop temporary cache
813 delete $self->{_cache};
814
c39e3507 815 return \@tables;
996be9ee 816}
817
af31090c 818sub _reload_classes {
106a976a 819 my ($self, $tables, $unload) = @_;
820
821 my @tables = @$tables;
822 $unload = 1 unless defined $unload;
181cc907 823
4daef04f 824 # so that we don't repeat custom sections
825 @INC = grep $_ ne $self->dump_directory, @INC;
826
181cc907 827 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 828
829 unshift @INC, $self->dump_directory;
af31090c 830
706ef173 831 my @to_register;
832 my %have_source = map { $_ => $self->schema->source($_) }
833 $self->schema->sources;
834
181cc907 835 for my $table (@tables) {
836 my $moniker = $self->monikers->{$table};
837 my $class = $self->classes->{$table};
0ae6b65d 838
839 {
840 no warnings 'redefine';
841 local *Class::C3::reinitialize = sub {};
842 use warnings;
843
106a976a 844 Class::Unload->unload($class) if $unload;
706ef173 845 my ($source, $resultset_class);
846 if (
847 ($source = $have_source{$moniker})
848 && ($resultset_class = $source->resultset_class)
849 && ($resultset_class ne 'DBIx::Class::ResultSet')
850 ) {
851 my $has_file = Class::Inspector->loaded_filename($resultset_class);
106a976a 852 Class::Unload->unload($resultset_class) if $unload;
853 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 854 }
106a976a 855 $self->_reload_class($class);
af31090c 856 }
706ef173 857 push @to_register, [$moniker, $class];
858 }
af31090c 859
706ef173 860 Class::C3->reinitialize;
861 for (@to_register) {
862 $self->schema->register_class(@$_);
af31090c 863 }
864}
865
106a976a 866# We use this instead of ensure_class_loaded when there are package symbols we
867# want to preserve.
868sub _reload_class {
869 my ($self, $class) = @_;
870
871 my $class_path = $self->_class_path($class);
872 delete $INC{ $class_path };
f53dcdf0 873
874# kill redefined warnings
502b65d4 875 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
f53dcdf0 876 local $SIG{__WARN__} = sub {
502b65d4 877 $warn_handler->(@_)
878 unless $_[0] =~ /^Subroutine \S+ redefined/;
f53dcdf0 879 };
106a976a 880 eval "require $class;";
881}
882
996be9ee 883sub _get_dump_filename {
884 my ($self, $class) = (@_);
885
886 $class =~ s{::}{/}g;
887 return $self->dump_directory . q{/} . $class . q{.pm};
888}
889
890sub _ensure_dump_subdirs {
891 my ($self, $class) = (@_);
892
893 my @name_parts = split(/::/, $class);
dd03ee1a 894 pop @name_parts; # we don't care about the very last element,
895 # which is a filename
896
996be9ee 897 my $dir = $self->dump_directory;
7cab3ab7 898 while (1) {
899 if(!-d $dir) {
25328cc4 900 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 901 }
7cab3ab7 902 last if !@name_parts;
903 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 904 }
905}
906
907sub _dump_to_dir {
af31090c 908 my ($self, @classes) = @_;
996be9ee 909
fc2b71fd 910 my $schema_class = $self->schema_class;
9c9c2f2b 911 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 912
e9b8719e 913 my $target_dir = $self->dump_directory;
af31090c 914 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
915 unless $self->{dynamic} or $self->{quiet};
996be9ee 916
7cab3ab7 917 my $schema_text =
918 qq|package $schema_class;\n\n|
b4dcbcc5 919 . qq|# Created by DBIx::Class::Schema::Loader\n|
920 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 921 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 922 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 923
f44ecc2f 924 if ($self->use_namespaces) {
925 $schema_text .= qq|__PACKAGE__->load_namespaces|;
926 my $namespace_options;
927 for my $attr (qw(result_namespace
928 resultset_namespace
929 default_resultset_class)) {
930 if ($self->$attr) {
931 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
932 }
933 }
934 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
935 $schema_text .= qq|;\n|;
936 }
937 else {
938 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 939 }
996be9ee 940
1c95b304 941 {
942 local $self->{version_to_dump} = $self->schema_version_to_dump;
68d49e50 943 $self->_write_classfile($schema_class, $schema_text, 1);
1c95b304 944 }
996be9ee 945
2229729e 946 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 947
af31090c 948 foreach my $src_class (@classes) {
7cab3ab7 949 my $src_text =
950 qq|package $src_class;\n\n|
b4dcbcc5 951 . qq|# Created by DBIx::Class::Schema::Loader\n|
952 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 953 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 954 . qq|use base '$result_base_class';\n\n|;
996be9ee 955
7cab3ab7 956 $self->_write_classfile($src_class, $src_text);
02356864 957 }
996be9ee 958
a4b94090 959 # remove Result dir if downgrading from use_namespaces, and there are no
960 # files left.
b5f1b43c 961 if (my $result_ns = $self->_downgrading_to_load_classes
962 || $self->_rewriting_result_namespace) {
540a8149 963 my $result_namespace = $self->_result_namespace(
964 $schema_class,
965 $result_ns,
966 );
a4b94090 967
540a8149 968 (my $result_dir = $result_namespace) =~ s{::}{/}g;
a4b94090 969 $result_dir = $self->dump_directory . '/' . $result_dir;
970
971 unless (my @files = glob "$result_dir/*") {
972 rmdir $result_dir;
973 }
974 }
975
af31090c 976 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
977
7cab3ab7 978}
979
79193756 980sub _sig_comment {
981 my ($self, $version, $ts) = @_;
982 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
983 . qq| v| . $version
984 . q| @ | . $ts
985 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
986}
987
7cab3ab7 988sub _write_classfile {
68d49e50 989 my ($self, $class, $text, $is_schema) = @_;
7cab3ab7 990
991 my $filename = $self->_get_dump_filename($class);
992 $self->_ensure_dump_subdirs($class);
993
28b4691d 994 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 995 warn "Deleting existing file '$filename' due to "
af31090c 996 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 997 unlink($filename);
998 }
999
79193756 1000 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 1001
e1373c52 1002 if (my $old_class = $self->_upgrading_classes->{$class}) {
1003 my $old_filename = $self->_get_dump_filename($old_class);
f53dcdf0 1004
e1373c52 1005 my ($old_custom_content) = $self->_get_custom_content(
1006 $old_class, $old_filename, 0 # do not add default comment
1007 );
ffc705f3 1008
e1373c52 1009 $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
f53dcdf0 1010
e1373c52 1011 if ($old_custom_content) {
1012 $custom_content =
1013 "\n" . $old_custom_content . "\n" . $custom_content;
f53dcdf0 1014 }
e1373c52 1015
1016 unlink $old_filename;
f53dcdf0 1017 }
1018
b24cb177 1019 $custom_content = $self->_rewrite_old_classnames($custom_content);
1020
7cab3ab7 1021 $text .= qq|$_\n|
1022 for @{$self->{_dump_storage}->{$class} || []};
1023
79193756 1024 # Check and see if the dump is infact differnt
1025
1026 my $compare_to;
1027 if ($old_md5) {
1028 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1029
1030
1031 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
68d49e50 1032 return unless $self->_upgrading_from && $is_schema;
79193756 1033 }
1034 }
1035
1036 $text .= $self->_sig_comment(
01012543 1037 $self->version_to_dump,
79193756 1038 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1039 );
7cab3ab7 1040
1041 open(my $fh, '>', $filename)
1042 or croak "Cannot open '$filename' for writing: $!";
1043
1044 # Write the top half and its MD5 sum
a4476f41 1045 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 1046
1047 # Write out anything loaded via external partial class file in @INC
1048 print $fh qq|$_\n|
1049 for @{$self->{_ext_storage}->{$class} || []};
1050
1eea4fb1 1051 # Write out any custom content the user has added
7cab3ab7 1052 print $fh $custom_content;
1053
1054 close($fh)
e9b8719e 1055 or croak "Error closing '$filename': $!";
7cab3ab7 1056}
1057
79193756 1058sub _default_custom_content {
1059 return qq|\n\n# You can replace this text with custom|
1060 . qq| content, and it will be preserved on regeneration|
1061 . qq|\n1;\n|;
1062}
1063
7cab3ab7 1064sub _get_custom_content {
ffc705f3 1065 my ($self, $class, $filename, $add_default) = @_;
1066
1067 $add_default = 1 unless defined $add_default;
7cab3ab7 1068
79193756 1069 return ($self->_default_custom_content) if ! -f $filename;
1070
7cab3ab7 1071 open(my $fh, '<', $filename)
1072 or croak "Cannot open '$filename' for reading: $!";
1073
1074 my $mark_re =
419a2eeb 1075 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1076
7cab3ab7 1077 my $buffer = '';
79193756 1078 my ($md5, $ts, $ver);
7cab3ab7 1079 while(<$fh>) {
79193756 1080 if(!$md5 && /$mark_re/) {
1081 $md5 = $2;
1082 my $line = $1;
1083
1084 # Pull out the previous version and timestamp
1085 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
1086
1087 $buffer .= $line;
b4cc5793 1088 croak "Checksum mismatch in '$filename', the auto-generated part of the file has been modified outside of this loader. Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
639a1367 1089 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 1090
1091 $buffer = '';
1092 }
1093 else {
1094 $buffer .= $_;
1095 }
996be9ee 1096 }
1097
28b4691d 1098 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 1099 . " it does not appear to have been generated by Loader"
79193756 1100 if !$md5;
5ef3c771 1101
79193756 1102 # Default custom content:
ffc705f3 1103 $buffer ||= $self->_default_custom_content if $add_default;
5ef3c771 1104
79193756 1105 return ($buffer, $md5, $ver, $ts);
996be9ee 1106}
1107
1108sub _use {
1109 my $self = shift;
1110 my $target = shift;
1111
1112 foreach (@_) {
cb54990b 1113 warn "$target: use $_;" if $self->debug;
996be9ee 1114 $self->_raw_stmt($target, "use $_;");
996be9ee 1115 }
1116}
1117
1118sub _inject {
1119 my $self = shift;
1120 my $target = shift;
1121 my $schema_class = $self->schema_class;
1122
af31090c 1123 my $blist = join(q{ }, @_);
1124 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
1125 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 1126}
1127
540a8149 1128sub _result_namespace {
1129 my ($self, $schema_class, $ns) = @_;
1130 my @result_namespace;
1131
1132 if ($ns =~ /^\+(.*)/) {
1133 # Fully qualified namespace
1134 @result_namespace = ($1)
1135 }
1136 else {
1137 # Relative namespace
1138 @result_namespace = ($schema_class, $ns);
1139 }
1140
1141 return wantarray ? @result_namespace : join '::', @result_namespace;
1142}
1143
f96ef30f 1144# Create class with applicable bases, setup monikers, etc
1145sub _make_src_class {
1146 my ($self, $table) = @_;
996be9ee 1147
a13b2803 1148 my $schema = $self->schema;
1149 my $schema_class = $self->schema_class;
996be9ee 1150
f96ef30f 1151 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1152 my @result_namespace = ($schema_class);
1153 if ($self->use_namespaces) {
1154 my $result_namespace = $self->result_namespace || 'Result';
540a8149 1155 @result_namespace = $self->_result_namespace(
1156 $schema_class,
1157 $result_namespace,
1158 );
f44ecc2f 1159 }
1160 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1161
805dbe0a 1162 if ((my $upgrading_v = $self->_upgrading_from)
a4b94090 1163 || $self->_rewriting) {
805dbe0a 1164 local $self->naming->{monikers} = $upgrading_v
1165 if $upgrading_v;
1166
1167 my @result_namespace = @result_namespace;
a4b94090 1168 if ($self->_upgrading_from_load_classes) {
1169 @result_namespace = ($schema_class);
1170 }
1171 elsif (my $ns = $self->_downgrading_to_load_classes) {
540a8149 1172 @result_namespace = $self->_result_namespace(
1173 $schema_class,
1174 $ns,
1175 );
1176 }
1177 elsif ($ns = $self->_rewriting_result_namespace) {
1178 @result_namespace = $self->_result_namespace(
1179 $schema_class,
1180 $ns,
1181 );
a4b94090 1182 }
f53dcdf0 1183
1184 my $old_class = join(q{::}, @result_namespace,
1185 $self->_table2moniker($table));
1186
68d49e50 1187 $self->_upgrading_classes->{$table_class} = $old_class
1188 unless $table_class eq $old_class;
f53dcdf0 1189 }
1190
f96ef30f 1191 my $table_normalized = lc $table;
1192 $self->classes->{$table} = $table_class;
1193 $self->classes->{$table_normalized} = $table_class;
1194 $self->monikers->{$table} = $table_moniker;
1195 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 1196
f96ef30f 1197 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1198 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1199
2229729e 1200 if (my @components = @{ $self->components }) {
1201 $self->_dbic_stmt($table_class, 'load_components', @components);
1202 }
996be9ee 1203
f96ef30f 1204 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1205 if @{$self->resultset_components};
af31090c 1206 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1207}
996be9ee 1208
af31090c 1209# Set up metadata (cols, pks, etc)
f96ef30f 1210sub _setup_src_meta {
1211 my ($self, $table) = @_;
996be9ee 1212
f96ef30f 1213 my $schema = $self->schema;
1214 my $schema_class = $self->schema_class;
a13b2803 1215
f96ef30f 1216 my $table_class = $self->classes->{$table};
1217 my $table_moniker = $self->monikers->{$table};
996be9ee 1218
ff30991a 1219 my $table_name = $table;
1220 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1221
c177d483 1222 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1223 $table_name = \ $self->_quote_table_name($table_name);
1224 }
1225
1226 $self->_dbic_stmt($table_class,'table',$table_name);
996be9ee 1227
f96ef30f 1228 my $cols = $self->_table_columns($table);
1229 my $col_info;
1230 eval { $col_info = $self->_columns_info_for($table) };
1231 if($@) {
1232 $self->_dbic_stmt($table_class,'add_columns',@$cols);
1233 }
1234 else {
0906d55b 1235 if ($self->_is_case_sensitive) {
1236 for my $col (keys %$col_info) {
1237 $col_info->{$col}{accessor} = lc $col
1238 if $col ne lc($col);
1239 }
1240 } else {
1241 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
c9373b79 1242 }
1243
e7213f4f 1244 my $fks = $self->_table_fk_info($table);
565335e6 1245
e7213f4f 1246 for my $fkdef (@$fks) {
1247 for my $col (@{ $fkdef->{local_columns} }) {
565335e6 1248 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1249 }
1250 }
f96ef30f 1251 $self->_dbic_stmt(
1252 $table_class,
1253 'add_columns',
565335e6 1254 map { $_, ($col_info->{$_}||{}) } @$cols
f96ef30f 1255 );
996be9ee 1256 }
1257
d70c335f 1258 my %uniq_tag; # used to eliminate duplicate uniqs
1259
f96ef30f 1260 my $pks = $self->_table_pk_info($table) || [];
1261 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1262 : carp("$table has no primary key");
d70c335f 1263 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1264
f96ef30f 1265 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1266 for (@$uniqs) {
1267 my ($name, $cols) = @$_;
1268 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1269 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1270 }
1271
996be9ee 1272}
1273
1274=head2 tables
1275
1276Returns a sorted list of loaded tables, using the original database table
1277names.
1278
1279=cut
1280
1281sub tables {
1282 my $self = shift;
1283
b97c2c1e 1284 return keys %{$self->_tables};
996be9ee 1285}
1286
1287# Make a moniker from a table
c39e403e 1288sub _default_table2moniker {
66afce69 1289 no warnings 'uninitialized';
c39e403e 1290 my ($self, $table) = @_;
1291
a8d229ff 1292 if ($self->naming->{monikers} eq 'v4') {
1293 return join '', map ucfirst, split /[\W_]+/, lc $table;
1294 }
1295
c39e403e 1296 return join '', map ucfirst, split /[\W_]+/,
1297 Lingua::EN::Inflect::Number::to_S(lc $table);
1298}
1299
996be9ee 1300sub _table2moniker {
1301 my ( $self, $table ) = @_;
1302
1303 my $moniker;
1304
1305 if( ref $self->moniker_map eq 'HASH' ) {
1306 $moniker = $self->moniker_map->{$table};
1307 }
1308 elsif( ref $self->moniker_map eq 'CODE' ) {
1309 $moniker = $self->moniker_map->($table);
1310 }
1311
c39e403e 1312 $moniker ||= $self->_default_table2moniker($table);
996be9ee 1313
1314 return $moniker;
1315}
1316
1317sub _load_relationships {
e8ad6491 1318 my ($self, $table) = @_;
996be9ee 1319
e8ad6491 1320 my $tbl_fk_info = $self->_table_fk_info($table);
1321 foreach my $fkdef (@$tbl_fk_info) {
1322 $fkdef->{remote_source} =
1323 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1324 }
26f1c8c9 1325 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1326
e8ad6491 1327 my $local_moniker = $self->monikers->{$table};
7824616e 1328 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1329
996be9ee 1330 foreach my $src_class (sort keys %$rel_stmts) {
1331 my $src_stmts = $rel_stmts->{$src_class};
1332 foreach my $stmt (@$src_stmts) {
1333 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1334 }
1335 }
1336}
1337
1338# Overload these in driver class:
1339
1340# Returns an arrayref of column names
1341sub _table_columns { croak "ABSTRACT METHOD" }
1342
1343# Returns arrayref of pk col names
1344sub _table_pk_info { croak "ABSTRACT METHOD" }
1345
1346# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1347sub _table_uniq_info { croak "ABSTRACT METHOD" }
1348
1349# Returns an arrayref of foreign key constraints, each
1350# being a hashref with 3 keys:
1351# local_columns (arrayref), remote_columns (arrayref), remote_table
1352sub _table_fk_info { croak "ABSTRACT METHOD" }
1353
1354# Returns an array of lower case table names
1355sub _tables_list { croak "ABSTRACT METHOD" }
1356
1357# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1358sub _dbic_stmt {
bf654ab9 1359 my $self = shift;
1360 my $class = shift;
996be9ee 1361 my $method = shift;
bf654ab9 1362
1363 # generate the pod for this statement, storing it with $self->_pod
1364 $self->_make_pod( $class, $method, @_ );
1365
1366 my $args = dump(@_);
1367 $args = '(' . $args . ')' if @_ < 2;
1368 my $stmt = $method . $args . q{;};
1369
1370 warn qq|$class\->$stmt\n| if $self->debug;
1371 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1372 return;
1373}
1374
1375# generates the accompanying pod for a DBIC class method statement,
1376# storing it with $self->_pod
1377sub _make_pod {
1378 my $self = shift;
1379 my $class = shift;
1380 my $method = shift;
1381
fbcfebdd 1382 if ( $method eq 'table' ) {
1383 my ($table) = @_;
1384 $self->_pod( $class, "=head1 NAME" );
1385 my $table_descr = $class;
1386 if ( $self->can('_table_comment') ) {
1387 my $comment = $self->_table_comment($table);
1388 $table_descr .= " - " . $comment if $comment;
1389 }
1390 $self->{_class2table}{ $class } = $table;
1391 $self->_pod( $class, $table_descr );
1392 $self->_pod_cut( $class );
1393 } elsif ( $method eq 'add_columns' ) {
1394 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1395 my $col_counter = 0;
1396 my @cols = @_;
1397 while( my ($name,$attrs) = splice @cols,0,2 ) {
1398 $col_counter++;
1399 $self->_pod( $class, '=head2 ' . $name );
1400 $self->_pod( $class,
1401 join "\n", map {
1402 my $s = $attrs->{$_};
1403 $s = !defined $s ? 'undef' :
1404 length($s) == 0 ? '(empty string)' :
1405 $s;
1406
1407 " $_: $s"
1408 } sort keys %$attrs,
1409 );
1410
1411 if( $self->can('_column_comment')
1412 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1413 ) {
1414 $self->_pod( $class, $comment );
1415 }
fbcfebdd 1416 }
1417 $self->_pod_cut( $class );
1418 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1419 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1420 my ( $accessor, $rel_class ) = @_;
1421 $self->_pod( $class, "=head2 $accessor" );
1422 $self->_pod( $class, 'Type: ' . $method );
1423 $self->_pod( $class, "Related object: L<$rel_class>" );
1424 $self->_pod_cut( $class );
1425 $self->{_relations_started} { $class } = 1;
1426 }
996be9ee 1427}
1428
fbcfebdd 1429# Stores a POD documentation
1430sub _pod {
1431 my ($self, $class, $stmt) = @_;
1432 $self->_raw_stmt( $class, "\n" . $stmt );
1433}
1434
1435sub _pod_cut {
1436 my ($self, $class ) = @_;
1437 $self->_raw_stmt( $class, "\n=cut\n" );
1438}
1439
1440
996be9ee 1441# Store a raw source line for a class (for dumping purposes)
1442sub _raw_stmt {
1443 my ($self, $class, $stmt) = @_;
af31090c 1444 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1445}
1446
7cab3ab7 1447# Like above, but separately for the externally loaded stuff
1448sub _ext_stmt {
1449 my ($self, $class, $stmt) = @_;
af31090c 1450 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1451}
1452
565335e6 1453sub _quote_table_name {
1454 my ($self, $table) = @_;
1455
1456 my $qt = $self->schema->storage->sql_maker->quote_char;
1457
c177d483 1458 return $table unless $qt;
1459
565335e6 1460 if (ref $qt) {
1461 return $qt->[0] . $table . $qt->[1];
1462 }
1463
1464 return $qt . $table . $qt;
1465}
1466
1467sub _is_case_sensitive { 0 }
1468
ffc705f3 1469# remove the dump dir from @INC on destruction
1470sub DESTROY {
1471 my $self = shift;
1472
1473 @INC = grep $_ ne $self->dump_directory, @INC;
1474}
1475
996be9ee 1476=head2 monikers
1477
8f9d7ce5 1478Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1479be two entries for each table, the original name and the "normalized"
1480name, in the case that the two are different (such as databases
1481that like uppercase table names, or preserve your original mixed-case
1482definitions, or what-have-you).
1483
1484=head2 classes
1485
8f9d7ce5 1486Returns a hashref of table to class mappings. In some cases it will
996be9ee 1487contain multiple entries per table for the original and normalized table
1488names, as above in L</monikers>.
1489
1490=head1 SEE ALSO
1491
1492L<DBIx::Class::Schema::Loader>
1493
be80bba7 1494=head1 AUTHOR
1495
9cc8e7e1 1496See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1497
1498=head1 LICENSE
1499
1500This library is free software; you can redistribute it and/or modify it under
1501the same terms as Perl itself.
1502
996be9ee 1503=cut
1504
15051;