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