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