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